Package: openvpn
Version: 2.3.2-4
Severity: wishlist
Tags: patch

Hello,

I tried following patch.
https://community.openvpn.net/openvpn/attachment/ticket/301
 [0001-Add-AEAD-cipher-modes.patch]

But there are some problems.

1) XTS mode is not AEAD cipher.
2) CCM mode does not work.
   Because EVP_aes_nnn_ccm() functions is not in OpenSSL_add_all_algorithms()
   and referring to following
   http://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption

   CCM mode differ from other modes in a significant way of EVP functions
   calling.
3) In "crypto.c": crypto_adjust_frame_parameters() function, size of
   authentication tag is unconsidered.
4) For a reason of packed-id is not encrypted, it makes security weaken.

Then I've made a new patch that was off CCM mode and add CTR mode.
In my case of performance test (with aesni cpu), GCM mode is about 10 % better
than CBC mode, CTR and XTS modes are a few % better than CBC mode.
Note that using GCM mode, specify "auth none" to config file.

Dear Maintainer,
Please try the patch and send it Upstream.

Thank you,
Hiroyuki YAMAMORI


-- System Information:
Debian Release: jessie/sid
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)

Kernel: Linux 3.10-2-amd64 (SMP w/8 CPU cores)
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
Shell: /bin/sh linked to /bin/dash

Versions of packages openvpn depends on:
ii  debconf [debconf-2.0]  1.5.51
ii  initscripts            2.88dsf-43
ii  iproute2               3.11.0-1
ii  libc6                  2.17-92+b1
ii  liblzo2-2              2.06-1.2
ii  libpam0g               1.1.3-9
ii  libpkcs11-helper1      1.10-1
ii  libssl1.0.0            1.0.1e-3
ii  net-tools              1.60-25

Versions of packages openvpn recommends:
pn  easy-rsa  <none>

Versions of packages openvpn suggests:
ii  openssl     1.0.1e-3
pn  resolvconf  <none>

-- debconf information excluded
--- a/configure.ac	2013-05-31 21:00:25.000000000 +0900
+++ b/configure.ac	2013-09-08 19:19:13.678406806 +0900
@@ -61,6 +61,13 @@
 )
 
 AC_ARG_ENABLE(
+	[xtra-cipher-modes],
+	[AS_HELP_STRING([--disable-xtra-cipher-modes], [disable xtra cipher modes @<:@default=yes@:>@])],
+	,
+	[enable_xtra_cipher_modes="yes"]
+)
+
+AC_ARG_ENABLE(
 	[ssl],
 	[AS_HELP_STRING([--disable-ssl], [disable SSL support for TLS-based key exchange @<:@default=yes@:>@])],
 	,
@@ -777,6 +784,17 @@
 		[have_openssl_engine="no"; break]
 	)
 
+	have_openssl_xtra_cipher_modes="yes"
+	AC_CHECK_FUNCS(
+		[ \
+			EVP_aes_256_gcm \
+			EVP_aes_256_ctr \
+			EVP_aes_256_xts \
+		],
+		,
+		[have_openssl_xtra_cipher_modes="no"; break]
+	)
+
 	CFLAGS="${saved_CFLAGS}"
 	LIBS="${saved_LIBS}"
 fi
@@ -947,6 +965,10 @@
 		CRYPTO_SSL_LIBS="${OPENSSL_SSL_LIBS}"
 		AC_DEFINE([ENABLE_CRYPTO_OPENSSL], [1], [Use OpenSSL library])
 		test "${have_openssl_engine}" = "yes" && AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [Use crypto library])
+		if test "${enable_xtra_cipher_modes}" = "yes"; then
+			test "${have_openssl_xtra_cipher_modes}" = "yes" && AC_DEFINE([HAVE_XTRA_CIPHER_MODES], [1], [Use crypto library])
+			test "${have_openssl_xtra_cipher_modes}" != "yes" && AC_MSG_ERROR([Xtra cipher modes required but missing])
+		fi
 		;;
 	polarssl)
 		have_crypto_crypto="${have_polarssl_crypto}"
