Bug#737921: [TLS1.2] gnutls only likes SHA1 and SHA256 certificates
Jan Nordholz
jnordholz at sec.t-labs.tu-berlin.de
Thu Feb 6 23:14:38 UTC 2014
Package: gnutls26
Version: 2.12.23-10
Severity: minor
Dear GnuTLS maintainers,
I've just spent several hours debugging a problem which I think should be
stated somewhere. (Severity minor as it's a documentation issue.)
After replacing some expired certificates, I wondered why satellite exim4
instances would no longer talk to the one that had just received a new
certificate. With s_client and gnutls-cli-debug I could narrow the problem
down to a problem with TLS1.2 - albeit the reason was completely opaque.
The only output on the server side was the infamous
] (gnutls_handshake): Could not negotiate a supported cipher suite.
After single-stepping through exim and hotpatching _gnutls_log_level and
_gnutls_log_func to meaningful values I found that the library was
removing all the ciphers, accompanied by another, even more cryptic
message about the server certificate:
] Feb 6 23:19:58 $HOST exim4: ASSERT: gnutls_handshake.c:3348
] Feb 6 23:19:58 $HOST exim4: Could not find an appropriate certificate: Insufficient credentials for that request.
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_ARCFOUR_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_3DES_EDE_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_AES_128_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_AES_256_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_CAMELLIA_128_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_CAMELLIA_256_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_AES_128_CBC_SHA256
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_DSS_AES_256_CBC_SHA256
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_3DES_EDE_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_AES_128_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_AES_256_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_CAMELLIA_128_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_CAMELLIA_256_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_AES_128_CBC_SHA256
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: DHE_RSA_AES_256_CBC_SHA256
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_ARCFOUR_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_ARCFOUR_MD5
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_3DES_EDE_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_AES_128_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_AES_256_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_CAMELLIA_128_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_CAMELLIA_256_CBC_SHA1
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_AES_128_CBC_SHA256
] Feb 6 23:19:58 $HOST exim4: HSK[0x7fe9524e2680]: Removing ciphersuite: RSA_AES_256_CBC_SHA256
] Feb 6 23:19:58 $HOST exim4: ASSERT: gnutls_handshake.c:921
] Feb 6 23:19:58 $HOST exim4: ASSERT: gnutls_handshake.c:586
] Feb 6 23:19:58 $HOST exim4: ASSERT: gnutls_handshake.c:2358
] Feb 6 23:19:58 $HOST exim4: ASSERT: gnutls_handshake.c:2991
$SEARCHING revealed that I might have set improper keyUsage extensions on the
certificate - however there were none, and as I generated another certificate
with explicit keyUsage just to check, sure enough the problem persisted.
So another round of digging into GnuTLS source code, until I finally
stumbled across this gem:
] int
] _gnutls_server_select_cert (gnutls_session_t session,
] gnutls_pk_algorithm_t requested_algo)
] {
] [...]
] for (i = 0; i < cred->ncerts; i++)
] {
] /* find one compatible certificate
] */
] if (requested_algo == GNUTLS_PK_ANY ||
] requested_algo == cred->cert_list[i][0].subject_pk_algorithm)
] {
] /* if cert type and signature algorithm matches
] */
] /* *INDENT-OFF* */
] if (session->security_parameters.cert_type
] == cred->cert_list[i][0].cert_type
] && (cred->cert_list[i][0].cert_type == GNUTLS_CRT_OPENPGP
] || /* FIXME: make this a check for certificate
] type capabilities */
] !_gnutls_version_has_selectable_sighash
] (gnutls_protocol_get_version (session))
] ||
] _gnutls_session_sign_algo_requested
] (session, cred->cert_list[i][0].sign_algo) == 0))
] {
] idx = i;
] break;
] }
] /* *INDENT-ON* */
] }
] }
requested_algo was PK_ANY, cert_type X509, that part was uninteresting.
_gnutls_version_has_selectable_sighash() is TRUE iff we are doing TLS1.2; ah!
_gnutls_session_sign_algo_requested() looks at whether the client actually
requested a particular signature algorithm to go with that connection; of
course it didn't. So we fall back to an "agreeable default":
] /* extension not received allow SHA1 and SHA256 */
] hash = _gnutls_sign_get_hash_algorithm (sig);
] if (hash == GNUTLS_DIG_SHA1 || hash == GNUTLS_DIG_SHA256)
] return 0;
Better not be an early adopter and create certificates with SHA512...
downgraded the certificate's hash algorithm, and it works flawlessly again.
This error message "Insufficient credentials for that request" *really* has
to go away or to be replaced with something more meaningful. Calling this
"misleading" is still euphemistic...
Jan
More information about the Pkg-gnutls-maint
mailing list