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 <j@w1.fi>
This commit is contained in:
Jouni Malinen 2015-01-11 18:45:59 +02:00
parent d4d1f5cb33
commit 0e1bb94b91

View file

@ -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 &&