--- a/src/openvpn/crypto.c	2013-05-31 21:00:07.000000000 +0900
+++ b/src/openvpn/crypto.c	2013-09-09 01:23:49.215559844 +0900
@@ -94,16 +94,21 @@
   if (buf->len > 0 && opt->key_ctx_bi)
     {
       struct key_ctx *ctx = &opt->key_ctx_bi->encrypt;
+      unsigned int mode = 0;
 
       /* Do Encrypt from buf -> work */
       if (ctx->cipher)
 	{
 	  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);
+	  int block_size = cipher_ctx_block_size (ctx->cipher);
+	  mode = cipher_ctx_mode (ctx->cipher);
 	  int outlen;
 
-	  if (mode == OPENVPN_MODE_CBC)
+	  if (all_xtra_mode (mode))
+	    ASSERT (opt->flags & CO_USE_IV);	/* IV required */
+
+	  if (mode == OPENVPN_MODE_CBC || all_xtra_mode (mode))
 	    {
 	      CLEAR (iv_buf);
 
@@ -132,7 +137,7 @@
 	      buf_set_write (&b, iv_buf, iv_size);
 	      ASSERT (packet_id_write (&pin, &b, true, false));
 	    }
-	  else /* We only support CBC, CFB, or OFB modes right now */
+	  else /* We only support CBC, CFB, OFB, GCM, CTR or XTS modes right now */
 	    {
 	      ASSERT (0);
 	    }
@@ -151,7 +156,7 @@
 	  ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf));
 
 	  /* Buffer overflow check */
-	  if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher)))
+	  if (!buf_safe (&work, buf->len + block_size))
 	    {
 	      msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d",
 		   buf->capacity,
@@ -160,7 +165,7 @@
 		   work.capacity,
 		   work.offset,
 		   work.len,
-		   cipher_ctx_block_size (ctx->cipher));
+		   block_size);
 	      goto err;
 	    }
 
@@ -171,7 +176,10 @@
 	  /* Flush the encryption buffer */
 	  ASSERT(cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen));
 	  work.len += outlen;
-	  ASSERT (outlen == iv_size);
+
+	  /* Some cipher modes don't need padding */
+	  if (block_size != 1)
+	    ASSERT (outlen == iv_size);
 
 	  /* prepend the IV to the ciphertext */
 	  if (opt->flags & CO_USE_IV)
@@ -206,6 +214,16 @@
 	  ASSERT (output);
 	  hmac_ctx_final (ctx->hmac, output);
 	}
+      else if (aead_mode (mode))
+	{
+	  int tag_len = aead_tag_len (mode);
+	  uint8_t* output = NULL;
+
+	  output = buf_prepend (&work, tag_len);
+	  ASSERT (output);
+	  ASSERT (cipher_ctx_get_tag (ctx->cipher, output, tag_len));
+	  dmsg (D_PACKET_CONTENT, "AEAD TAG: %s", format_hex (output, tag_len, 0, &gc));
+	}
 
       *buf = work;
     }
@@ -275,11 +293,22 @@
 	  const unsigned int mode = cipher_ctx_mode (ctx->cipher);
 	  const int iv_size = cipher_ctx_iv_length (ctx->cipher);
 	  uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH];
+	  uint8_t tag_buf[OPENVPN_AEAD_TAG_LENGTH]; /* tag of AEAD ciphertext */
+	  int tag_len = aead_tag_len (mode);
 	  int outlen;
 
 	  /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */
 	  ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT)));
 
+	  /* for AEAD ciphers, keep the tag value to feed in later */
+	  if (aead_mode (mode))
+	    {
+	      CLEAR (tag_buf);
+	      memcpy (tag_buf, BPTR (buf), tag_len);
+	      ASSERT (buf_advance (buf, tag_len));
+	      dmsg (D_PACKET_CONTENT, "AEAD TAG: %s", format_hex (tag_buf, tag_len, 0, &gc));
+	    }
+
 	  /* use IV if user requested it */
 	  CLEAR (iv_buf);
 	  if (opt->flags & CO_USE_IV)
@@ -305,6 +334,12 @@
 	  if (!buf_safe (&work, buf->len))
 	    CRYPT_ERROR ("buffer overflow");
 
+	  /* feed in tag and the authenticated data for AEAD mode ciphers */
+	  if (aead_mode (mode))
+	    {
+	      ASSERT (cipher_ctx_set_tag (ctx->cipher, tag_buf, tag_len));
+	    }
+
 	  /* Decrypt packet ID, payload */
 	  if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf)))
 	    CRYPT_ERROR ("cipher update failed");
