diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index c223eafa3..7ee3fa3a0 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -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);