Commit 004e9255e4 for openssl.org
commit 004e9255e4e70454c9e9f46dad181d4c6a20c294
Author: Daniel Kubec <kubec@openssl.foundation>
Date: Thu Apr 2 14:25:29 2026 +0100
EAP-FAST: echo Session ID on PAC-based session resumption
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)
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 97455842ec..f061a47f4b 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -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 */
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 411d007681..9e994062d5 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -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);