@@ -320,12 +355,12 @@
 
 	  /* Get packet ID from plaintext buffer or IV, depending on cipher mode */
 	  {
-	    if (mode == OPENVPN_MODE_CBC)
+	    if (mode == OPENVPN_MODE_CBC || all_xtra_mode (mode))
 	      {
 		if (opt->packet_id)
 		  {
 		    if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)))
-		      CRYPT_ERROR ("error reading CBC packet-id");
+		      CRYPT_ERROR ("error reading packet-id");
 		    have_pin = true;
 		  }
 	      }
@@ -341,7 +376,7 @@
 		  CRYPT_ERROR ("error reading CFB/OFB packet-id");
 		have_pin = true;
 	      }
-	    else /* We only support CBC, CFB, or OFB modes right now */
+	    else /* We only support CBC, CFB, OFB, GCM, CTR or XTS modes right now */
 	      {
 		ASSERT (0);
 	      }
@@ -404,6 +439,8 @@
 			    (packet_id ? packet_id_size (packet_id_long_form) : 0) +
 			    ((cipher_defined && use_iv) ? cipher_kt_iv_size (kt->cipher) : 0) +
 			    (cipher_defined ? cipher_kt_block_size (kt->cipher) : 0) + /* worst case padding expansion */
+			    ((cipher_defined && aead_mode (cipher_kt_mode (kt->cipher))) ?
+			      aead_tag_len (cipher_kt_mode (kt->cipher)) : 0) +
 			    kt->hmac_length);
 }
 
