Skip to content

Commit 08f56cf

Browse files
EMS code review feedback:
Check as early in the connection as possible Abort resumption rather than fully aborting connection when EMS is disabled Make version check around haveEMS consistent Clear premaster secret when EMS check fails Update documentation
1 parent 9ade2bb commit 08f56cf

7 files changed

Lines changed: 162 additions & 49 deletions

File tree

doc/dox_comments/header_files/ssl.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17287,8 +17287,10 @@ int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled);
1728717287
\ingroup Setup
1728817288
\brief Disables the TLS Extended Master Secret extension (RFC 7627) on
1728917289
the context: a client stops advertising it and a server ignores the
17290-
peer's request, so a standard master secret is negotiated. TLS 1.2 and
17291-
earlier only. Requires HAVE_EXTENDED_MASTER.
17290+
peer's request, so a standard master secret is negotiated. A server also
17291+
declines resumption of sessions or tickets that used EMS and does a full
17292+
handshake instead. TLS 1.2 and earlier only. Requires
17293+
HAVE_EXTENDED_MASTER.
1729217294

1729317295
\return WOLFSSL_SUCCESS on success.
1729417296
\return BAD_FUNC_ARG if ctx is NULL.
@@ -17311,8 +17313,10 @@ int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx);
1731117313
\ingroup Setup
1731217314
\brief Disables the TLS Extended Master Secret extension (RFC 7627) on
1731317315
the SSL object: a client stops advertising it and a server ignores the
17314-
peer's request, so a standard master secret is negotiated. TLS 1.2 and
17315-
earlier only. Requires HAVE_EXTENDED_MASTER.
17316+
peer's request, so a standard master secret is negotiated. A server also
17317+
declines resumption of sessions or tickets that used EMS and does a full
17318+
handshake instead. TLS 1.2 and earlier only. Requires
17319+
HAVE_EXTENDED_MASTER.
1731617320

1731717321
\return WOLFSSL_SUCCESS on success.
1731817322
\return BAD_FUNC_ARG if ssl is NULL.
@@ -17382,7 +17386,8 @@ int wolfSSL_EnableExtendedMasterSecret(WOLFSSL* ssl);
1738217386
\brief Makes the TLS Extended Master Secret extension (RFC 7627)
1738317387
mandatory on the context: if it is not negotiated, the connection
1738417388
is aborted with EXT_MASTER_SECRET_NEEDED_E. A client advertises
17385-
the extension even after a previous disable. TLS 1.2 and earlier
17389+
the extension even after a previous disable. Sessions using a
17390+
session-secret callback (EAP-FAST) are exempt. TLS 1.2 and earlier
1738617391
only. Requires HAVE_EXTENDED_MASTER.
1738717392

1738817393
\return WOLFSSL_SUCCESS on success.
@@ -17407,8 +17412,9 @@ int wolfSSL_CTX_RequireExtendedMasterSecret(WOLFSSL_CTX* ctx);
1740717412
\brief Makes the TLS Extended Master Secret extension (RFC 7627)
1740817413
mandatory on the SSL object: if it is not negotiated, including on
1740917414
resumption, the connection is aborted with EXT_MASTER_SECRET_NEEDED_E. A
17410-
client advertises the extension even after a previous disable. TLS 1.2
17411-
and earlier only. Requires HAVE_EXTENDED_MASTER.
17415+
client advertises the extension even after a previous disable. Sessions
17416+
using a session-secret callback (EAP-FAST) are exempt. TLS 1.2 and
17417+
earlier only. Requires HAVE_EXTENDED_MASTER.
1741217418

1741317419
\return WOLFSSL_SUCCESS on success.
1741417420
\return BAD_FUNC_ARG if ssl is NULL.

