From: Jouni Malinen Date: Sun, 11 Jan 2015 16:45:59 +0000 (+0200) Subject: GnuTLS: Verify that server certificate EKU is valid for a server X-Git-Tag: hostap_2_4~431 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0e1bb94b9138f5aad5482310bbc560fb81993b61;p=thirdparty%2Fhostap.git GnuTLS: Verify that server certificate EKU is valid for a server The server certificate will be rejected if it includes any EKU and none of the listed EKUs is either TLS Web Server Authentication or ANY. Signed-off-by: Jouni Malinen --- diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index 3245bfd45..ca5226a68 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -741,6 +741,42 @@ static void gnutls_tls_fail_event(struct tls_connection *conn, } +#if GNUTLS_VERSION_NUMBER < 0x030300 +static int server_eku_purpose(gnutls_x509_crt_t cert) +{ + unsigned int i; + + for (i = 0; ; i++) { + char oid[128]; + size_t oid_size = sizeof(oid); + int res; + + res = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid, + &oid_size, NULL); + if (res == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + if (i == 0) { + /* No EKU - assume any use allowed */ + return 1; + } + break; + } + + if (res < 0) { + wpa_printf(MSG_INFO, "GnuTLS: Failed to get EKU"); + return 0; + } + + wpa_printf(MSG_DEBUG, "GnuTLS: Certificate purpose: %s", oid); + if (os_strcmp(oid, GNUTLS_KP_TLS_WWW_SERVER) == 0 || + os_strcmp(oid, GNUTLS_KP_ANY) == 0) + return 1; + } + + return 0; +} +#endif /* < 3.3.0 */ + + static int tls_connection_verify_peer(gnutls_session_t session) { struct tls_connection *conn; @@ -749,6 +785,7 @@ static int tls_connection_verify_peer(gnutls_session_t session) const gnutls_datum_t *certs; gnutls_x509_crt_t cert; gnutls_alert_description_t err; + int res; conn = gnutls_session_get_ptr(session); if (!conn->verify_peer) { @@ -759,7 +796,24 @@ static int tls_connection_verify_peer(gnutls_session_t session) wpa_printf(MSG_DEBUG, "GnuTSL: Verifying peer certificate"); - if (gnutls_certificate_verify_peers2(session, &status) < 0) { +#if GNUTLS_VERSION_NUMBER >= 0x030300 + { + gnutls_typed_vdata_st data[1]; + unsigned int elements = 0; + + os_memset(data, 0, sizeof(data)); + if (!conn->global->server) { + data[elements].type = GNUTLS_DT_KEY_PURPOSE_OID; + data[elements].data = (void *) GNUTLS_KP_TLS_WWW_SERVER; + elements++; + } + res = gnutls_certificate_verify_peers(session, data, 1, + &status); + } +#else /* < 3.3.0 */ + res = gnutls_certificate_verify_peers2(session, &status); +#endif + if (res < 0) { wpa_printf(MSG_INFO, "TLS: Failed to verify peer " "certificate chain"); err = GNUTLS_A_INTERNAL_ERROR; @@ -904,6 +958,26 @@ static int tls_connection_verify_peer(gnutls_session_t session) /* TODO: validate altsubject_match. * For now, any such configuration is rejected in * tls_connection_set_params() */ + +#if GNUTLS_VERSION_NUMBER < 0x030300 + /* + * gnutls_certificate_verify_peers() not available, so + * need to check EKU separately. + */ + if (!conn->global->server && + !server_eku_purpose(cert)) { + wpa_printf(MSG_WARNING, + "GnuTLS: No server EKU"); + gnutls_tls_fail_event( + conn, &certs[i], i, buf, + "No server EKU", + TLS_FAIL_BAD_CERTIFICATE); + err = GNUTLS_A_BAD_CERTIFICATE; + gnutls_x509_crt_deinit(cert); + os_free(buf); + goto out; + } +#endif /* < 3.3.0 */ } if (!conn->disable_time_checks &&