1 /* 2 * Copyright 2026 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include <openssl/ssl.h> 11 #include "helpers/ssltestlib.h" 12 #include "testutil.h" 13 14 struct stats { 15 unsigned int tickets; 16 }; 17 18 static char *cert = NULL; 19 static char *pkey = NULL; 20 static int stats_idx = -1; 21 22 static int stats_init(struct stats *stats) 23 { 24 memset(stats, 0, sizeof(*stats)); 25 return 1; 26 } 27 28 static int sess_new_cb(SSL *ssl, SSL_SESSION *session) 29 { 30 struct stats *stats = SSL_get_ex_data(ssl, stats_idx); 31 if (stats == NULL) 32 return 0; 33 if (SSL_is_init_finished(ssl) == 0) 34 stats->tickets++; 35 return 0; 36 } 37 38 static void handshake_finished(const SSL *ssl) 39 { 40 const char *endpoint = SSL_is_server(ssl) ? "server" : "client"; 41 if (SSL_session_reused(ssl)) 42 TEST_info("%s: Abbreviated handshake finished", endpoint); 43 else 44 TEST_info("%s: Full handshake finished", endpoint); 45 } 46 47 static void info_cb(const SSL *ssl, int type, int val) 48 { 49 const char *endpoint = SSL_is_server(ssl) ? "server" : "client"; 50 51 if (type & SSL_CB_ALERT) { 52 const char *dir = (type & SSL_CB_READ) ? "read" : "write"; 53 54 TEST_info("%s: alert %s: %s : %s", endpoint, dir, 55 SSL_alert_type_string_long(val), 56 SSL_alert_desc_string_long(val)); 57 } 58 if (type & SSL_CB_HANDSHAKE_DONE) 59 handshake_finished(ssl); 60 } 61 62 static int set_callbacks(SSL *ssl) 63 { 64 SSL_set_info_callback(ssl, info_cb); 65 return 1; 66 } 67 68 static int set_shutdown(SSL *c, SSL *s) 69 { 70 SSL_set_shutdown(c, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 71 SSL_set_shutdown(s, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); 72 return 1; 73 } 74 75 static int enable_tickets(SSL_CTX *s, SSL_CTX *c) 76 { 77 unsigned int cf = SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE; 78 unsigned int sf = SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_INTERNAL_STORE; 79 80 SSL_CTX_set_session_cache_mode(s, sf); 81 SSL_CTX_set_session_cache_mode(c, cf); 82 SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL); 83 84 SSL_CTX_sess_set_new_cb(s, sess_new_cb); 85 SSL_CTX_sess_set_new_cb(c, sess_new_cb); 86 87 return 1; 88 } 89 90 /* 91 * Verify ticket regeneration after fallback to a full handshake. If session 92 * resumption fails due to a ciphersuite mismatch, it falls back to a full 93 * handshake. In that case, ensure a new session ticket is issued reflecting the 94 * negotiated ciphersuite. 95 */ 96 static int test_tls13_ticket_ciphersuite_mismatch(void) 97 { 98 struct stats stats1, stats2; 99 SSL_CTX *s_ctx = NULL, *c_ctx = NULL; 100 SSL *s_ssl = NULL, *c_ssl = NULL, *s = NULL, *c = NULL; 101 SSL_SESSION *sess = NULL; 102 int test; 103 104 test = create_ssl_ctx_pair(NULL, TLS_server_method(), TLS_client_method(), 105 TLS1_3_VERSION, TLS1_3_VERSION, &s_ctx, &c_ctx, cert, pkey) 106 && TEST_true(SSL_CTX_set_ciphersuites(s_ctx, "TLS_AES_128_GCM_SHA256")) 107 && TEST_true(SSL_CTX_set_ciphersuites(c_ctx, "TLS_AES_128_GCM_SHA256")) 108 && TEST_true(enable_tickets(s_ctx, c_ctx)) 109 && TEST_true(create_ssl_objects(s_ctx, c_ctx, &s, &c, NULL, NULL)) 110 && TEST_true(set_callbacks(c)) 111 && TEST_true(set_callbacks(s)) 112 && TEST_true(stats_init(&stats1)) 113 && TEST_true(SSL_set_ex_data(c, stats_idx, &stats1)) 114 && TEST_true(create_ssl_connection(s, c, SSL_ERROR_NONE)) 115 && TEST_uint_eq(stats1.tickets, 2) 116 && TEST_true(set_shutdown(c, s)) 117 && TEST_ptr(sess = SSL_get1_session(c)) 118 && TEST_true(SSL_CTX_set_ciphersuites(s_ctx, "TLS_AES_256_GCM_SHA384")) 119 && TEST_true(SSL_CTX_set_ciphersuites(c_ctx, "TLS_AES_256_GCM_SHA384")) 120 && TEST_true(create_ssl_objects(s_ctx, c_ctx, &s_ssl, &c_ssl, NULL, NULL)) 121 && TEST_true(SSL_set_session(c_ssl, sess)) 122 && TEST_true(set_callbacks(c_ssl)) 123 && TEST_true(set_callbacks(s_ssl)) 124 && TEST_true(stats_init(&stats2)) 125 && TEST_true(SSL_set_ex_data(c_ssl, stats_idx, &stats2)) 126 && TEST_true(create_ssl_connection(s_ssl, c_ssl, SSL_ERROR_NONE)) 127 && TEST_false(SSL_session_reused(c_ssl)) 128 && TEST_uint_eq(stats2.tickets, 2); 129 130 SSL_SESSION_free(sess); 131 SSL_free(s_ssl); 132 SSL_free(c_ssl); 133 SSL_free(s); 134 SSL_free(c); 135 SSL_CTX_free(s_ctx); 136 SSL_CTX_free(c_ctx); 137 return test; 138 } 139 140 OPT_TEST_DECLARE_USAGE("\n") 141 142 int setup_tests(void) 143 { 144 if (!test_skip_common_options()) { 145 TEST_error("Error parsing test options\n"); 146 return 0; 147 } 148 149 if (!TEST_ptr(cert = test_get_argument(0)) 150 || !TEST_ptr(pkey = test_get_argument(1))) 151 return 0; 152 153 stats_idx = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 154 ADD_TEST(test_tls13_ticket_ciphersuite_mismatch); 155 156 return 1; 157 } 158