src/internal.c

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24554,15 +24554,6 @@ static int CheckResumptionConsistency(WOLFSSL* ssl)
2455424554
WOLFSSL_ERROR_VERBOSE(EXT_MASTER_SECRET_NEEDED_E);
2455524555
return EXT_MASTER_SECRET_NEEDED_E;
2455624556
}
24557-
#ifdef HAVE_EXTENDED_MASTER
24558-
/* Resumption skips MakeMasterSecret, so enforce required EMS here. */
24559-
if (!skipEmsCheck && ssl->options.requireEMS && !ssl->options.haveEMS) {
24560-
WOLFSSL_MSG("EMS required but not negotiated with peer");
24561-
SendAlert(ssl, alert_fatal, handshake_failure);
24562-
WOLFSSL_ERROR_VERBOSE(EXT_MASTER_SECRET_NEEDED_E);
24563-
return EXT_MASTER_SECRET_NEEDED_E;
24564-
}
24565-
#endif /* HAVE_EXTENDED_MASTER */
2456624557
#ifndef NO_RESUME_SUITE_CHECK
2456724558
/* Suite must match (RFC 5246 7.4.1.3), tickets included. Skip when no suite
2456824559
* was retained (both zero = TLS_NULL_WITH_NULL_NULL, e.g. EAP-FAST PAC). */
@@ -34553,6 +34544,31 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
3455334544
}
3455434545
#endif /* HAVE_TLS_EXTENSIONS */
3455534546

34547+
#ifdef HAVE_EXTENDED_MASTER
34548+
/* The negotiated EMS state is final once the ServerHello extensions
34549+
* are parsed: abort a requiring client here, before any key material
34550+
* is computed or sent. */
34551+
if (ssl->options.requireEMS && !ssl->options.haveEMS) {
34552+
byte skipEmsCheck = 0;
34553+
#ifdef HAVE_SECRET_CALLBACK
34554+
/* Skip for EAP-FAST (session-secret callback): the master secret
34555+
* comes from the callback. */
34556+
skipEmsCheck = (ssl->sessionSecretCb != NULL
34557+
#ifdef HAVE_SESSION_TICKET
34558+
&& ssl->session != NULL
34559+
&& ssl->session->ticketLen > 0
34560+
#endif
34561+
) ? 1 : 0;
34562+
#endif
34563+
if (!skipEmsCheck) {
34564+
WOLFSSL_MSG("EMS required but not negotiated with peer");
34565+
SendAlert(ssl, alert_fatal, handshake_failure);
34566+
WOLFSSL_ERROR_VERBOSE(EXT_MASTER_SECRET_NEEDED_E);
34567+
return EXT_MASTER_SECRET_NEEDED_E;
34568+
}
34569+
}
34570+
#endif /* HAVE_EXTENDED_MASTER */
34571+
3455634572
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
3455734573
defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
3455834574
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
@@ -40665,7 +40681,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
4066540681
#endif /* !WOLFSSL_NO_TICKET_EXPIRE && !NO_ASN_TIME */
4066640682

4066740683
if (!ssl->options.resuming) {
40668-
/* Expired above: DoClientHello falls back to a full handshake. */
40684+
/* Resumption abandoned: DoClientHello runs a full handshake. */
4066940685
return ret;
4067040686
}
4067140687

@@ -40680,13 +40696,25 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
4068040696
}
4068140697
/* if old sess used EMS, but new doesn't, MUST abort */
4068240698
else if (session->haveEMS && !ssl->options.haveEMS) {
40683-
WOLFSSL_MSG("Trying to resume a session with EMS without "
40684-
"using EMS");
40685-
#ifdef WOLFSSL_EXTRA_ALERTS
40686-
SendAlert(ssl, alert_fatal, handshake_failure);
40687-
#endif
40688-
ret = EXT_MASTER_SECRET_NEEDED_E;
40689-
WOLFSSL_ERROR_VERBOSE(ret);
40699+
#ifdef HAVE_EXTENDED_MASTER
40700+
if (ssl->options.disableEMS) {
40701+
/* Local disable, not a client downgrade: decline the
40702+
* resumption and do a full handshake. */
40703+
WOLFSSL_MSG("EMS disabled locally, declining resumption "
40704+
"of an EMS session. Do full handshake.");
40705+
ssl->options.resuming = 0;
40706+
}
40707+
else
40708+
#endif
40709+
{
40710+
WOLFSSL_MSG("Trying to resume a session with EMS without "
40711+
"using EMS");
40712+
#ifdef WOLFSSL_EXTRA_ALERTS
40713+
SendAlert(ssl, alert_fatal, handshake_failure);
40714+
#endif
40715+
ret = EXT_MASTER_SECRET_NEEDED_E;
40716+
WOLFSSL_ERROR_VERBOSE(ret);
40717+
}
4069040718
}
4069140719
}
4069240720
else {

src/keys.c

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3935,6 +3935,28 @@ int StoreKeys(WOLFSSL* ssl, const byte* keyData, int side)
39353935
return 0;
39363936
}
39373937

3938+
#if !defined(NO_OLD_TLS) || defined(HAVE_EXTENDED_MASTER)
3939+
static void CleanPreMaster(WOLFSSL* ssl)
3940+
{
3941+
int sz = (int)(ssl->arrays->preMasterSz);
3942+
3943+
#ifdef WOLFSSL_CHECK_MEM_ZERO
3944+
wc_MemZero_Add("CleanPreMaster preMasterSecret",
3945+
ssl->arrays->preMasterSecret, sz);
3946+
#endif
3947+
3948+
ForceZero(ssl->arrays->preMasterSecret, sz);
3949+
3950+
#ifdef WOLFSSL_CHECK_MEM_ZERO
3951+
wc_MemZero_Check(ssl->arrays->preMasterSecret, sz);
3952+
#endif
3953+
3954+
XFREE(ssl->arrays->preMasterSecret, ssl->heap, DYNAMIC_TYPE_SECRET);
3955+
ssl->arrays->preMasterSecret = NULL;
3956+
ssl->arrays->preMasterSz = 0;
3957+
}
3958+
#endif /* !NO_OLD_TLS || HAVE_EXTENDED_MASTER */
3959+
39383960
#ifndef NO_OLD_TLS
39393961
int DeriveKeys(WOLFSSL* ssl)
39403962
{
@@ -4062,27 +4084,6 @@ int DeriveKeys(WOLFSSL* ssl)
40624084
}
40634085

40644086

4065-
static void CleanPreMaster(WOLFSSL* ssl)
4066-
{
4067-
int sz = (int)(ssl->arrays->preMasterSz);
4068-
4069-
#ifdef WOLFSSL_CHECK_MEM_ZERO
4070-
wc_MemZero_Add("CleanPreMaster preMasterSecret",
4071-
ssl->arrays->preMasterSecret, sz);
4072-
#endif
4073-
4074-
ForceZero(ssl->arrays->preMasterSecret, sz);
4075-
4076-
#ifdef WOLFSSL_CHECK_MEM_ZERO
4077-
wc_MemZero_Check(ssl->arrays->preMasterSecret, sz);
4078-
#endif
4079-
4080-
XFREE(ssl->arrays->preMasterSecret, ssl->heap, DYNAMIC_TYPE_SECRET);
4081-
ssl->arrays->preMasterSecret = NULL;
4082-
ssl->arrays->preMasterSz = 0;
4083-
}
4084-
4085-
40864087
/* Create and store the master secret see page 32, 6.1 */
40874088
static int MakeSslMasterSecret(WOLFSSL* ssl)
40884089
{
@@ -4238,6 +4239,8 @@ int MakeMasterSecret(WOLFSSL* ssl)
42384239
WOLFSSL_MSG("EMS required but not negotiated with peer");
42394240
SendAlert(ssl, alert_fatal, handshake_failure);
42404241
WOLFSSL_ERROR_VERBOSE(EXT_MASTER_SECRET_NEEDED_E);
4242+
if (ssl->arrays->preMasterSecret != NULL)
4243+
CleanPreMaster(ssl);
42414244
return EXT_MASTER_SECRET_NEEDED_E;
42424245
}
42434246
#endif

