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
-----------------
#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
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;
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
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 ********
1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <CALLER@localhost.test.ex> 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: <CALLER@dane256ee.test.ex> R=server
1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
# 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
# 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>PSK)_)?(SECP256R1|X25519))?__?)? # key-exchange
+ ((?<auth>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./;
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 = $_;
$_ = <IN>;