]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
cert auth: reject auth if no signature algorithm is usable in TLS 1.3
authorDaiki Ueno <dueno@redhat.com>
Thu, 4 Apr 2019 15:01:24 +0000 (17:01 +0200)
committerDaiki Ueno <dueno@redhat.com>
Thu, 4 Apr 2019 15:11:04 +0000 (17:11 +0200)
Previously, when there is no overlap between usable signature
algorithms and the "signature_algorithms" extension in Certificate
Request, the client failed in sending Certificate Verify, followed by
a connection close.  In TLS 1.3, it is possible to keep the connection
but reject the authentication by not sending Certificate Verify.

Signed-off-by: Daiki Ueno <dueno@redhat.com>
lib/tls13/certificate_request.c
lib/tls13/certificate_verify.c
tests/tls13-cert-key-exchange.c

index 002646ed6b0c6c37cd38922e9887e795992c0f87..d56ce4273828b6bb05b901a56d9df5119001b87a 100644 (file)
@@ -128,17 +128,20 @@ int _gnutls13_recv_certificate_request_int(gnutls_session_t session, gnutls_buff
 {
        int ret;
        crt_req_ctx_st ctx;
+       gnutls_pcert_st *apr_cert_list;
+       gnutls_privkey_t apr_pkey;
+       int apr_cert_list_length;
 
        _gnutls_handshake_log("HSK[%p]: parsing certificate request\n", session);
 
+       if (unlikely(session->security_parameters.entity == GNUTLS_SERVER))
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
        /* if initial negotiation is complete, this is a post-handshake auth */
-       if (!session->internals.initial_negotiation_completed ||
-           session->security_parameters.entity == GNUTLS_SERVER) {
+       if (!session->internals.initial_negotiation_completed) {
                if (buf->data[0] != 0) {
                        /* The context field must be empty during handshake */
-                       ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
-                       gnutls_assert();
-                       goto cleanup;
+                       return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
                }
 
                /* buf->length is positive */
@@ -162,10 +165,8 @@ int _gnutls13_recv_certificate_request_int(gnutls_session_t session, gnutls_buff
        ctx.session = session;
 
        ret = _gnutls_extv_parse(&ctx, parse_cert_extension, buf->data, buf->length);
-       if (ret < 0) {
-               gnutls_assert();
-               goto cleanup;
-       }
+       if (ret < 0)
+               return gnutls_assert_val(ret);
 
        /* The "signature_algorithms" extension MUST be specified */
        if (!ctx.got_sig_algo)
@@ -175,15 +176,28 @@ int _gnutls13_recv_certificate_request_int(gnutls_session_t session, gnutls_buff
 
        ret = _gnutls_select_client_cert(session, ctx.rdn, ctx.rdn_size,
                                         ctx.pk_algos, ctx.pk_algos_length);
-       if (ret < 0) {
-               gnutls_assert();
-               goto cleanup;
-       }
+       if (ret < 0)
+               return gnutls_assert_val(ret);
 
-       ret = 0;
+       ret = _gnutls_get_selected_cert(session, &apr_cert_list,
+                                       &apr_cert_list_length, &apr_pkey);
+       if (ret < 0)
+               return gnutls_assert_val(ret);
 
- cleanup:
-       return ret;
+       if (apr_cert_list_length > 0) {
+               gnutls_sign_algorithm_t algo;
+
+               algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0);
+               if (algo == GNUTLS_SIGN_UNKNOWN) {
+                       _gnutls_handshake_log("HSK[%p]: rejecting client auth because of no suitable signature algorithm\n", session);
+                       _gnutls_selected_certs_deinit(session);
+                       return gnutls_assert_val(0);
+               }
+
+               gnutls_sign_algorithm_set_client(session, algo);
+       }
+
+       return 0;
 }
 
 int _gnutls13_recv_certificate_request(gnutls_session_t session)
index 55245f2efd0ff050441c738098ec71d9215cc320..7300f88f5d79f2db560fe4a8a2185dd263d6e05a 100644 (file)
@@ -187,14 +187,19 @@ int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again)
                        }
                }
 
-               algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0);
-               if (algo == GNUTLS_SIGN_UNKNOWN)
-                       return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
+               if (server) {
+                       algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0);
+                       if (algo == GNUTLS_SIGN_UNKNOWN)
+                               return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
 
-               if (server)
                        gnutls_sign_algorithm_set_server(session, algo);
-               else
-                       gnutls_sign_algorithm_set_client(session, algo);
+               } else {
+                       /* for client, signature algorithm is already
+                        * determined from Certificate Request */
+                       algo = gnutls_sign_algorithm_get_client(session);
+                       if (unlikely(algo == GNUTLS_SIGN_UNKNOWN))
+                               return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+               }
 
                se = _gnutls_sign_to_entry(algo);
 
index d59811c760602fddea2dace336c474464231a8b8..0eae61c44fcec27522b6f6a8d2cb6b40c666f59e 100644 (file)
@@ -135,7 +135,7 @@ void doit(void)
 
        try_with_key_fail("TLS 1.3 with rsa-pss cert and rsa cli cert with only RSA-PSS sig algos",
                        "NORMAL:-VERS-ALL:+VERS-TLS1.3:-SIGN-ALL:+SIGN-RSA-PSS-SHA256:+SIGN-RSA-PSS-SHA384:+SIGN-RSA-PSS-SHA512",
-                       GNUTLS_E_AGAIN, GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY,
+                       GNUTLS_E_CERTIFICATE_REQUIRED, GNUTLS_E_SUCCESS,
                        &server_ca3_rsa_pss_cert, &server_ca3_rsa_pss_key, &cli_ca3_cert, &cli_ca3_key);
 
        try_with_key_fail("TLS 1.3 with rsa encryption cert",