src/ssl_api_ext.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,23 @@ int wolfSSL_set_SessionTicket_cb(WOLFSSL* ssl,
15631563

15641564
#ifdef HAVE_EXTENDED_MASTER
15651565

1566+
/* EMS applies to (D)TLS 1.0-1.2 only; the same version gate is applied by
1567+
* InitSSL_Ctx and InitSSL_Side when arming the default advertisement. */
1568+
static int EmsAllowedForVersion(ProtocolVersion pv)
1569+
{
1570+
int allowed = 0;
1571+
1572+
if (pv.major == SSLv3_MAJOR && pv.minor >= TLSv1_MINOR)
1573+
allowed = 1;
1574+
#ifdef WOLFSSL_DTLS
1575+
if (pv.major == DTLS_MAJOR)
1576+
allowed = 1;
1577+
#endif
1578+
1579+
return allowed;
1580+
}
1581+
1582+
15661583
/* Disable the Extended Master Secret extension on the context.
15671584
*
15681585
* For a client this stops the extension being advertised. For a server this
@@ -1641,7 +1658,8 @@ int wolfSSL_CTX_EnableExtendedMasterSecret(WOLFSSL_CTX* ctx)
16411658
/* Re-arm client advertising. A side-less (wolfSSLv23) object is
16421659
* armed by InitSSL_Side instead; arming it here would make a server
16431660
* echo an unsolicited extension. */
1644-
if (ctx->method != NULL && ctx->method->side == WOLFSSL_CLIENT_END)
1661+
if (ctx->method != NULL && ctx->method->side == WOLFSSL_CLIENT_END &&
1662+
EmsAllowedForVersion(ctx->method->version))
16451663
ctx->haveEMS = 1;
16461664
}
16471665

@@ -1671,7 +1689,8 @@ int wolfSSL_EnableExtendedMasterSecret(WOLFSSL* ssl)
16711689
/* Re-arm client advertising. A side-less (wolfSSLv23) object is
16721690
* armed by InitSSL_Side instead; arming it here would make a server
16731691
* echo an unsolicited extension. */
1674-
if (ssl->options.side == WOLFSSL_CLIENT_END)
1692+
if (ssl->options.side == WOLFSSL_CLIENT_END &&
1693+
EmsAllowedForVersion(ssl->ctx->method->version))
16751694
ssl->options.haveEMS = 1;
16761695
}
16771696

@@ -1705,7 +1724,8 @@ int wolfSSL_CTX_RequireExtendedMasterSecret(WOLFSSL_CTX* ctx)
17051724
/* Re-arm client advertising. A side-less (wolfSSLv23) object is
17061725
* armed by InitSSL_Side instead; arming it here would make a server
17071726
* echo an unsolicited extension. */
1708-
if (ctx->method != NULL && ctx->method->side == WOLFSSL_CLIENT_END)
1727+
if (ctx->method != NULL && ctx->method->side == WOLFSSL_CLIENT_END &&
1728+
EmsAllowedForVersion(ctx->method->version))
17091729
ctx->haveEMS = 1;
17101730
}
17111731

@@ -1737,7 +1757,8 @@ int wolfSSL_RequireExtendedMasterSecret(WOLFSSL* ssl)
17371757
/* Re-arm client advertising. A side-less (wolfSSLv23) object is
17381758
* armed by InitSSL_Side instead; arming it here would make a server
17391759
* echo an unsolicited extension. */
1740-
if (ssl->options.side == WOLFSSL_CLIENT_END)
1760+
if (ssl->options.side == WOLFSSL_CLIENT_END &&
1761+
EmsAllowedForVersion(ssl->ctx->method->version))
17411762
ssl->options.haveEMS = 1;
17421763
}
17431764

