Skip to content

Commit 9f84638

Browse files
committed
Enforce RFC 5746 renegotiation_info in TLS 1.2 client by default
1 parent 4a7695e commit 9f84638

10 files changed

Lines changed: 371 additions & 83 deletions

File tree

configure.ac

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8804,6 +8804,26 @@ AC_ARG_ENABLE([secure-renegotiation-info],
88048804
[ ENABLED_SECURE_RENEGOTIATION_INFO=yes ]
88058805
)
88068806
8807+
# Legacy Server Connect
8808+
# By default a TLS 1.2 client requires the server to acknowledge the
8809+
# renegotiation_info extension on the initial handshake (RFC 5746 / RFC 9325).
8810+
# Enable this option to also connect to legacy servers that do not support
8811+
# secure renegotiation (not recommended).
8812+
AC_ARG_ENABLE([legacy-server-connect],
8813+
[AS_HELP_STRING([--enable-legacy-server-connect],[Allow connecting to servers that do not support secure renegotiation (default: disabled)])],
8814+
[ ENABLED_LEGACY_SERVER_CONNECT=$enableval ],
8815+
[ ENABLED_LEGACY_SERVER_CONNECT=no ]
8816+
)
8817+
8818+
if test "x$ENABLED_LEGACY_SERVER_CONNECT" = "xyes"
8819+
then
8820+
if test "x$ENABLED_HARDEN_TLS" != "xno"
8821+
then
8822+
AC_MSG_ERROR([--enable-legacy-server-connect conflicts with --enable-harden-tls (RFC 9325 3.5). Define WOLFSSL_HARDEN_TLS_NO_SCR_CHECK directly if this is intended.])
8823+
fi
8824+
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ALLOW_LEGACY_SERVER_CONNECT"
8825+
fi
8826+
88078827
88088828
# Exporting Keying Material
88098829
AC_ARG_ENABLE([keying-material],
@@ -13528,6 +13548,7 @@ echo " * Session Ticket: $ENABLED_SESSION_TICKET"
1352813548
echo " * Extended Master Secret: $ENABLED_EXTENDED_MASTER"
1352913549
echo " * Renegotiation Indication: $ENABLED_RENEGOTIATION_INDICATION"
1353013550
echo " * Secure Renegotiation: $ENABLED_SECURE_RENEGOTIATION"
13551+
echo " * Legacy Server Connect: $ENABLED_LEGACY_SERVER_CONNECT"
1353113552
echo " * Keying Material Exporter: $ENABLED_KEYING_MATERIAL"
1353213553
echo " * All TLS Extensions: $ENABLED_TLSX"
1353313554
echo " * S/MIME: $ENABLED_SMIME"

src/internal.c

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,17 @@ int InitSSL_Ctx(WOLFSSL_CTX* ctx, WOLFSSL_METHOD* method, void* heap)
26992699
ctx->minMlDsaKeySz = MIN_MLDSAKEY_SZ;
27002700
#endif /* WOLFSSL_HAVE_MLDSA */
27012701
ctx->verifyDepth = MAX_CHAIN_DEPTH;
2702+
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
2703+
defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
2704+
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK) && \
2705+
!defined(WOLFSSL_ALLOW_LEGACY_SERVER_CONNECT)
2706+
/* RFC 5746 / RFC 9325: a TLS 1.2 client requires the server to acknowledge
2707+
* the renegotiation_info extension on the initial handshake. Enabled by
2708+
* default; define WOLFSSL_ALLOW_LEGACY_SERVER_CONNECT (or call
2709+
* wolfSSL_CTX_set_scr_check_enabled(ctx, 0)) to connect to servers that do
2710+
* not support secure renegotiation. */
2711+
ctx->scr_check_enabled = 1;
2712+
#endif
27022713
#ifdef OPENSSL_EXTRA
27032714
ctx->cbioFlag = WOLFSSL_CBIO_NONE;
27042715
#endif
@@ -8023,6 +8034,58 @@ static void InitSSL_Multicast(WOLFSSL* ssl, WOLFSSL_CTX* ctx)
80238034
}
80248035
#endif /* WOLFSSL_MULTICAST */
80258036

