From: Nikos Mavrogiannopoulos Date: Fri, 14 Aug 2015 09:27:50 +0000 (+0200) Subject: Re-enable the certificate key usage checks for compliance with ciphersuite X-Git-Tag: gnutls_3_5_0~736 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=701526f31dc2e7fffa23b2cf2698cd3e407c3ff9;p=thirdparty%2Fgnutls.git Re-enable the certificate key usage checks for compliance with ciphersuite There is a new attack on the TLS protocol which relies on using certificates for ECDSA as certificates for ECDH ciphersuites. That attack while it doesn't affect gnutls, which doesn't support static ECDH, assumes that implementations ignore the key usage bits in the certificate. We have done it since 3.1.0 for compatibility reasons (see http://www.gnutls.org/faq.html#key-usage-violation), but that clearly opens the door for real attacks in the future. For this reason the key usage bits will no longer be ignored. Resolves #24 --- diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index a8bc811ccc..3f327943e0 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -662,6 +662,7 @@ struct gnutls_priority_st { safe_renegotiation_t sr; bool min_record_version; bool server_precedence; + bool allow_key_usage_violation; bool allow_wrong_pms; bool no_tickets; bool no_etm; @@ -690,6 +691,7 @@ struct gnutls_priority_st { (x)->allow_large_records = 1; \ (x)->no_etm = 1; \ (x)->no_ext_master_secret = 1; \ + (x)->allow_key_usage_violation = 1; \ (x)->allow_wrong_pms = 1; \ (x)->dumbfw = 1 diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c index 4764e14ab4..215404b170 100644 --- a/lib/gnutls_sig.c +++ b/lib/gnutls_sig.c @@ -157,6 +157,25 @@ _gnutls_handshake_sign_data(gnutls_session_t session, } +static +int check_key_usage_for_sig(gnutls_session_t session, unsigned key_usage) +{ + if (key_usage != 0) { + if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { + gnutls_assert(); + if (session->internals.priorities.allow_key_usage_violation == 0) { + _gnutls_audit_log(session, + "Peer's certificate does not allow digital signatures. Key usage violation detected.\n"); + return GNUTLS_E_KEY_USAGE_VIOLATION; + } else { + _gnutls_audit_log(session, + "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); + } + } + } + return 0; +} + /* This will create a PKCS1 or DSA signature, as defined in the TLS protocol. * Cert is the certificate of the corresponding private key. It is only checked if * it supports signing. @@ -169,19 +188,16 @@ sign_tls_hash(gnutls_session_t session, const mac_entry_st * hash_algo, { const version_entry_st *ver = get_version(session); unsigned int key_usage = 0; + int ret; /* If our certificate supports signing */ if (cert != NULL) { gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); - if (key_usage != 0) { - if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { - gnutls_assert(); - _gnutls_audit_log(session, - "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); - } - } + ret = check_key_usage_for_sig(session, key_usage); + if (ret < 0) + return gnutls_assert_val(ret); } if (!_gnutls_version_has_selectable_sighash(ver)) @@ -212,14 +228,9 @@ verify_tls_hash(gnutls_session_t session, gnutls_pubkey_get_key_usage(cert->pubkey, &key_usage); - /* If the certificate supports signing continue. - */ - if (key_usage != 0) - if (!(key_usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { - gnutls_assert(); - _gnutls_audit_log(session, - "Peer's certificate does not allow digital signatures. Key usage violation detected (ignored).\n"); - } + ret = check_key_usage_for_sig(session, key_usage); + if (ret < 0) + return gnutls_assert_val(ret); if (pk_algo == GNUTLS_PK_UNKNOWN) pk_algo =