tests/api.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39474,6 +39474,7 @@ TEST_CASE testCases[] = {
3947439474
TEST_DECL(test_tls_ems_resumption_downgrade),
3947539475
TEST_DECL(test_tls_ems_resumption_server_downgrade),
3947639476
TEST_DECL(test_tls_ems_server_disable),
39477+
TEST_DECL(test_tls_ems_server_disable_resumption),
3947739478
TEST_DECL(test_tls_ems_disable_v23),
3947839479
TEST_DECL(test_tls_require_ems),
3947939480
TEST_DECL(test_tls_require_ems_resumption),

tests/api/test_tls_ext.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,59 @@ int test_tls_ems_server_disable(void)
352352
}
353353

354354

355+
/* A server that disables EMS declines resumption of a session that used EMS
356+
* from an EMS-offering client: full handshake instead of a fatal alert. */
357+
int test_tls_ems_server_disable_resumption(void)
358+
{
359+
EXPECT_DECLS;
360+
#if !defined(WOLFSSL_NO_TLS12) && defined(HAVE_EXTENDED_MASTER) && \
361+
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
362+
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
363+
!defined(NO_SESSION_CACHE)
364+
struct test_memio_ctx test_ctx;
365+
WOLFSSL_CTX *ctx_c = NULL;
366+
WOLFSSL_CTX *ctx_s = NULL;
367+
WOLFSSL *ssl_c = NULL;
368+
WOLFSSL *ssl_s = NULL;
369+
WOLFSSL_SESSION *session = NULL;
370+
371+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
372+
373+
/* Establish a session that uses EMS. */
374+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
375+
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
376+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
377+
ExpectNotNull(session = wolfSSL_get1_session(ssl_c));
378+
ExpectTrue(session->haveEMS);
379+
380+
wolfSSL_free(ssl_c);
381+
ssl_c = NULL;
382+
wolfSSL_free(ssl_s);
383+
ssl_s = NULL;
384+
test_memio_clear_buffer(&test_ctx, 0);
385+
test_memio_clear_buffer(&test_ctx, 1);
386+
387+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
388+
wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
389+
ExpectIntEQ(wolfSSL_DisableExtendedMasterSecret(ssl_s), WOLFSSL_SUCCESS);
390+
ExpectIntEQ(wolfSSL_set_session(ssl_c, session), WOLFSSL_SUCCESS);
391+
392+
/* The handshake must complete as a full handshake without EMS. */
393+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
394+
ExpectIntEQ(ssl_s->options.resuming, 0);
395+
ExpectIntEQ(ssl_c->options.haveEMS, 0);
396+
ExpectIntEQ(ssl_s->options.haveEMS, 0);
397+
398+
wolfSSL_SESSION_free(session);
399+
wolfSSL_free(ssl_c);
400+
wolfSSL_free(ssl_s);
401+
wolfSSL_CTX_free(ctx_c);
402+
wolfSSL_CTX_free(ctx_s);
403+
#endif
404+
return EXPECT_RESULT();
405+
}
406+
407+
355408
#if !defined(WOLFSSL_NO_TLS12) && defined(HAVE_EXTENDED_MASTER) && \
356409
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER) && \
357410
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES)

tests/api/test_tls_ext.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ int test_tls_ems_downgrade(void);
2626
int test_tls_ems_resumption_downgrade(void);
2727
int test_tls_ems_resumption_server_downgrade(void);
2828
int test_tls_ems_server_disable(void);
29+
int test_tls_ems_server_disable_resumption(void);
2930
int test_tls_ems_disable_v23(void);
3031
int test_tls_require_ems(void);
3132
int test_tls_require_ems_resumption(void);

0 commit comments

Comments
 (0)