Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/configs/os-check-linux.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
{"name": "all-faultharden-pk-privkey", "minutes": 7.8,
"comment": "Test holding private key in the PK callback with fault harden. Based on existing customer use case.",
"configure": ["--enable-all", "--enable-faultharden", "--enable-pkcallbacks", "CPPFLAGS=-DTEST_PK_PRIVKEY"]},
{"name": "all-no-ticket-expire", "minutes": 7.8,
"comment": "Nothing else in CI compiles WOLFSSL_NO_TICKET_EXPIRE; it removes the session expiry check that heads the resumption control flow in HandleTlsResumption.",
"configure": ["--enable-all", "CPPFLAGS=-DWOLFSSL_NO_TICKET_EXPIRE"]},
{"name": "all-secure-renegotiation", "minutes": 7.8,
"configure": ["--enable-all", "--enable-secure-renegotiation"]},
{"name": "all-debug-certs", "minutes": 7.8,
Expand Down
149 changes: 149 additions & 0 deletions doc/dox_comments/header_files/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17372,3 +17372,152 @@ int wolfSSL_get_scr_check_enabled(const WOLFSSL* ssl);
\sa wolfSSL_get_scr_check_enabled
*/
int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled);

/*!
\ingroup Setup
\brief Disables the TLS Extended Master Secret extension (RFC 7627) on
the context: a client stops advertising it and a server ignores the
peer's request, so a standard master secret is negotiated. A server also
declines resumption of sessions or tickets that used EMS and does a full
handshake instead. TLS 1.2 and earlier only. Requires
HAVE_EXTENDED_MASTER.

\return WOLFSSL_SUCCESS on success.
\return BAD_FUNC_ARG if ctx is NULL.

\param ctx a pointer to a WOLFSSL_CTX structure, created using
wolfSSL_CTX_new().

_Example_
\code
wolfSSL_CTX_DisableExtendedMasterSecret(ctx);
\endcode

\sa wolfSSL_DisableExtendedMasterSecret
\sa wolfSSL_CTX_EnableExtendedMasterSecret
\sa wolfSSL_CTX_RequireExtendedMasterSecret
*/
int wolfSSL_CTX_DisableExtendedMasterSecret(WOLFSSL_CTX* ctx);

/*!
\ingroup Setup
\brief Disables the TLS Extended Master Secret extension (RFC 7627) on
the SSL object: a client stops advertising it and a server ignores the
peer's request, so a standard master secret is negotiated. A server also
declines resumption of sessions or tickets that used EMS and does a full
handshake instead. TLS 1.2 and earlier only. Requires
HAVE_EXTENDED_MASTER.

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

\param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new().

_Example_
\code
wolfSSL_DisableExtendedMasterSecret(ssl);
\endcode

\sa wolfSSL_CTX_DisableExtendedMasterSecret
\sa wolfSSL_EnableExtendedMasterSecret
\sa wolfSSL_RequireExtendedMasterSecret
*/
int wolfSSL_DisableExtendedMasterSecret(WOLFSSL* ssl);

/*!
\ingroup Setup
\brief Re-enables the TLS Extended Master Secret extension (RFC 7627) on
the context (the default): EMS is used when the peer supports it but is
not mandatory. Undoes a previous disable or require. Requires
HAVE_EXTENDED_MASTER.

\return WOLFSSL_SUCCESS on success.
\return BAD_FUNC_ARG if ctx is NULL.

\param ctx a pointer to a WOLFSSL_CTX structure, created using
wolfSSL_CTX_new().

_Example_
\code
wolfSSL_CTX_EnableExtendedMasterSecret(ctx);
\endcode

\sa wolfSSL_EnableExtendedMasterSecret
\sa wolfSSL_CTX_DisableExtendedMasterSecret
\sa wolfSSL_CTX_RequireExtendedMasterSecret
*/
int wolfSSL_CTX_EnableExtendedMasterSecret(WOLFSSL_CTX* ctx);

/*!
\ingroup Setup
\brief Re-enables the TLS Extended Master Secret extension (RFC 7627) on
the SSL object (the default): EMS is used when the peer supports it but
is not mandatory. Undoes a previous disable or require. Requires
HAVE_EXTENDED_MASTER.

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

\param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new().

_Example_
\code
wolfSSL_EnableExtendedMasterSecret(ssl);
\endcode

\sa wolfSSL_CTX_EnableExtendedMasterSecret
\sa wolfSSL_DisableExtendedMasterSecret
\sa wolfSSL_RequireExtendedMasterSecret
*/
int wolfSSL_EnableExtendedMasterSecret(WOLFSSL* ssl);

