Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP2:GA
openvpn.23372
0006-Discourage-using-64-bit-block-ciphers.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0006-Discourage-using-64-bit-block-ciphers.patch of Package openvpn.23372
From 610fdbbdb0abf65c1e7620143afccd62cd162a8f Mon Sep 17 00:00:00 2001 From: Steffan Karger <steffan@karger.me> Date: Tue, 16 Aug 2016 16:46:01 +0200 Subject: [PATCH] Discourage using 64-bit block ciphers As discussed with the development team, we should start moving away from ciphers with a small block size. For OpenVPN in particular this means moving away from 64-bit block ciphers, towards 128-bit block ciphers. This patch makes a start with that by moving ciphers with a block size < 128 bits to the bottom of the --show-ciphers output, and printing a warning in the connection phase if such a cipher is used. While touching this function, improve the output of --show-ciphers by ordering the output alphabetically, and changing the output format slightly. [DS: Fixed C89 issues in patch, moving 'int nid' and 'size_t i' declaration to begining of function instead of in the for-loops. This is also required to not break building on stricter compiler setups where C99 must be enabled explicitly ] Signed-off-by: Steffan Karger <steffan@karger.me> Acked-by: Arne Schwabe <arne@rfc2549.org> Message-Id: <1471358761-8828-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00030.html CVE: 2016-6329 Signed-off-by: David Sommerseth <davids@openvpn.net> --- src/openvpn/crypto.c | 11 +++-- src/openvpn/crypto_openssl.c | 110 ++++++++++++++++++++++++++++++++++-------- src/openvpn/crypto_polarssl.c | 41 ++++++++++++++-- tests/t_lpback.sh | 2 +- 4 files changed, 135 insertions(+), 29 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 400bf117..552e3332 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -492,9 +492,14 @@ init_key_ctx (struct key_ctx *ctx, struct key *key, dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, format_hex (key->cipher, kt->cipher_length, 0, &gc)); dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", - prefix, - cipher_kt_block_size(kt->cipher), - cipher_kt_iv_size(kt->cipher)); + prefix, cipher_kt_block_size(kt->cipher), + cipher_kt_iv_size(kt->cipher)); + if (cipher_kt_block_size(kt->cipher) < 128/8) + { + msg (M_WARN, "WARNING: this cipher's block size is less than 128 bit " + "(%d bit). Consider using a --cipher with a larger block size.", + cipher_kt_block_size(kt->cipher)*8); + } } if (kt->digest && kt->hmac_length > 0) { diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index c147245a..2180b1a4 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -288,11 +288,45 @@ translate_cipher_name_to_openvpn (const char *cipher_name) { return cipher_name; } +static int +cipher_name_cmp(const void *a, const void *b) +{ + const EVP_CIPHER * const *cipher_a = a; + const EVP_CIPHER * const *cipher_b = b; + + const char *cipher_name_a = + translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_a)); + const char *cipher_name_b = + translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_b)); + + return strcmp(cipher_name_a, cipher_name_b); +} + +static void +print_cipher(const EVP_CIPHER *cipher) +{ + const char *var_key_size = + (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? + " by default" : ""; + const char *ssl_only = cipher_kt_mode_cbc(cipher) ? + "" : ", TLS client/server mode only"; + + printf ("%s (%d bit key%s, %d bit block%s)\n", + translate_cipher_name_to_openvpn (EVP_CIPHER_name (cipher)), + EVP_CIPHER_key_length (cipher) * 8, var_key_size, + cipher_kt_block_size (cipher) * 8, ssl_only); +} + void show_available_ciphers () { int nid; + size_t i; + /* If we ever exceed this, we must be more selective */ + const size_t cipher_list_len = 1000; + const EVP_CIPHER *cipher_list[cipher_list_len]; + size_t num_ciphers = 0; #ifndef ENABLE_SMALL printf ("The following ciphers and cipher modes are available\n" "for use with " PACKAGE_NAME ". Each cipher shown below may be\n" @@ -302,29 +336,37 @@ show_available_ciphers () "is recommended. In static key mode only CBC mode is allowed.\n\n"); #endif - for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ + for (nid = 0; nid < 10000; ++nid) { - const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid); - if (cipher) - { - if (cipher_kt_mode_cbc(cipher) + const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid); + if (cipher && (cipher_kt_mode_cbc(cipher) #ifdef ENABLE_OFB_CFB_MODE || cipher_kt_mode_ofb_cfb(cipher) #endif - ) - { - const char *var_key_size = - (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? - "variable" : "fixed"; - const char *ssl_only = cipher_kt_mode_ofb_cfb(cipher) ? - " (TLS client/server mode)" : ""; - - printf ("%s %d bit default key (%s)%s\n", OBJ_nid2sn (nid), - EVP_CIPHER_key_length (cipher) * 8, var_key_size, - ssl_only); - } + )) + { + cipher_list[num_ciphers++] = cipher; + } + if (num_ciphers == cipher_list_len) + { + msg (M_WARN, "WARNING: Too many ciphers, not showing all"); + break; } } + + qsort (cipher_list, num_ciphers, sizeof(*cipher_list), cipher_name_cmp); + + for (i = 0; i < num_ciphers; i++) { + if (cipher_kt_block_size(cipher_list[i]) >= 128/8) + print_cipher(cipher_list[i]); + } + + printf ("\nThe following ciphers have a block size of less than 128 bits, \n" + "and are therefore deprecated. Do not use unless you have to.\n\n"); + for (i = 0; i < num_ciphers; i++) { + if (cipher_kt_block_size(cipher_list[i]) < 128/8) + print_cipher(cipher_list[i]); + } printf ("\n"); } @@ -530,9 +572,37 @@ cipher_kt_iv_size (const EVP_CIPHER *cipher_kt) } int -cipher_kt_block_size (const EVP_CIPHER *cipher_kt) -{ - return EVP_CIPHER_block_size (cipher_kt); +cipher_kt_block_size (const EVP_CIPHER *cipher) { + /* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work + * around that, try to replace the mode with 'CBC' and return the block size + * reported for that cipher, if possible. If that doesn't work, just return + * the value reported by OpenSSL. + */ + char *name = NULL; + char *mode_str = NULL; + const char *orig_name = NULL; + const EVP_CIPHER *cbc_cipher = NULL; + + int block_size = EVP_CIPHER_block_size(cipher); + + orig_name = cipher_kt_name(cipher); + if (!orig_name) + goto cleanup; + + name = string_alloc(translate_cipher_name_to_openvpn(orig_name), NULL); + mode_str = strrchr (name, '-'); + if (!mode_str || strlen(mode_str) < 4) + goto cleanup; + + strcpy (mode_str, "-CBC"); + + cbc_cipher = EVP_get_cipherbyname(translate_cipher_name_from_openvpn(name)); + if (cbc_cipher) + block_size = EVP_CIPHER_block_size(cbc_cipher); + +cleanup: + free (name); + return block_size; } int diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index 92fdb787..bca6a6f5 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -168,6 +168,25 @@ translate_cipher_name_to_openvpn (const char *cipher_name) { return pair->openvpn_name; } +static void print_cipher(const cipher_kt_t *info) +{ + if (info && (cipher_kt_mode_cbc(info) +#ifdef HAVE_AEAD_CIPHER_MODES + || cipher_kt_mode_aead(info) +#endif + )) + { + const char *ssl_only = cipher_kt_mode_cbc(info) ? + "" : ", TLS client/server mode only"; + const char *var_key_size = info->flags & POLARSSL_CIPHER_VARIABLE_KEY_LEN + ? " by default" : ""; + + printf ("%s (%d bit key%s, %d bit block%s)\n", + cipher_kt_name(info), cipher_kt_key_size(info) * 8, var_key_size, + cipher_kt_block_size(info) * 8, ssl_only); + } +} + void show_available_ciphers () { @@ -184,12 +203,24 @@ show_available_ciphers () while (*ciphers != 0) { - const cipher_info_t *info = cipher_info_from_type(*ciphers); - - if (info && info->mode == POLARSSL_MODE_CBC) - printf ("%s %d bit default key\n", - cipher_kt_name(info), cipher_kt_key_size(info) * 8); + const cipher_kt_t *info = cipher_info_from_type(*ciphers); + if (info && cipher_kt_block_size(info) >= 128/8) + { + print_cipher(info); + } + ciphers++; + } + printf ("\nThe following ciphers have a block size of less than 128 bits, \n" + "and are therefore deprecated. Do not use unless you have to.\n\n"); + ciphers = cipher_list(); + while (*ciphers != 0) + { + const cipher_kt_t *info = cipher_info_from_type(*ciphers); + if (info && cipher_kt_block_size(info) < 128/8) + { + print_cipher(info); + } ciphers++; } printf ("\n"); diff --git a/tests/t_lpback.sh b/tests/t_lpback.sh index d7792cd3..2052c626 100755 --- a/tests/t_lpback.sh +++ b/tests/t_lpback.sh @@ -26,7 +26,7 @@ trap "rm -f key.$$ log.$$ ; exit 1" 0 3 # Get list of supported ciphers from openvpn --show-ciphers output CIPHERS=$(${top_builddir}/src/openvpn/openvpn --show-ciphers | \ - sed -e '1,/^$/d' -e s'/ .*//' -e '/^\s*$/d' | sort) + sed -e '/The following/,/^$/d' -e s'/ .*//' -e '/^\s*$/d') # SK, 2014-06-04: currently the DES-EDE3-CFB1 implementation of OpenSSL is # broken (see http://rt.openssl.org/Ticket/Display.html?id=2867), so exclude -- 2.12.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor