GnuTLS: Suite B validation

This allows OpenSSL-style configuration of Suite B parameters to be used
in the wpa_supplicant network profile. 128-bit and 192-bit level
requirements for ECDHE-ECDSA cases are supported. RSA >=3K case is
enforced using GnuTLS %PROFILE_HIGH special priority string keyword.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2017-12-28 18:46:28 +02:00
parent dd227e67ab
commit c36d822418

View file

@ -346,6 +346,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
int ret;
const char *err;
char prio_buf[100];
const char *prio = NULL;
if (conn == NULL || params == NULL)
return -1;
@ -400,16 +403,46 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (params->flags & (TLS_CONN_DISABLE_TLSv1_0 |
TLS_CONN_DISABLE_TLSv1_1 |
TLS_CONN_DISABLE_TLSv1_2)) {
const char *err;
char prio[100];
os_snprintf(prio, sizeof(prio), "NORMAL:-VERS-SSL3.0%s%s%s",
os_snprintf(prio_buf, sizeof(prio_buf),
"NORMAL:-VERS-SSL3.0%s%s%s",
params->flags & TLS_CONN_DISABLE_TLSv1_0 ?
":-VERS-TLS1.0" : "",
params->flags & TLS_CONN_DISABLE_TLSv1_1 ?
":-VERS-TLS1.1" : "",
params->flags & TLS_CONN_DISABLE_TLSv1_2 ?
":-VERS-TLS1.2" : "");
prio = prio_buf;
}
if (params->openssl_ciphers) {
if (os_strcmp(params->openssl_ciphers, "SUITEB128") == 0) {
prio = "SUITEB128";
} else if (os_strcmp(params->openssl_ciphers,
"SUITEB192") == 0) {
prio = "SUITEB192";
} else if ((params->flags & TLS_CONN_SUITEB) &&
os_strcmp(params->openssl_ciphers,
"ECDHE-RSA-AES256-GCM-SHA384") == 0) {
prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
} else if (os_strcmp(params->openssl_ciphers,
"ECDHE-RSA-AES256-GCM-SHA384") == 0) {
prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
} else if (os_strcmp(params->openssl_ciphers,
"DHE-RSA-AES256-GCM-SHA384") == 0) {
prio = "NONE:+VERS-TLS1.2:+AEAD:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
} else if (os_strcmp(params->openssl_ciphers,
"ECDHE-ECDSA-AES256-GCM-SHA384") == 0) {
prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL";
} else {
wpa_printf(MSG_INFO,
"GnuTLS: openssl_ciphers not supported");
return -1;
}
} else if (params->flags & TLS_CONN_SUITEB) {
prio = "NONE:+VERS-TLS1.2:+AEAD:+ECDHE-ECDSA:+ECDHE-RSA:+DHE-RSA:+AES-256-GCM:+SIGN-RSA-SHA384:+CURVE-SECP384R1:+COMP-NULL:%PROFILE_HIGH";
}
if (prio) {
wpa_printf(MSG_DEBUG, "GnuTLS: Set priority string: %s", prio);
ret = gnutls_priority_set_direct(conn->session, prio, &err);
if (ret < 0) {
@ -420,11 +453,6 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
}
if (params->openssl_ciphers) {
wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
return -1;
}
/* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
* to force peer validation(?) */
@ -1375,6 +1403,7 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
ret = gnutls_handshake(conn->session);
if (ret < 0) {
gnutls_alert_description_t alert;
union tls_event_data ev;
switch (ret) {
case GNUTLS_E_AGAIN:
@ -1385,14 +1414,29 @@ struct wpabuf * tls_connection_handshake(void *tls_ctx,
conn->push_buf = wpabuf_alloc(0);
}
break;
case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
wpa_printf(MSG_DEBUG, "GnuTLS: Unacceptable DH prime");
if (conn->global->event_cb) {
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = 1;
ev.alert.type = "fatal";
ev.alert.description = "insufficient security";
conn->global->event_cb(conn->global->cb_ctx,
TLS_ALERT, &ev);
}
/*
* Could send a TLS Alert to the server, but for now,
* simply terminate handshake.
*/
conn->failed++;
conn->write_alerts++;
break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
alert = gnutls_alert_get(conn->session);
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
__func__, gnutls_alert_get_name(alert));
conn->read_alerts++;
if (conn->global->event_cb != NULL) {
union tls_event_data ev;
os_memset(&ev, 0, sizeof(ev));
ev.alert.is_local = 0;
ev.alert.type = gnutls_alert_get_name(alert);