/*!
\ingroup Setup
\brief Makes the TLS Extended Master Secret extension (RFC 7627)
mandatory on the context: if it is not negotiated, the connection
is aborted with EXT_MASTER_SECRET_NEEDED_E. A client advertises
the extension even after a previous disable. Sessions using a
session-secret callback (EAP-FAST) are exempt. TLS 1.2 and earlier
only. Requires HAVE_EXTENDED_MASTER.

\return WOLFSSL_SUCCESS on success.
\return BAD_FUNC_ARG if ctx is NULL.

\param ctx a pointer to a WOLFSSL_CTX structure, created using
wolfSSL_CTX_new().

_Example_
\code
wolfSSL_CTX_RequireExtendedMasterSecret(ctx);
\endcode

\sa wolfSSL_RequireExtendedMasterSecret
\sa wolfSSL_CTX_EnableExtendedMasterSecret
\sa wolfSSL_CTX_DisableExtendedMasterSecret
*/
int wolfSSL_CTX_RequireExtendedMasterSecret(WOLFSSL_CTX* ctx);

/*!
\ingroup Setup
\brief Makes the TLS Extended Master Secret extension (RFC 7627)
mandatory on the SSL object: if it is not negotiated, including on
resumption, the connection is aborted with EXT_MASTER_SECRET_NEEDED_E. A
client advertises the extension even after a previous disable. Sessions
using a session-secret callback (EAP-FAST) are exempt. TLS 1.2 and
earlier only. Requires HAVE_EXTENDED_MASTER.

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

\param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new().

_Example_
\code
wolfSSL_RequireExtendedMasterSecret(ssl);
\endcode

\sa wolfSSL_CTX_RequireExtendedMasterSecret
\sa wolfSSL_EnableExtendedMasterSecret
\sa wolfSSL_DisableExtendedMasterSecret
*/
int wolfSSL_RequireExtendedMasterSecret(WOLFSSL* ssl);
108 changes: 91 additions & 17 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2362,7 +2362,8 @@ int InitSSL_Side(WOLFSSL* ssl, word16 side)
#endif /* WOLFSSL_HAVE_SLHDSA */

