Skip to content

Commit 45bd3c3

Browse files
pluknetmattcaswell
authored andcommitted
Preserve connection custom extensions in SSL_set_SSL_CTX()
The SSL_set_SSL_CTX() function is used to switch SSL contexts for the given SSL object. If contexts differ, this includes updating a cert structure with custom extensions from the new context. This however overwrites connection custom extensions previously set on top of inherited from the old context. The fix is to preserve connection custom extensions using a newly introduced flag SSL_EXT_FLAG_CONN in custom_ext_copy_conn(). Similar to custom_ext_copy(), it is a no-op if there are no custom extensions to copy. The only such consumer is ossl_quic_tls_configure() used to set the "quic_transport_parameters" extension. Before this change, context switch resulted in transport parameters not being sent due to the missing extension. Initially reported at nginx/nginx#711 Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from #27706) (cherry picked from commit 403ba31)
1 parent be4e397 commit 45bd3c3

File tree

4 files changed

+86
-3
lines changed

4 files changed

+86
-3
lines changed

ssl/ssl_lib.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5476,6 +5476,8 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx)
54765476
new_cert = ssl_cert_dup(ctx->cert);
54775477
if (new_cert == NULL)
54785478
goto err;
5479+
if (!custom_exts_copy_conn(&new_cert->custext, &sc->cert->custext))
5480+
goto err;
54795481
if (!custom_exts_copy_flags(&new_cert->custext, &sc->cert->custext))
54805482
goto err;
54815483

ssl/ssl_local.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,11 @@ typedef struct {
20672067
* corresponding ServerHello extension.
20682068
*/
20692069
# define SSL_EXT_FLAG_SENT 0x2
2070+
/*
2071+
* Indicates an extension that was set on SSL object and needs to be
2072+
* preserved when switching SSL contexts.
2073+
*/
2074+
# define SSL_EXT_FLAG_CONN 0x4
20702075

20712076
typedef struct {
20722077
custom_ext_method *meths;
@@ -2998,6 +3003,8 @@ __owur int custom_ext_add(SSL_CONNECTION *s, int context, WPACKET *pkt, X509 *x,
29983003

29993004
__owur int custom_exts_copy(custom_ext_methods *dst,
30003005
const custom_ext_methods *src);
3006+
__owur int custom_exts_copy_conn(custom_ext_methods *dst,
3007+
const custom_ext_methods *src);
30013008
__owur int custom_exts_copy_flags(custom_ext_methods *dst,
30023009
const custom_ext_methods *src);
30033010
void custom_exts_free(custom_ext_methods *exts);

ssl/statem/extensions_cust.c

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ void custom_ext_init(custom_ext_methods *exts)
107107
custom_ext_method *meth = exts->meths;
108108

109109
for (i = 0; i < exts->meths_count; i++, meth++)
110-
meth->ext_flags = 0;
110+
meth->ext_flags &= ~(SSL_EXT_FLAG_SENT | SSL_EXT_FLAG_RECEIVED);
111111
}
112112

113113
/* Pass received custom extension data to the application for parsing. */
@@ -330,6 +330,58 @@ int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src)
330330
return 1;
331331
}
332332