@@ -416,6 +453,8 @@
 	       bool authname_defined, int keysize,
 	       bool cfb_ofb_allowed, bool warn)
 {
+  bool aead_cipher = false;
+
   CLEAR (*kt);
   if (ciphername && ciphername_defined)
     {
@@ -427,7 +466,8 @@
       /* check legal cipher mode */
       {
 	const unsigned int mode = cipher_kt_mode (kt->cipher);
-	if (!(mode == OPENVPN_MODE_CBC
+	aead_cipher = aead_mode (mode);
+	if (!(mode == OPENVPN_MODE_CBC || all_xtra_mode (mode)
 #ifdef ALLOW_NON_CBC_CIPHERS
 	      || (cfb_ofb_allowed && (mode == OPENVPN_MODE_CFB || mode == OPENVPN_MODE_OFB))
 #endif
@@ -446,10 +486,14 @@
     }
   if (authname && authname_defined)
     {
-      kt->digest = md_kt_get (authname);
-      kt->hmac_length = md_kt_size (kt->digest);
+      if (aead_cipher) {
+	msg (M_FATAL, "AEAD mode cipher '%s' does not need an HMAC algorithm", ciphername);
+      } else {
+	kt->digest = md_kt_get (authname);
+	kt->hmac_length = md_kt_size (kt->digest);
+      }
     }
-  else
+  else if (!aead_cipher)
     {
       if (warn)
 	msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used");
--- a/src/openvpn/crypto.h	2013-05-31 21:00:07.000000000 +0900
+++ b/src/openvpn/crypto.h	2013-09-09 01:43:51.093114639 +0900
@@ -393,6 +393,35 @@
   return key->encrypt.cipher || key->encrypt.hmac || key->decrypt.cipher || key->decrypt.hmac;
 }
 
+static inline bool
+all_xtra_mode (unsigned int mode)
+{
+#ifdef HAVE_XTRA_CIPHER_MODES
+  return mode == OPENVPN_MODE_GCM || mode == OPENVPN_MODE_CTR || mode == OPENVPN_MODE_XTS;
+#else
+  return false;
+#endif
+}
+
+static inline bool
+aead_mode (unsigned int mode)
+{
+#ifdef HAVE_XTRA_CIPHER_MODES
+  return mode == OPENVPN_MODE_GCM;
+#else
+  return false;
+#endif
+}
+
+static inline int
+aead_tag_len (unsigned int mode)
+{
+#ifdef HAVE_XTRA_CIPHER_MODES
+  return mode == OPENVPN_MODE_GCM ? OPENVPN_GCM_TAG_LENGTH : 0;
+#else
+  return 0;
+#endif
+}
 
 #endif /* ENABLE_CRYPTO */
 #endif /* CRYPTO_H */
--- a/src/openvpn/crypto_backend.h	2013-05-31 21:00:07.000000000 +0900
+++ b/src/openvpn/crypto_backend.h	2013-09-08 19:21:22.430003330 +0900
@@ -330,6 +330,24 @@
  */
 int cipher_ctx_final (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len);
 
+/**
+ * Gets the expected message authenticated code (MAC) tag for this cipher.
+ *
+ * @param ctx		The cipher's context
+ * @param tag		The expected MAC tag
+ * @param tag_size	The tag's size, in bytes.
+ */
+int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len);
+
+/**
+ * Sets the expected message authenticated code (MAC) tag for this cipher.
+ *
+ * @param ctx		The cipher's context
+ * @param tag		The expected MAC tag
+ * @param tag_size	The tag's size, in bytes.
+ */
+int cipher_ctx_set_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len);
+
 /*
  *
  * Generic message digest information functions
--- a/src/openvpn/crypto_openssl.c	2013-05-31 21:00:07.000000000 +0900
+++ b/src/openvpn/crypto_openssl.c	2013-09-08 19:36:06.052330292 +0900
@@ -316,6 +316,9 @@
 	{
 	  const unsigned int mode = EVP_CIPHER_mode (cipher);
 	  if (mode == EVP_CIPH_CBC_MODE
+#ifdef HAVE_XTRA_CIPHER_MODES
+	      || mode == EVP_CIPH_GCM_MODE || mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_XTS_MODE
+#endif
 #ifdef ALLOW_NON_CBC_CIPHERS
 	      || mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE
 #endif
@@ -608,6 +611,25 @@
   return EVP_CipherFinal (ctx, dst, dst_len);
 }
 
+int cipher_ctx_get_tag (EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size)
+{
+#ifdef HAVE_XTRA_CIPHER_MODES
+  return EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf);
+#else
+  ASSERT (0);
+#endif
+}
+
+int
+cipher_ctx_set_tag (EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size)
+{
+#ifdef HAVE_XTRA_CIPHER_MODES
+  return EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, tag_size, tag_buf);
+#else
+  ASSERT (0);
+#endif
+}
+
 
 void
 cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
--- a/src/openvpn/crypto_openssl.h	2013-05-31 21:00:07.000000000 +0900
+++ b/src/openvpn/crypto_openssl.h	2013-09-08 23:21:52.017145222 +0900
@@ -61,6 +61,26 @@
 /** Cipher is in CFB mode */
 #define OPENVPN_MODE_CFB 	EVP_CIPH_CFB_MODE
 
+/** Cipher is in GCM mode */
+#define OPENVPN_MODE_GCM 	EVP_CIPH_GCM_MODE
+
+/* not support CCM mode */
+
+/** Cipher is in CTR mode */
+#define OPENVPN_MODE_CTR 	EVP_CIPH_CTR_MODE
+
+/** Cipher is in XTS mode */
+#define OPENVPN_MODE_XTS 	EVP_CIPH_XTS_MODE
+
+#ifdef HAVE_XTRA_CIPHER_MODES
+#define OPENVPN_AEAD_TAG_LENGTH	EVP_GCM_TLS_TAG_LEN
+/** Tag length of GCM mode is 16 */
+#define OPENVPN_GCM_TAG_LENGTH	OPENVPN_AEAD_TAG_LENGTH
+/*	OPENVPN_CCM_TAG_LENGTH	12 */
+#else
+#define OPENVPN_AEAD_TAG_LENGTH	0
+#endif
+
 /** Cipher should encrypt */
 #define OPENVPN_OP_ENCRYPT 	1
 
--- a/src/openvpn/crypto_polarssl.c	2013-05-31 21:00:07.000000000 +0900
+++ b/src/openvpn/crypto_polarssl.c	2013-09-08 19:22:18.890318231 +0900
@@ -493,6 +493,16 @@
   return 0 == retval;
 }
 
+int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len)
+{
+  ASSERT (0);
+}
+
+int cipher_ctx_set_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len)
+{
+  ASSERT (0);
+}
+
 void
 cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH],
     unsigned char *src,

Reply via email to