]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
EAP-FAST: echo Session ID on PAC-based session resumption
authorDaniel Kubec <kubec@openssl.foundation>
Thu, 2 Apr 2026 13:25:29 +0000 (14:25 +0100)
committerTomas Mraz <tomas@openssl.foundation>
Thu, 16 Apr 2026 17:00:56 +0000 (19:00 +0200)
Ensure that when a ClientHello includes both a Session ID and a PAC-Opaque
in the SessionTicket extension, the server echoes the same Session ID in
the ServerHello if the session is resumed based on the PAC-Opaque.

Fixes #29095

Signed-off-by: Daniel Kubec <kubec@openssl.foundation>
Co-authored-by: Matt Caswell <matt@openssl.foundation>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
MergeDate: Thu Apr 16 17:01:03 2026
(Merged from https://github.com/openssl/openssl/pull/30695)

ssl/statem/statem_srvr.c
test/sslapitest.c

index 97455842ecbb1e4d7bd8881135f65fd3556d1bd7..f061a47f4b52239f035a7ca52521d8ffa12f33cd 100644 (file)
@@ -2156,6 +2156,19 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s)
             s->peer_ciphers = ciphers;
             s->session->verify_result = X509_V_OK;
 
+            /*
+             * Per RFC 4851, Section 3.2.2:
+             * If the ClientHello contains both a Session ID and a PAC-Opaque in
+             * the SessionTicket extension, and the server resumes the session
+             * using the PAC-Opaque, it should echo the same Session ID in the
+             * ServerHello.
+             */
+            if (clienthello->session_id_len > 0) {
+                memcpy(s->session->session_id, clienthello->session_id,
+                    clienthello->session_id_len);
+                s->session->session_id_length = clienthello->session_id_len;
+            }
+
             ciphers = NULL;
 
             /* check if some cipher was preferred by call back */
index 411d0076812b2791e1e33c64a8d548c3bb500d4e..9e994062d5181189b897e99714e898e3a34831e8 100644 (file)
@@ -11197,11 +11197,13 @@ static int secret_cb(SSL *s, void *secretin, int *secret_len,
 /*
  * Test the session_secret_cb which is designed for use with EAP-FAST
  */
-static int test_session_secret_cb(void)
+static int test_session_secret_cb(int idx)
 {
     SSL_CTX *cctx = NULL, *sctx = NULL;
     SSL *clientssl = NULL, *serverssl = NULL;
-    SSL_SESSION *secret_sess = NULL;
+    SSL_SESSION *secret_sess = NULL, *server_sess = NULL;
+    unsigned int sess_len;
+    const unsigned char *sessid;
     int testresult = 0;
 
     if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(),
@@ -11235,12 +11237,20 @@ static int test_session_secret_cb(void)
             NULL, NULL)))
         goto end;
 
-    /*
-     * No session ids for EAP-FAST - otherwise the state machine gets very
-     * confused.
-     */
-    if (!TEST_true(SSL_SESSION_set1_id(secret_sess, NULL, 0)))
-        goto end;
+    if (idx == 0) {
+        /*
+         * Normal case: no session id
+         */
+        if (!TEST_true(SSL_SESSION_set1_id(secret_sess, NULL, 0)))
+            goto end;
+    } else {
+        /*
+         * Set an explicit session id. Normally we don't support this, but we
+         * can get away with it if we reset the session id later
+         */
+        if (!TEST_true(SSL_SESSION_set1_id(secret_sess, (unsigned char *)"sessionid", 9)))
+            goto end;
+    }
 
     if (!TEST_true(SSL_set_min_proto_version(clientssl, TLS1_2_VERSION))
         || !TEST_true(SSL_set_max_proto_version(serverssl, TLS1_2_VERSION))
@@ -11251,13 +11261,39 @@ static int test_session_secret_cb(void)
         || !TEST_true(SSL_set_session(clientssl, secret_sess)))
         goto end;
 
+    if (idx == 1) {
+        /*
+         * We just send the ClientHello here. We expect this to fail with
+         * SSL_ERROR_WANT_READ
+         */
+        if (!TEST_int_le(SSL_connect(clientssl), 0))
+            goto end;
+        /* Reset the session id to avoid confusing the state machine */
+        if (!TEST_true(SSL_SESSION_set1_id(secret_sess, NULL, 0)))
+            goto end;
+    }
     if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE)))
         goto end;
 
+    /* Check that session resumption was successful */
+    if (!TEST_true(SSL_session_reused(clientssl))
+        || !TEST_true(SSL_session_reused(serverssl)))
+        goto end;
+
+    if (idx == 1) {
+        server_sess = SSL_get1_session(serverssl);
+        if (!TEST_ptr(server_sess))
+            goto end;
+        sessid = SSL_SESSION_get_id(server_sess, &sess_len);
+
+        if (!TEST_mem_eq(sessid, sess_len, "sessionid", 9))
+            goto end;
+    }
     testresult = 1;
 
 end:
     SSL_SESSION_free(secret_sess);
+    SSL_SESSION_free(server_sess);
     SSL_free(serverssl);
     SSL_free(clientssl);
     SSL_CTX_free(sctx);
@@ -14910,7 +14946,7 @@ int setup_tests(void)
 #endif
 #ifndef OPENSSL_NO_TLS1_2
     ADD_TEST(test_ssl_dup);
-    ADD_TEST(test_session_secret_cb);
+    ADD_ALL_TESTS(test_session_secret_cb, 2);
 #ifndef OPENSSL_NO_DH
     ADD_ALL_TESTS(test_set_tmp_dh, 11);
     ADD_ALL_TESTS(test_dh_auto, 7);