333+
/* Copy custom extensions that were set on connection */
334+
int custom_exts_copy_conn(custom_ext_methods *dst,
335+
const custom_ext_methods *src)
336+
{
337+
size_t i;
338+
int err = 0;
339+
340+
if (src->meths_count > 0) {
341+
size_t meths_count = 0;
342+
343+
for (i = 0; i < src->meths_count; i++)
344+
if ((src->meths[i].ext_flags & SSL_EXT_FLAG_CONN) != 0)
345+
meths_count++;
346+
347+
if (meths_count > 0) {
348+
custom_ext_method *methdst =
349+
OPENSSL_realloc(dst->meths,
350+
(dst->meths_count + meths_count) *
351+
sizeof(custom_ext_method));
352+
353+
if (methdst == NULL)
354+
return 0;
355+
356+
for (i = 0; i < dst->meths_count; i++)
357+
custom_ext_copy_old_cb(&methdst[i], &dst->meths[i], &err);
358+
359+
dst->meths = methdst;
360+
methdst += dst->meths_count;
361+
362+
for (i = 0; i < src->meths_count; i++) {
363+
custom_ext_method *methsrc = &src->meths[i];
364+
365+
if ((methsrc->ext_flags & SSL_EXT_FLAG_CONN) == 0)
366+
continue;
367+
368+
memcpy(methdst, methsrc, sizeof(custom_ext_method));
369+
custom_ext_copy_old_cb(methdst, methsrc, &err);
370+
methdst++;
371+
}
372+
373+
dst->meths_count += meths_count;
374+
}
375+
}
376+
377+
if (err) {
378+
custom_exts_free(dst);
379+
return 0;
380+
}
381+
382+
return 1;
383+
}
384+
333385
void custom_exts_free(custom_ext_methods *exts)
334386
{
335387
size_t i;
@@ -417,6 +469,7 @@ int ossl_tls_add_custom_ext_intern(SSL_CTX *ctx, custom_ext_methods *exts,
417469
meth->add_cb = add_cb;
418470
meth->free_cb = free_cb;
419471
meth->ext_type = ext_type;
472+
meth->ext_flags = (ctx == NULL) ? SSL_EXT_FLAG_CONN : 0;
420473
meth->add_arg = add_arg;
421474
meth->parse_arg = parse_arg;
422475
exts->meths_count++;

test/sslapitest.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12866,10 +12866,11 @@ static int alert_cb(SSL *s, unsigned char alert_code, void *arg)
1286612866
* Test 1: Force a failure
1286712867
* Test 3: Use a CCM based ciphersuite
1286812868
* Test 4: fail yield_secret_cb to see double free
12869+
* Test 5: Normal run with SNI
1286912870
*/
1287012871
static int test_quic_tls(int idx)
1287112872
{
12872-
SSL_CTX *sctx = NULL, *cctx = NULL;
12873+
SSL_CTX *sctx = NULL, *sctx2 = NULL, *cctx = NULL;
1287312874
SSL *serverssl = NULL, *clientssl = NULL;
1287412875
int testresult = 0;
1287512876
OSSL_DISPATCH qtdis[] = {
@@ -12897,6 +12898,7 @@ static int test_quic_tls(int idx)
1289712898
if (idx == 4)
1289812899
qtdis[3].function = (void (*)(void))yield_secret_cb_fail;
1289912900

12901+
snicb = 0;
1290012902
memset(secret_history, 0, sizeof(secret_history));
1290112903
secret_history_idx = 0;
1290212904
memset(&sdata, 0, sizeof(sdata));
@@ -12911,6 +12913,18 @@ static int test_quic_tls(int idx)
1291112913
&sctx, &cctx, cert, privkey)))
1291212914
goto end;
1291312915

12916+
if (idx == 5) {
12917+
if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), NULL,
12918+
TLS1_3_VERSION, 0,
12919+
&sctx2, NULL, cert, privkey)))
12920+
goto end;
12921+
12922+
/* Set up SNI */
12923+
if (!TEST_true(SSL_CTX_set_tlsext_servername_callback(sctx, sni_cb))
12924+
|| !TEST_true(SSL_CTX_set_tlsext_servername_arg(sctx, sctx2)))
12925+
goto end;
12926+
}
12927+
1291412928
if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL,
1291512929
NULL)))
1291612930
goto end;
@@ -12951,6 +12965,12 @@ static int test_quic_tls(int idx)
1295112965
goto end;
1295212966
}
1295312967

12968+
/* We should have had the SNI callback called exactly once */
12969+
if (idx == 5) {
12970+
if (!TEST_int_eq(snicb, 1))
12971+
goto end;
12972+
}
12973+
1295412974
/* Check no problems during the handshake */
1295512975
if (!TEST_false(sdata.alert)
1295612976
|| !TEST_false(cdata.alert)
@@ -12992,6 +13012,7 @@ static int test_quic_tls(int idx)
1299213012
end:
1299313013
SSL_free(serverssl);
1299413014
SSL_free(clientssl);
13015+
SSL_CTX_free(sctx2);
1299513016
SSL_CTX_free(sctx);
1299613017
SSL_CTX_free(cctx);
1299713018

@@ -13573,7 +13594,7 @@ int setup_tests(void)
1357313594
#endif
1357413595
ADD_ALL_TESTS(test_alpn, 4);
1357513596
#if !defined(OSSL_NO_USABLE_TLS1_3)
13576-
ADD_ALL_TESTS(test_quic_tls, 5);
13597+
ADD_ALL_TESTS(test_quic_tls, 6);
1357713598
ADD_TEST(test_quic_tls_early_data);
1357813599
#endif
1357913600
ADD_ALL_TESTS(test_no_renegotiation, 2);

0 commit comments

Comments
 (0)