From d3a0dde57754d2b434957c126e1a22e2094cbbf1 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Thu, 25 Apr 2019 18:24:33 +0100 Subject: [PATCH] GnuTLS 3.6.7 cipher strings (cherry picked from commits d9acfc1ce6, 57eb2f6463, b9c6f63cd5) WARNING: This changes user-visible and configuration-visible behaviour. Read the ChangeLog! (cherry picked from commit 656b804e099a4704bd6071241a85bc1e0cc85887) (cherry picked from commit bf9375eaa85bfa0dbb973aa03accbe5f21808732) --- doc/doc-txt/ChangeLog | 9 ++++++ src/src/tls-gnu.c | 73 +++++++++++++++++++++++++++++++++---------- test/confs/2019 | 9 +----- test/log/5821 | 4 +-- test/runtest | 23 ++++++++++++-- 5 files changed, 89 insertions(+), 29 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 70fdc9510..445755dc6 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -56,6 +56,15 @@ JH/13 Bug 2386: Fix builds with Dane under LibreSSL 2.9.0 onward. Some old API was removed, so update to use the newer ones. +JH/16 GnuTLS: rework ciphersuite strings under recent library versions. Thanks + to changes apparently associated with TLS1.3 handling some of the APIs + previously used were either nonfunctional or inappropriate. Strings + like TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM__AEAD:256 + and TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_128_CBC__SHA256:128 replace + the previous TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256 . + This affects log line X= elements, the $tls_{in,out}_cipher variables, + and the use of specific cipher names in the encrypted= ACL condition. + Exim version 4.92 ----------------- diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index de2d70c09..af815d224 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -67,6 +67,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries). #if GNUTLS_VERSION_NUMBER >= 0x030109 # define SUPPORT_CORK #endif +#if GNUTLS_VERSION_NUMBER >= 0x03010a +# define SUPPORT_GNUTLS_SESS_DESC +#endif #if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP) # define SUPPORT_SRV_OCSP_STACK #endif @@ -1487,23 +1490,61 @@ state->peerdn = NULL; cipher = gnutls_cipher_get(state->session); protocol = gnutls_protocol_get_version(state->session); mac = gnutls_mac_get(state->session); -kx = gnutls_kx_get(state->session); - -string_format(cipherbuf, sizeof(cipherbuf), - "%s:%s:%d", - gnutls_protocol_get_name(protocol), - gnutls_cipher_suite_get_name(kx, cipher, mac), - (int) gnutls_cipher_get_key_size(cipher) * 8); - -/* I don't see a way that spaces could occur, in the current GnuTLS -code base, but it was a concern in the old code and perhaps older GnuTLS -releases did return "TLS 1.0"; play it safe, just in case. */ -for (p = cipherbuf; *p != '\0'; ++p) - if (isspace(*p)) - *p = '-'; +kx = +#ifdef GNUTLS_TLS1_3 + protocol >= GNUTLS_TLS1_3 ? 0 : +#endif + gnutls_kx_get(state->session); + old_pool = store_pool; -store_pool = POOL_PERM; -state->ciphersuite = string_copy(cipherbuf); + { + store_pool = POOL_PERM; + +#ifdef SUPPORT_GNUTLS_SESS_DESC + { + gstring * g = NULL; + uschar * s = US gnutls_session_get_desc(state->session), c; + + /* Nikos M suggests we use this by preference. It returns like: + (TLS1.3)-(ECDHE-SECP256R1)-(RSA-PSS-RSAE-SHA256)-(AES-256-GCM) + + For partial back-compat, put a colon after the TLS version, replace the + )-( grouping with __, replace in-group - with _ and append the :keysize. */ + + /* debug_printf("peer_status: gnutls_session_get_desc %s\n", s); */ + + for (s++; (c = *s) && c != ')'; s++) g = string_catn(g, s, 1); + g = string_catn(g, US":", 1); + if (*s) s++; /* now on _ between groups */ + while ((c = *s)) + { + for (*++s && ++s; (c = *s) && c != ')'; s++) g = string_catn(g, c == '-' ? US"_" : s, 1); + /* now on ) closing group */ + if ((c = *s) && *++s == '-') g = string_catn(g, US"__", 2); + /* now on _ between groups */ + } + g = string_catn(g, US":", 1); + g = string_cat(g, string_sprintf("%d", (int) gnutls_cipher_get_key_size(cipher) * 8)); + state->ciphersuite = string_from_gstring(g); + } +#else + state->ciphersuite = string_sprintf("%s:%s:%d", + gnutls_protocol_get_name(protocol), + gnutls_cipher_suite_get_name(kx, cipher, mac), + (int) gnutls_cipher_get_key_size(cipher) * 8); + + /* I don't see a way that spaces could occur, in the current GnuTLS + code base, but it was a concern in the old code and perhaps older GnuTLS + releases did return "TLS 1.0"; play it safe, just in case. */ + + for (uschar * p = state->ciphersuite; *p; p++) if (isspace(*p)) *p = '-'; +#endif + +/* debug_printf("peer_status: ciphersuite %s\n", state->ciphersuite); */ + + state->tlsp->cipher = state->ciphersuite; + state->tlsp->bits = gnutls_cipher_get_key_size(cipher) * 8; + } store_pool = old_pool; state->tlsp->cipher = state->ciphersuite; diff --git a/test/confs/2019 b/test/confs/2019 index fdc030c23..bd2cf5a6a 100644 --- a/test/confs/2019 +++ b/test/confs/2019 @@ -29,14 +29,7 @@ begin acl check_recipient: accept hosts = : deny hosts = HOSTIPV4 - !encrypted = AES256-SHA:\ - AES256-GCM-SHA384:\ - IDEA-CBC-MD5:\ - DES-CBC3-SHA:\ - DHE_RSA_AES_256_CBC_SHA1:\ - DHE_RSA_3DES_EDE_CBC_SHA:\ - RSA_AES_256_CBC_SHA1 :\ - ECDHE_RSA_AES_256_GCM_SHA384 + !encrypted = * accept diff --git a/test/log/5821 b/test/log/5821 index 1ce642635..b95cfbe44 100644 --- a/test/log/5821 +++ b/test/log/5821 @@ -8,7 +8,7 @@ 1999-03-02 09:44:33 10HmbB-0005vi-00 => CALLER@localhost.test.ex R=client T=send_to_server H=localhost.test.ex [127.0.0.1] X=TLS1.x:ke-RSA-AES256-SHAnnn:xxx CV=yes DN="CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00" 1999-03-02 09:44:33 10HmbB-0005vi-00 Completed 1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane256ee.test.ex -1999-03-02 09:44:33 10HmbD-0005vi-00 => CALLER@dane256ee.test.ex R=client T=send_to_server H=dane256ee.test.ex [ip4.ip4.ip4.ip4] X=TLS1.2:RSA_CAMELLIA_256_GCM_SHA384:256 CV=dane DN="CN=server1.example.com" C="250 OK id=10HmbE-0005vi-00" +1999-03-02 09:44:33 10HmbD-0005vi-00 => CALLER@dane256ee.test.ex R=client T=send_to_server H=dane256ee.test.ex [ip4.ip4.ip4.ip4] X=TLS1.2:RSA_CAMELLIA_256_GCM-SHAnnn:256 CV=dane DN="CN=server1.example.com" C="250 OK id=10HmbE-0005vi-00" 1999-03-02 09:44:33 10HmbD-0005vi-00 Completed ******** SERVER ******** @@ -26,6 +26,6 @@ 1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: R=server 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed 1999-03-02 09:44:33 "rcpt ACL" -1999-03-02 09:44:33 10HmbE-0005vi-00 <= <> H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.2:RSA_CAMELLIA_256_GCM_SHA384:256 CV=no S=sss id=E10HmbD-0005vi-00@myhost.test.ex for CALLER@dane256ee.test.ex +1999-03-02 09:44:33 10HmbE-0005vi-00 <= <> H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtps X=TLS1.2:RSA_CAMELLIA_256_GCM-SHAnnn:256 CV=no S=sss id=E10HmbD-0005vi-00@myhost.test.ex for CALLER@dane256ee.test.ex 1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: R=server 1999-03-02 09:44:33 10HmbE-0005vi-00 Completed diff --git a/test/runtest b/test/runtest index dafca16ec..b6c73bbe0 100755 --- a/test/runtest +++ b/test/runtest @@ -595,11 +595,18 @@ RESET_AFTER_EXTRA_LINE_READ: # GnuTLS have seen: # TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256 + # TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM__AEAD:256 + # TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256 + # TLS1.3:ECDHE_PSK_SECP256R1__AES_256_GCM__AEAD:256 # # TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256 # TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128 # TLS1.2:RSA_AES_256_CBC_SHA1:256 (canonical) # TLS1.2:DHE_RSA_AES_128_CBC_SHA1:128 + # TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_256_GCM:256 + # TLS1.2:ECDHE_SECP256R1__RSA_SHA256__AES_128_CBC__SHA256:128 + # TLS1.2:ECDHE_SECP256R1__ECDSA_SHA512__AES_256_GCM:256 + # TLS1.2:RSA__CAMELLIA_256_GCM:256 (leave the cipher name) # # X=TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256 # X=TLS1.2:RSA_AES_256_CBC_SHA1:256 @@ -611,11 +618,21 @@ RESET_AFTER_EXTRA_LINE_READ: # DHE-RSA-AES256-SHA # picking latter as canonical simply because regex easier that way. s/\bDHE_RSA_AES_128_CBC_SHA1:128/RSA-AES256-SHA1:256/g; - s/TLS1.[0123]:((EC)?DHE_)?(RSA|ECDSA)_AES_(256|128)_(CBC|GCM)_SHA(1|256|384):(256|128)/TLS1.x:ke-$3-AES256-SHAnnn:xxx/g; + s/TLS1.[0123]: # TLS version + ((EC)?DHE(_((?PSK)_)?(SECP256R1|X25519))?__?)? # key-exchange + ((?RSA|ECDSA)((_PSS_RSAE)?_SHA(512|256))?__?)? # authentication + AES_(256|128)_(CBC|GCM) # cipher + (__?SHA(1|256|384))?: # PRF + (256|128) # cipher strength + /"TLS1.x:ke-" + . (defined($+{psk}) ? $+{psk} : "") + . (defined($+{auth}) ? $+{auth} : "") + . "-AES256-SHAnnn:xxx"/genx; + s/TLS1.2:RSA__CAMELLIA_256_GCM(_SHA384)?:256/TLS1.2:RSA_CAMELLIA_256_GCM-SHAnnn:256/g; s/\b(ECDHE-(RSA|ECDSA)-AES256-SHA|DHE-RSA-AES256-SHA256)\b/ke-$2-AES256-SHAnnn/g; # GnuTLS library error message changes - s/No certificate was found/The peer did not send any certificate/g; + s/(No certificate was found|Certificate is required)/The peer did not send any certificate/g; #(dodgy test?) s/\(certificate verification failed\): invalid/\(gnutls_handshake\): The peer did not send any certificate./g; s/\(gnutls_priority_set\): No or insufficient priorities were set/\(gnutls_handshake\): Could not negotiate a supported cipher suite/g; s/\(gnutls_handshake\): \KNo supported cipher suites have been found.$/Could not negotiate a supported cipher suite./; @@ -1254,7 +1271,7 @@ RESET_AFTER_EXTRA_LINE_READ: s/(DKIM: validation error: )error:[0-9A-F]{8}:rsa routines:(?:(?i)int_rsa_verify|CRYPTO_internal):(?:bad signature|algorithm mismatch)$/$1Public key signature verification has failed./; # gnutls version variances - if (/TLS error on connection \(recv\): .* Decode error/) + if (/TLS error on connection \(recv\): .* (Decode error|peer did not send any certificate)/) { my $prev = $_; $_ = ; -- 2.30.2