new_cert = ssl_cert_dup(ctx->cert);
if (new_cert == NULL)
goto err;
+ if (!custom_exts_copy_conn(&new_cert->custext, &sc->cert->custext))
+ goto err;
if (!custom_exts_copy_flags(&new_cert->custext, &sc->cert->custext))
goto err;
* corresponding ServerHello extension.
*/
# define SSL_EXT_FLAG_SENT 0x2
+/*
+ * Indicates an extension that was set on SSL object and needs to be
+ * preserved when switching SSL contexts.
+ */
+# define SSL_EXT_FLAG_CONN 0x4
typedef struct {
custom_ext_method *meths;
__owur int custom_exts_copy(custom_ext_methods *dst,
const custom_ext_methods *src);
+__owur int custom_exts_copy_conn(custom_ext_methods *dst,
+ const custom_ext_methods *src);
__owur int custom_exts_copy_flags(custom_ext_methods *dst,
const custom_ext_methods *src);
void custom_exts_free(custom_ext_methods *exts);
custom_ext_method *meth = exts->meths;
for (i = 0; i < exts->meths_count; i++, meth++)
- meth->ext_flags = 0;
+ meth->ext_flags &= ~(SSL_EXT_FLAG_SENT | SSL_EXT_FLAG_RECEIVED);
}
/* Pass received custom extension data to the application for parsing. */
return 1;
}
+/* Copy custom extensions that were set on connection */
+int custom_exts_copy_conn(custom_ext_methods *dst,
+ const custom_ext_methods *src)
+{
+ size_t i;
+ int err = 0;
+
+ if (src->meths_count > 0) {
+ size_t meths_count = 0;
+
+ for (i = 0; i < src->meths_count; i++)
+ if ((src->meths[i].ext_flags & SSL_EXT_FLAG_CONN) != 0)
+ meths_count++;
+
+ if (meths_count > 0) {
+ custom_ext_method *methdst =
+ OPENSSL_realloc(dst->meths,
+ (dst->meths_count + meths_count) *
+ sizeof(custom_ext_method));
+
+ if (methdst == NULL)
+ return 0;
+
+ for (i = 0; i < dst->meths_count; i++)
+ custom_ext_copy_old_cb(&methdst[i], &dst->meths[i], &err);
+
+ dst->meths = methdst;
+ methdst += dst->meths_count;
+
+ for (i = 0; i < src->meths_count; i++) {
+ custom_ext_method *methsrc = &src->meths[i];
+
+ if ((methsrc->ext_flags & SSL_EXT_FLAG_CONN) == 0)
+ continue;
+
+ memcpy(methdst, methsrc, sizeof(custom_ext_method));
+ custom_ext_copy_old_cb(methdst, methsrc, &err);
+ methdst++;
+ }
+
+ dst->meths_count += meths_count;
+ }
+ }
+
+ if (err) {
+ custom_exts_free(dst);
+ return 0;
+ }
+
+ return 1;
+}
+
void custom_exts_free(custom_ext_methods *exts)
{
size_t i;
meth->add_cb = add_cb;
meth->free_cb = free_cb;
meth->ext_type = ext_type;
+ meth->ext_flags = (ctx == NULL) ? SSL_EXT_FLAG_CONN : 0;
meth->add_arg = add_arg;
meth->parse_arg = parse_arg;
exts->meths_count++;
* Test 1: Force a failure
* Test 3: Use a CCM based ciphersuite
* Test 4: fail yield_secret_cb to see double free
+ * Test 5: Normal run with SNI
*/
static int test_quic_tls(int idx)
{
- SSL_CTX *sctx = NULL, *cctx = NULL;
+ SSL_CTX *sctx = NULL, *sctx2 = NULL, *cctx = NULL;
SSL *serverssl = NULL, *clientssl = NULL;
int testresult = 0;
OSSL_DISPATCH qtdis[] = {
if (idx == 4)
qtdis[3].function = (void (*)(void))yield_secret_cb_fail;
+ snicb = 0;
memset(secret_history, 0, sizeof(secret_history));
secret_history_idx = 0;
memset(&sdata, 0, sizeof(sdata));
&sctx, &cctx, cert, privkey)))
goto end;
+ if (idx == 5) {
+ if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), NULL,
+ TLS1_3_VERSION, 0,
+ &sctx2, NULL, cert, privkey)))
+ goto end;
+
+ /* Set up SNI */
+ if (!TEST_true(SSL_CTX_set_tlsext_servername_callback(sctx, sni_cb))
+ || !TEST_true(SSL_CTX_set_tlsext_servername_arg(sctx, sctx2)))
+ goto end;
+ }
+
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL,
NULL)))
goto end;
goto end;
}
+ /* We should have had the SNI callback called exactly once */
+ if (idx == 5) {
+ if (!TEST_int_eq(snicb, 1))
+ goto end;
+ }
+
/* Check no problems during the handshake */
if (!TEST_false(sdata.alert)
|| !TEST_false(cdata.alert)
end:
SSL_free(serverssl);
SSL_free(clientssl);
+ SSL_CTX_free(sctx2);
SSL_CTX_free(sctx);
SSL_CTX_free(cctx);
#endif
ADD_ALL_TESTS(test_alpn, 4);
#if !defined(OSSL_NO_USABLE_TLS1_3)
- ADD_ALL_TESTS(test_quic_tls, 5);
+ ADD_ALL_TESTS(test_quic_tls, 6);
ADD_TEST(test_quic_tls_early_data);
#endif
ADD_ALL_TESTS(test_no_renegotiation, 2);