#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT)
if (ssl->options.side == WOLFSSL_CLIENT_END) {
/* Don't re-arm EMS advertising that the user disabled. */
if (ssl->options.side == WOLFSSL_CLIENT_END && !ssl->options.disableEMS) {
if ((ssl->ctx->method->version.major == SSLv3_MAJOR) &&
(ssl->ctx->method->version.minor >= TLSv1_MINOR)) {
ssl->options.haveEMS = 1;
Expand Down Expand Up @@ -8675,6 +8676,8 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)

#ifdef HAVE_EXTENDED_MASTER
ssl->options.haveEMS = ctx->haveEMS;
ssl->options.disableEMS = ctx->disableEMS;
ssl->options.requireEMS = ctx->requireEMS;
#endif
ssl->options.useClientOrder = ctx->useClientOrder;
ssl->options.mutualAuth = ctx->mutualAuth;
Expand Down Expand Up @@ -24711,18 +24714,21 @@ static void DropAndRestartProcessReply(WOLFSSL* ssl)
* Returns 0 if consistent, else sends a fatal alert and returns an error. */
static int CheckResumptionConsistency(WOLFSSL* ssl)
{
byte skipEmsCheck = 0;

if (ssl->session == NULL) /* nothing to compare against */
return 0;
/* EMS must match (RFC 7627 5.3); skip EAP-FAST (session-secret callback). */
if (
#ifdef HAVE_SECRET_CALLBACK
!(ssl->sessionSecretCb != NULL
/* Skip the EMS checks for EAP-FAST (session-secret callback): the master
* secret comes from the callback rather than the cached session. */
skipEmsCheck = (ssl->sessionSecretCb != NULL
#ifdef HAVE_SESSION_TICKET
&& ssl->session->ticketLen > 0
#endif
) &&
) ? 1 : 0;
#endif
ssl->session->haveEMS != ssl->options.haveEMS) {
/* EMS must match (RFC 7627 5.3). */
if (!skipEmsCheck && ssl->session->haveEMS != ssl->options.haveEMS) {
WOLFSSL_MSG("Resumed session EMS state does not match "
"ServerHello EMS state");
SendAlert(ssl, alert_fatal, handshake_failure);
Expand Down Expand Up @@ -30059,7 +30065,7 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e)
return "Initialize ctx mutex error";

case EXT_MASTER_SECRET_NEEDED_E:
return "Extended Master Secret must be enabled to resume EMS session";
return "Extended Master Secret required but not negotiated with peer";

case DTLS_POOL_SZ_E:
return "Maximum DTLS pool size exceeded";
Expand Down Expand Up @@ -34700,8 +34706,16 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
if (OPAQUE16_LEN + OPAQUE16_LEN + extSz > totalExtSz)
return BUFFER_ERROR;

if (extId == HELLO_EXT_EXTMS)
if (extId == HELLO_EXT_EXTMS) {
#ifdef HAVE_EXTENDED_MASTER
/* Ignore the peer's extension when the user
* disabled EMS. */
if (!ssl->options.disableEMS)
pendingEMS = 1;
#else
pendingEMS = 1;
#endif
}
else
i += extSz;

Expand All @@ -34721,6 +34735,31 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
}
#endif /* HAVE_TLS_EXTENSIONS */

#ifdef HAVE_EXTENDED_MASTER
/* The negotiated EMS state is final once the ServerHello extensions
* are parsed: abort a requiring client here, before any key material
* is computed or sent. */
if (ssl->options.requireEMS && !ssl->options.haveEMS) {
byte skipEmsCheck = 0;
#ifdef HAVE_SECRET_CALLBACK
/* Skip for EAP-FAST (session-secret callback): the master secret
* comes from the callback. */
skipEmsCheck = (ssl->sessionSecretCb != NULL
#ifdef HAVE_SESSION_TICKET
&& ssl->session != NULL
&& ssl->session->ticketLen > 0
#endif
) ? 1 : 0;
#endif
if (!skipEmsCheck) {
WOLFSSL_MSG("EMS required but not negotiated with peer");
SendAlert(ssl, alert_fatal, handshake_failure);
WOLFSSL_ERROR_VERBOSE(EXT_MASTER_SECRET_NEEDED_E);
return EXT_MASTER_SECRET_NEEDED_E;
}
}
#endif /* HAVE_EXTENDED_MASTER */

#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
Expand Down Expand Up @@ -40822,6 +40861,19 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
#endif
}
#endif /* HAVE_SESSION_TICKET && (HAVE_SNI || HAVE_ALPN) */

#ifdef HAVE_EXTENDED_MASTER
/* Resumption skips MakeMasterSecret, so enforce required EMS here. */
if (ssl->options.requireEMS && !ssl->options.haveEMS) {
WOLFSSL_MSG("EMS required but not negotiated with peer");
#ifdef WOLFSSL_EXTRA_ALERTS
SendAlert(ssl, alert_fatal, handshake_failure);
#endif
WOLFSSL_ERROR_VERBOSE(EXT_MASTER_SECRET_NEEDED_E);
return EXT_MASTER_SECRET_NEEDED_E;
}
#endif /* HAVE_EXTENDED_MASTER */

#if !defined(WOLFSSL_NO_TICKET_EXPIRE) && !defined(NO_ASN_TIME)
/* check if the ticket is valid */
if (LowResTimer() > session->bornOn + ssl->timeout) {
Expand All @@ -40830,7 +40882,12 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
}
#endif /* !WOLFSSL_NO_TICKET_EXPIRE && !NO_ASN_TIME */

else if (session->haveEMS != ssl->options.haveEMS) {
if (!ssl->options.resuming) {
Comment thread
kareem-wolfssl marked this conversation as resolved.
/* Resumption abandoned: DoClientHello runs a full handshake. */
return ret;
}

if (session->haveEMS != ssl->options.haveEMS) {
/* RFC 7627, 5.3, server-side */
/* if old sess didn't have EMS, but new does, full handshake */
if (!session->haveEMS && ssl->options.haveEMS) {
Expand All @@ -40841,13 +40898,27 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
}
/* if old sess used EMS, but new doesn't, MUST abort */
else if (session->haveEMS && !ssl->options.haveEMS) {
WOLFSSL_MSG("Trying to resume a session with EMS without "
"using EMS");
#ifdef WOLFSSL_EXTRA_ALERTS
SendAlert(ssl, alert_fatal, handshake_failure);
#endif
ret = EXT_MASTER_SECRET_NEEDED_E;
WOLFSSL_ERROR_VERBOSE(ret);
#ifdef HAVE_EXTENDED_MASTER
if (ssl->options.disableEMS) {
/* Local disable, not a client downgrade: decline the
* resumption and do a full handshake. */
WOLFSSL_MSG("EMS disabled locally, declining resumption "
"of an EMS session. Do full handshake.");
ssl->options.resuming = 0;
Comment thread
kareem-wolfssl marked this conversation as resolved.
/* A declined ticket must not satisfy client auth. */
ssl->options.peerAuthGood = 0;
}
else
#endif
{
WOLFSSL_MSG("Trying to resume a session with EMS without "
"using EMS");
#ifdef WOLFSSL_EXTRA_ALERTS
SendAlert(ssl, alert_fatal, handshake_failure);
#endif
ret = EXT_MASTER_SECRET_NEEDED_E;
WOLFSSL_ERROR_VERBOSE(ret);
}
}
}
else {
Expand Down Expand Up @@ -41548,7 +41619,10 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
i += hashSigAlgoSz;
}
#ifdef HAVE_EXTENDED_MASTER
else if (extId == HELLO_EXT_EXTMS)
/* Honor a user request to disable EMS on the server by
* ignoring the peer's extension. */
else if (extId == HELLO_EXT_EXTMS &&
!ssl->options.disableEMS)
ssl->options.haveEMS = 1;
#endif
else
Expand Down
Loading
Loading