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,