]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Add proper check for crypto modes (CBC or OFB/CFB)
authorSteffan Karger <steffan@karger.me>
Sun, 8 Jun 2014 16:16:13 +0000 (18:16 +0200)
committerGert Doering <gert@greenie.muc.de>
Mon, 7 Jul 2014 20:35:30 +0000 (22:35 +0200)
OpenSSL has added AEAD-CBC mode ciphers like AES-128-CBC-HMAC-SHA1, which
have mode EVP_CIPH_CBC_MODE, but require a different API (the AEAD API).
So, add extra checks to filter out those AEAD-mode ciphers.

Adding these made the crypto library agnostic function cfb_ofb_mode()
superfuous, so removed that on the go.

Also update all cipher mode checks to use the new cipher_kt_mode_*()
functions for consistency.

Signed-off-by: Steffan Karger <steffan@karger.me>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: <1402244175-31462-3-git-send-email-steffan@karger.me>
URL: http://article.gmane.org/gmane.network.openvpn.devel/8779
Signed-off-by: Gert Doering <gert@greenie.muc.de>
(cherry picked from commit a4b27b6481c7496f2a8705c993edfe150a3541cb)

src/openvpn/crypto.c
src/openvpn/crypto.h
src/openvpn/crypto_backend.h
src/openvpn/crypto_openssl.c
src/openvpn/crypto_polarssl.c
src/openvpn/init.c

index 9f1ae6c5a279b360a1379060119b3a472fbb9826..a0954b18ce67c2c614d1c51dbe1046e9bb138706 100644 (file)
@@ -100,10 +100,10 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
        {
          uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH];
          const int iv_size = cipher_ctx_iv_length (ctx->cipher);
-         const unsigned int mode = cipher_ctx_mode (ctx->cipher);
+         const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
          int outlen;
 
-         if (mode == OPENVPN_MODE_CBC)
+         if (cipher_kt_mode_cbc(cipher_kt))
            {
              CLEAR (iv_buf);
 
@@ -119,7 +119,7 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
                  ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true));
                }
            }
-         else if (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB)
+         else if (cipher_kt_mode_ofb_cfb(cipher_kt))
            {
              struct packet_id_net pin;
              struct buffer b;
@@ -171,7 +171,10 @@ openvpn_encrypt (struct buffer *buf, struct buffer work,
          /* Flush the encryption buffer */
          ASSERT(cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen));
          work.len += outlen;
-         ASSERT (mode != OPENVPN_MODE_CBC || outlen == iv_size);
+
+         /* For all CBC mode ciphers, check the last block is complete */
+         ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC ||
+             outlen == iv_size);
 
          /* prepend the IV to the ciphertext */
          if (opt->flags & CO_USE_IV)
@@ -272,8 +275,8 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 
       if (ctx->cipher)
        {
-         const unsigned int mode = cipher_ctx_mode (ctx->cipher);
          const int iv_size = cipher_ctx_iv_length (ctx->cipher);
+         const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher);
          uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH];
          int outlen;
 