8037+
#if defined(HAVE_SECURE_RENEGOTIATION) || defined(HAVE_SERVER_RENEGOTIATION_INFO)
8038+
/* Set up the client's renegotiation_info advertising. Shared by InitSSL and the
8039+
* ClientHello send paths so the "advertise implies enforce" invariant survives
8040+
* WOLFSSL object reuse: without re-advertising after wolfSSL_clear the client
8041+
* would send no renegotiation_info yet still enforce its presence, failing
8042+
* every reused-object handshake.
8043+
*
8044+
* Willingness to perform a peer-initiated renegotiation is derived from
8045+
* ssl->ctx->useSecureReneg. A per-object wolfSSL_UseSecureRenegotiation() opt-in
8046+
* is not tracked here, so after wolfSSL_clear a reused object reverts to
8047+
* advertise-only; applications that renegotiate on reused objects should opt in
8048+
* at the context level with wolfSSL_CTX_UseSecureRenegotiation(). */
8049+
int SetupClientSecureRenegotiation(WOLFSSL* ssl)
8050+
{
8051+
int ret = WOLFSSL_SUCCESS;
8052+
8053+
if (ssl->options.side == WOLFSSL_CLIENT_END) {
8054+
int useSecureReneg = ssl->ctx->useSecureReneg;
8055+
#ifdef HAVE_SECURE_RENEGOTIATION
8056+
int advertiseOnly = 0;
8057+
#endif
8058+
/* Advertise the empty renegotiation_info extension by default so the
8059+
* client can enforce RFC 5746 / RFC 9325 on the initial handshake.
8060+
* Advertising is always safe: legacy servers ignore it and secure
8061+
* servers echo it. */
8062+
#if defined(WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT)
8063+
/* Integrator asked for secure renegotiation by default: keep the full
8064+
* renegotiation behavior (advertiseOnly stays 0). */
8065+
useSecureReneg = 1;
8066+
#elif !defined(WOLFSSL_NO_TLS12) && defined(HAVE_SERVER_RENEGOTIATION_INFO)
8067+
#ifdef HAVE_SECURE_RENEGOTIATION
8068+
/* Advertising was forced on for the RFC 5746 check, not requested by
8069+
* the application, so do not also grant willingness to perform a
8070+
* peer-initiated renegotiation. */
8071+
if (!useSecureReneg)
8072+
advertiseOnly = 1;
8073+
#endif
8074+
useSecureReneg = 1;
8075+
#endif
8076+
if (useSecureReneg) {
8077+
ret = wolfSSL_UseSecureRenegotiation(ssl);
8078+
#ifdef HAVE_SECURE_RENEGOTIATION
8079+
if (ret == WOLFSSL_SUCCESS && ssl->secure_renegotiation != NULL)
8080+
ssl->secure_renegotiation->advertiseOnly = (byte)advertiseOnly;
8081+
#endif
8082+
}
8083+
}
8084+
8085+
return ret;
8086+
}
8087+
#endif /* HAVE_SECURE_RENEGOTIATION || HAVE_SERVER_RENEGOTIATION_INFO */
8088+
80268089
int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
80278090
{
80288091
int ret;
@@ -8239,8 +8302,10 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
82398302
ssl->disabledCurves = ctx->disabledCurves;
82408303
#endif
82418304
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
8242-
defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
8243-
ssl->scr_check_enabled = 1;
8305+
defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
8306+
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
8307+
/* Inherit the renegotiation_info enforcement setting from the context. */
8308+
ssl->scr_check_enabled = ctx->scr_check_enabled;
82448309
#endif
82458310

82468311
InitCiphers(ssl);
@@ -8366,20 +8431,9 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
83668431

83678432
#if defined(HAVE_SECURE_RENEGOTIATION) || \
83688433
defined(HAVE_SERVER_RENEGOTIATION_INFO)
8369-
if (ssl->options.side == WOLFSSL_CLIENT_END) {
8370-
int useSecureReneg = ssl->ctx->useSecureReneg;
8371-
/* use secure renegotiation by default (not recommend) */
8372-
#if defined(WOLFSSL_SECURE_RENEGOTIATION_ON_BY_DEFAULT) || \
8373-
(defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_NO_TLS12) && \
8374-
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK))
8375-
useSecureReneg = 1;
8376-
#endif
8377-
if (useSecureReneg) {
8378-
ret = wolfSSL_UseSecureRenegotiation(ssl);
8379-
if (ret != WOLFSSL_SUCCESS)
8380-
return ret;
8381-
}
8382-
}
8434+
ret = SetupClientSecureRenegotiation(ssl);
8435+
if (ret != WOLFSSL_SUCCESS)
8436+
return ret;
83838437
#endif /* HAVE_SECURE_RENEGOTIATION */
83848438

83858439
#ifdef WOLFSSL_QUIC
@@ -9428,7 +9482,10 @@ void FreeHandshakeResources(WOLFSSL* ssl)
94289482
#endif
94299483

