]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
ext/supported_versions: regenerate server random
authorDaiki Ueno <dueno@redhat.com>
Sat, 9 Feb 2019 09:26:56 +0000 (10:26 +0100)
committerDaiki Ueno <dueno@redhat.com>
Fri, 22 Feb 2019 09:52:26 +0000 (10:52 +0100)
This adds a call to _gnutls_gen_server_random() in handling the
"supported_versions" extension, so that the TLS 1.3 downgrade sentinel
is set only when the earlier versions are selected.

Signed-off-by: Daiki Ueno <dueno@redhat.com>
NEWS
lib/ext/supported_versions.c
tests/tls13/rnd-check-rollback-val.c

diff --git a/NEWS b/NEWS
index b171ef71e81212478188d206c2896df1c3071015..83d9b321a76613628f74e4aaa9a67303b22993b9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,11 @@ See the end for copying conditions.
    a certificate. We were already enforcing the signature algorithm, but there
    was a bug in parameter checking code.
 
+** libgnutls: no longer send downgrade sentinel in TLS 1.3.
+   Previously the sentinel value was embedded to early in version
+   negotiation and was sent even on TLS 1.3. It is now sent only when
+   TLS 1.2 or earlier is negotiated (#689).
+
 ** API and ABI modifications:
 No changes since last version.
 
index b7fe31f75bc2cdd99462e10318714300e751a777..b016c61c3c811d5545607fb0cf6b54bb67700313 100644 (file)
@@ -63,7 +63,10 @@ supported_versions_recv_params(gnutls_session_t session,
        int ret;
 
        if (session->security_parameters.entity == GNUTLS_SERVER) {
+               const version_entry_st *old_vers;
+
                vers = _gnutls_version_max(session);
+               old_vers = get_version(session);
 
                /* do not parse this extension when we haven't TLS1.3
                 * enabled. That is because we cannot handle earlier protocol
@@ -97,6 +100,18 @@ supported_versions_recv_params(gnutls_session_t session,
 
                                _gnutls_handshake_log("EXT[%p]: Negotiated version: %d.%d\n",
                                                      session, (int)major, (int)minor);
+
+                               vers = get_version(session);
+                               if (old_vers != vers) {
+                                       /* regenerate the random value to set
+                                        * downgrade sentinel if necessary
+                                        */
+                                       ret = _gnutls_gen_server_random(session,
+                                                                       vers->id);
+                                       if (ret < 0)
+                                               return gnutls_assert_val(ret);
+                               }
+
                                return 0;
                        }
                }
index f573596c5e1646b38f6dfb3cb595833985578d5f..6b7adafcb5a594c41d4c2f4ef22952e3b13bf40f 100644 (file)
@@ -89,6 +89,8 @@ static void client(int fd)
        gnutls_certificate_credentials_t x509_cred;
        gnutls_session_t session;
        gnutls_datum_t srandom;
+       unsigned try = 0;
+       gnutls_datum_t session_data = { NULL, 0 };
 
        global_init();
 
@@ -102,6 +104,7 @@ static void client(int fd)
                                            &cli_ca3_key,
                                            GNUTLS_X509_FMT_PEM);
 
+ retry:
        /* Initialize TLS session
         */
        gnutls_init(&session, GNUTLS_CLIENT);
@@ -112,6 +115,9 @@ static void client(int fd)
        if (ret < 0)
                fail("cannot set TLS priorities\n");
 
+       if (try > 0)
+               gnutls_session_set_data(session, session_data.data, session_data.size);
+
        /* put the anonymous credentials to the current session
         */
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
@@ -129,6 +135,9 @@ static void client(int fd)
                fail("error in handshake: %s\n", gnutls_strerror(ret));
        }
 
+       if (try > 0)
+               assert(gnutls_session_is_resumed(session));
+
        gnutls_session_get_random(session, NULL, &srandom);
 
        if (srandom.size != 32)
@@ -147,10 +156,28 @@ static void client(int fd)
                fail("unexpected random data for %s\n", name);
        }
 
-       close(fd);
+       do {
+               ret = gnutls_record_send(session, "\x00", 1);
+       } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+
+       if (try == 0) {
+               ret = gnutls_session_get_data2(session, &session_data);
+               if (ret < 0)
+                       fail("couldn't retrieve session data: %s\n",
+                            gnutls_strerror(ret));
+       }
 
        gnutls_deinit(session);
 
+       if (try == 0) {
+               try++;
+               goto retry;
+       }
+
+       close(fd);
+
+       gnutls_free(session_data.data);
+
        gnutls_certificate_free_credentials(x509_cred);
 
        gnutls_global_deinit();
@@ -162,6 +189,9 @@ static void server(int fd)
        int ret;
        gnutls_session_t session;
        gnutls_certificate_credentials_t x509_cred;
+       gnutls_datum_t skey;
+       unsigned try = 0;
+       unsigned char buf[16];
 
        /* this must be called once in the program
         */
@@ -177,6 +207,9 @@ static void server(int fd)
                                            &server_key,
                                            GNUTLS_X509_FMT_PEM);
 
+       assert(gnutls_session_ticket_key_generate(&skey) >= 0);
+
+ retry:
        gnutls_init(&session, GNUTLS_SERVER);
 
        gnutls_handshake_set_timeout(session, 20 * 1000);
@@ -185,6 +218,8 @@ static void server(int fd)
 
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);
 
+       assert(gnutls_session_ticket_enable_server(session, &skey) >= 0);
+
        gnutls_transport_set_int(session, fd);
 
        do {
@@ -197,9 +232,26 @@ static void server(int fd)
        if (ret < 0)
                fail("error in handshake: %s\n", gnutls_strerror(ret));
 
-       close(fd);
+       if (try > 0)
+               assert(gnutls_session_is_resumed(session));
+
+       do {
+               ret = gnutls_record_recv(session, buf, sizeof(buf));
+       } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+
+       if (ret < 0)
+               fail("server: recv did not succeed as expected: %s\n", gnutls_strerror(ret));
+
        gnutls_deinit(session);
 
+       if (try == 0) {
+               try++;
+               goto retry;
+       }
+
+       close(fd);
+
+       gnutls_free(skey.data);
        gnutls_certificate_free_credentials(x509_cred);
 
        gnutls_global_deinit();