@@ -320,7 +323,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
 
          /* Get packet ID from plaintext buffer or IV, depending on cipher mode */
          {
-           if (mode == OPENVPN_MODE_CBC)
+           if (cipher_kt_mode_cbc(cipher_kt))
              {
                if (opt->packet_id)
                  {
@@ -329,7 +332,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
                    have_pin = true;
                  }
              }
-           else if (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB)
+           else if (cipher_kt_mode_ofb_cfb(cipher_kt))
              {
                struct buffer b;
 
@@ -426,10 +429,9 @@ init_key_type (struct key_type *kt, const char *ciphername,
 
       /* check legal cipher mode */
       {
-       const unsigned int mode = cipher_kt_mode (kt->cipher);
-       if (!(mode == OPENVPN_MODE_CBC
+       if (!(cipher_kt_mode_cbc(kt->cipher)
 #ifdef ENABLE_OFB_CFB_MODE
-             || (cfb_ofb_allowed && (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB))
+             || (cfb_ofb_allowed && cipher_kt_mode_ofb_cfb(kt->cipher))
 #endif
              ))
 #ifdef ENABLE_SMALL
@@ -606,18 +608,10 @@ fixup_key (struct key *key, const struct key_type *kt)
 void
 check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv)
 {
-  if (cfb_ofb_mode (kt) && !(packet_id && use_iv))
-    msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");
-}
+  ASSERT(kt);
 
-bool
-cfb_ofb_mode (const struct key_type* kt)
-{
-  if (kt && kt->cipher) {
-      const unsigned int mode = cipher_kt_mode (kt->cipher);
-      return mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB;
-  }
-  return false;
+  if (cipher_kt_mode_ofb_cfb(kt->cipher) && !(packet_id && use_iv))
+    msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");
 }
 
 /*
index 1f1e1b6604126709650dd7a0d8a77b4977d44eb6..bf2f8028a90855acbc1c6a294a155bd5cf437645 100644 (file)
@@ -187,8 +187,6 @@ bool write_key (const struct key *key, const struct key_type *kt,
 
 int read_key (struct key *key, const struct key_type *kt, struct buffer *buf);
 
-bool cfb_ofb_mode (const struct key_type* kt);
-
 void init_key_type (struct key_type *kt, const char *ciphername,
     bool ciphername_defined, const char *authname, bool authname_defined,
     int keysize, bool cfb_ofb_allowed, bool warn);
index 5ae47e6c174d39f577a66912e7bbc364a854757d..a48ad6c5e84e2cc8e46c905accdb1e85e9439873 100644 (file)
@@ -230,6 +230,26 @@ int cipher_kt_block_size (const cipher_kt_t *cipher_kt);
  */
 int cipher_kt_mode (const cipher_kt_t *cipher_kt);
 
+/**
+ * Check of the supplied cipher is a supported CBC mode cipher.
+ *
+ * @param cipher       Static cipher parameters. May not be NULL.
+ *
+ * @return             true iff the cipher is a CBC mode cipher.
+ */
+bool cipher_kt_mode_cbc(const cipher_kt_t *cipher)
+  __attribute__((nonnull));
+
+/**
+ * Check of the supplied cipher is a supported OFB or CFB mode cipher.
+ *
+ * @param cipher       Static cipher parameters. May not be NULL.
+ *
+ * @return             true iff the cipher is a OFB or CFB mode cipher.
+ */
+bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
+  __attribute__((nonnull));
+
 
 /**
  *
@@ -287,6 +307,16 @@ int cipher_ctx_block_size (const cipher_ctx_t *ctx);
  */
 int cipher_ctx_mode (const cipher_ctx_t *ctx);
 
+/**
+ * Returns the static cipher parameters for this context.
+ *
+ * @param ctx          Cipher's context. May not be NULL.
+ *
+ * @return             Static cipher parameters for the supplied context.
+ */
+const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
+  __attribute__((nonnull));
+
 /**
  * Resets the given cipher context, setting the IV to the specified value.
  * Preserves the associated key information.
index 8c714a20e4d08938cae28db80ef214a1a531826f..4ba0f2d5c2ba5cad05fd07ec5fe384be8647f3ab 100644 (file)
@@ -296,10 +296,9 @@ show_available_ciphers ()
       const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid);
       if (cipher)
        {
-         const unsigned int mode = EVP_CIPHER_mode (cipher);
-         if (mode == EVP_CIPH_CBC_MODE
+         if (cipher_kt_mode_cbc(cipher)
 #ifdef ENABLE_OFB_CFB_MODE
-             || mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE
+             || cipher_kt_mode_ofb_cfb(cipher)
 #endif
              )
            printf ("%s %d bit default key (%s)\n",
@@ -518,6 +517,29 @@ cipher_kt_mode (const EVP_CIPHER *cipher_kt)
   return EVP_CIPHER_mode (cipher_kt);
 }
 
+bool
+cipher_kt_mode_cbc(const cipher_kt_t *cipher)
+{
+  return cipher_kt_mode(cipher) == OPENVPN_MODE_CBC
+#ifdef EVP_CIPH_FLAG_AEAD_CIPHER
+      /* Exclude AEAD cipher modes, they require a different API */
+      && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
+#endif
+    ;
+}
+
+bool
+cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
+{
+  return (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
+         cipher_kt_mode(cipher) == OPENVPN_MODE_CFB)
+#ifdef EVP_CIPH_FLAG_AEAD_CIPHER
+      /* Exclude AEAD cipher modes, they require a different API */
+      && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
+#endif
+    ;
+}
+
 /*
  *
  * Generic cipher context functions
@@ -571,6 +593,13 @@ cipher_ctx_mode (const EVP_CIPHER_CTX *ctx)
   return EVP_CIPHER_CTX_mode (ctx);
 }
 
+const cipher_kt_t *
+cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
+{
+  return EVP_CIPHER_CTX_cipher(ctx);
+}
+
+
 int
 cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
 {
index 1f27d6ca11438346438040f8abd25505aabf9a25..8bf8d8d1c9f9b2c0ccb482abec2bce3ac3f08e37 100644 (file)
@@ -416,6 +416,19 @@ cipher_kt_mode (const cipher_info_t *cipher_kt)
   return cipher_kt->mode;
 }
 
+bool
+cipher_kt_mode_cbc(const cipher_kt_t *cipher)
+{
+  return cipher_kt_mode(cipher) == OPENVPN_MODE_CBC;
+}
+
+bool
+cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher)
+{
+  return (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB ||
+         cipher_kt_mode(cipher) == OPENVPN_MODE_CFB);
+}
+
 
 /*
  *
@@ -464,6 +477,14 @@ int cipher_ctx_mode (const cipher_context_t *ctx)
   return cipher_kt_mode(ctx->cipher_info);
 }
 
+const cipher_kt_t *
+cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx)
+{
+  ASSERT(NULL != ctx);
+
+  return ctx->cipher_info;
+}
+
 int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf)
 {
   return 0 == cipher_reset(ctx, iv_buf);
index 88883fb7a9e009dd00879f3b02ecf35a4c2a3f5a..18f506c895514a040f114d4dc67c7c9a3d3198c9 100644 (file)
@@ -2161,7 +2161,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
                               options->use_iv);
 
   /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */
-  packet_id_long_form = cfb_ofb_mode (&c->c1.ks.key_type);
+  packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher);
 
   /* Compute MTU parameters */
   crypto_adjust_frame_parameters (&c->c2.frame,