94309484
#ifdef HAVE_SECURE_RENEGOTIATION
9431-
if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
9485+
/* advertiseOnly clients never renegotiate, so do not retain (and leave
9486+
* unzeroed) the master secret and other handshake resources for them. */
9487+
if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
9488+
!ssl->secure_renegotiation->advertiseOnly) {
94329489
WOLFSSL_MSG("Secure Renegotiation needs to retain handshake resources");
94339490
return;
94349491
}
@@ -18573,8 +18630,13 @@ static int DoHelloRequest(WOLFSSL* ssl, word32 size)
1857318630
return FATAL_ERROR;
1857418631
}
1857518632
#ifdef HAVE_SECURE_RENEGOTIATION
18576-
else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled) {
18577-
/* WOLFSSL_OP_NO_RENEGOTIATION: caller opted into rejecting
18633+
else if (ssl->secure_renegotiation && ssl->secure_renegotiation->enabled &&
18634+
!ssl->secure_renegotiation->advertiseOnly) {
18635+
/* advertiseOnly: renegotiation_info was advertised only for the RFC
18636+
* 5746 initial-handshake check, so the application did not opt into
18637+
* secure renegotiation; the else branch below refuses the request.
18638+
*
18639+
* WOLFSSL_OP_NO_RENEGOTIATION: caller opted into rejecting
1857818640
* peer-initiated renegotiation. Respond with a no_renegotiation
1857918641
* warning alert instead of starting a secure renegotiation. */
1858018642
if (ssl->options.mask & WOLFSSL_OP_NO_RENEGOTIATION) {
@@ -32654,6 +32716,17 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
3265432716
return BAD_FUNC_ARG;
3265532717
}
3265632718

32719+
#if defined(HAVE_SECURE_RENEGOTIATION) || defined(HAVE_SERVER_RENEGOTIATION_INFO)
32720+
/* Re-establish renegotiation_info advertising for a reused object
32721+
* (wolfSSL_clear frees it). Only when absent, so an in-progress
32722+
* renegotiation keeps its verify_data state. */
32723+
if (ssl->secure_renegotiation == NULL) {
32724+
ret = SetupClientSecureRenegotiation(ssl);
32725+
if (ret != WOLFSSL_SUCCESS)
32726+
return ret;
32727+
}
32728+
#endif
32729+
3265732730
#ifdef WOLFSSL_TLS13
3265832731
if (IsAtLeastTLSv1_3(ssl->version))
3265932732
return SendTls13ClientHello(ssl);
@@ -33346,14 +33419,18 @@ static void MakePSKPreMasterSecret(Arrays* arrays, byte use_psk_key)
3334633419
}
3334733420
#endif /* HAVE_TLS_EXTENSIONS */
3334833421

33349-
#if defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
33422+
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
33423+
defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
33424+
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
3335033425
if (ssl->scr_check_enabled && (ssl->secure_renegotiation == NULL ||
3335133426
!ssl->secure_renegotiation->enabled)) {
3335233427
/* If the server does not acknowledge the extension, the client
3335333428
* MUST generate a fatal handshake_failure alert prior to
3335433429
* terminating the connection.
3335533430
* https://www.rfc-editor.org/rfc/rfc9325#name-renegotiation-in-tls-12 */
3335633431
WOLFSSL_MSG("ServerHello did not contain SCR extension");
33432+
WOLFSSL_ERROR_VERBOSE(SECURE_RENEGOTIATION_E);
33433+
(void)SendAlert(ssl, alert_fatal, handshake_failure);
3335733434
return SECURE_RENEGOTIATION_E;
3335833435
}
3335933436
#endif

src/ssl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7988,6 +7988,9 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
79887988
#if defined(HAVE_SECURE_RENEGOTIATION) \
79897989
|| defined(HAVE_SERVER_RENEGOTIATION_INFO)
79907990
ssl->secure_renegotiation = NULL;
7991+
/* The renegotiation_info advertising is re-established when the next
7992+
* ClientHello is built (SendClientHello), so a reused client object
7993+
* keeps the "advertise implies enforce" invariant (RFC 5746). */
79917994
#endif
79927995
#endif
79937996

src/ssl_api_ext.c

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,13 @@ static int _Rehandshake(WOLFSSL* ssl)
804804
return SECURE_RENEGOTIATION_E;
805805
}
806806

807+
if (ssl->secure_renegotiation->advertiseOnly) {
808+
/* Extension was advertised only for the RFC 5746 check; the
809+
* application did not call wolfSSL_UseSecureRenegotiation(). */
810+
WOLFSSL_MSG("Secure Renegotiation not forced on by user");
811+
return SECURE_RENEGOTIATION_E;
812+
}
813+
807814
#ifdef WOLFSSL_DTLS
808815
if (ssl->options.dtls && ssl->keys.dtls_epoch == 0xFFFF) {
809816
WOLFSSL_MSG("Secure Renegotiation not allowed. Epoch would wrap");
@@ -962,7 +969,8 @@ long wolfSSL_SSL_get_secure_renegotiation_support(WOLFSSL* ssl)
962969
#endif /* HAVE_SECURE_RENEGOTIATION_INFO */
963970

964971
#if !defined(NO_WOLFSSL_CLIENT) && !defined(WOLFSSL_NO_TLS12) && \
965-
defined(WOLFSSL_HARDEN_TLS) && !defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
972+
defined(HAVE_SERVER_RENEGOTIATION_INFO) && \
973+
!defined(WOLFSSL_HARDEN_TLS_NO_SCR_CHECK)
966974
/* Get whether the secure renegotiation check is enabled for the object.
967975
*
968976
* @param [in] ssl SSL/TLS object.
@@ -996,6 +1004,45 @@ WOLFSSL_API int wolfSSL_set_scr_check_enabled(WOLFSSL* ssl, byte enabled)
9961004
ssl->scr_check_enabled = !!enabled;
9971005
return WOLFSSL_SUCCESS;
9981006
}
1007+
1008+
/* Get whether the secure renegotiation check is enabled for the context.
1009+
*
1010+
* @param [in] ctx SSL/TLS context object.
1011+
* @return Non-zero when the check is enabled, 0 otherwise.
1012+
* @return BAD_FUNC_ARG when ctx is NULL.
1013+
*/
1014+
WOLFSSL_API int wolfSSL_CTX_get_scr_check_enabled(const WOLFSSL_CTX* ctx)
1015+
{
1016+
WOLFSSL_ENTER("wolfSSL_CTX_get_scr_check_enabled");
1017+
1018+
if (ctx == NULL)
1019+
return BAD_FUNC_ARG;
1020+
1021+
return ctx->scr_check_enabled;
1022+
}
1023+
1024+
/* Set whether the secure renegotiation check is enabled for the context.
1025+
*
1026+
* WOLFSSL objects created from the context inherit this setting. Disabling the
1027+
* check allows connecting to servers that do not support secure renegotiation
1028+
* (RFC 5746), which is not recommended.
1029+
*
1030+
* @param [in] ctx SSL/TLS context object.
1031+
* @param [in] enabled Non-zero to enable the check, 0 to disable it.
1032+
* @return WOLFSSL_SUCCESS on success.
1033+
* @return BAD_FUNC_ARG when ctx is NULL.
1034+
*/
1035+
WOLFSSL_API int wolfSSL_CTX_set_scr_check_enabled(WOLFSSL_CTX* ctx,
1036+
byte enabled)
1037+
{
1038+
WOLFSSL_ENTER("wolfSSL_CTX_set_scr_check_enabled");
1039+
1040+
if (ctx == NULL)
1041+
return BAD_FUNC_ARG;
1042+
1043+
ctx->scr_check_enabled = !!enabled;
1044+
return WOLFSSL_SUCCESS;
1045+
}
9991046
#endif
10001047

10011048
#if defined(HAVE_SESSION_TICKET)

src/tls13.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4638,6 +4638,17 @@ int SendTls13ClientHello(WOLFSSL* ssl)
46384638
return BAD_FUNC_ARG;
46394639
}
46404640

4641+
#if defined(HAVE_SECURE_RENEGOTIATION) || defined(HAVE_SERVER_RENEGOTIATION_INFO)
4642+
/* Re-establish renegotiation_info advertising for a reused object
4643+
* (wolfSSL_clear frees it) so a TLS 1.2 downgrade still enforces what the
4644+
* ClientHello advertised. Only when absent, to keep any existing state. */
4645+
if (ssl->secure_renegotiation == NULL) {
4646+
ret = SetupClientSecureRenegotiation(ssl);
4647+
if (ret != WOLFSSL_SUCCESS)
4648+
return ret;
4649+
}
4650+
#endif
4651+
46414652
ssl->options.buildingMsg = 1;
46424653
major = SSLv3_MAJOR;
46434654
tls12minor = TLSv1_2_MINOR;

0 commit comments

Comments
 (0)