F-5810: require renegotiation_info on renegotiation ClientHello

The server validated client_verify_data only inside
TLSX_SecureRenegotiation_Parse, which never runs when the renegotiation_info
extension is absent, so a renegotiation ClientHello that omitted it was never
checked. Track a per-handshake renegInfoSeen flag and, after parsing the
renegotiation ClientHello extensions, abort with handshake_failure if the
extension was absent (RFC 5746 3.7). Also reject an SCSV received during
renegotiation (RFC 5746 3.5).
This commit is contained in:
Juliusz Sosinowicz
2026-06-03 00:32:43 +02:00
parent 1173a365fe
commit 1f4afe9ccc
3 changed files with 36 additions and 4 deletions
+26
View File
@@ -18811,6 +18811,8 @@ int DoHandShakeMsgType(WOLFSSL* ssl, byte* input, word32* inOutIdx,
ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
ssl->options.handShakeState = NULL_STATE;
ssl->secure_renegotiation->cache_status = SCR_CACHE_NEEDED;
/* Reset for the renegotiation_info presence check below. */
ssl->secure_renegotiation->renegInfoSeen = 0;
ret = InitHandshakeHashes(ssl);
if (ret != 0)
@@ -38745,6 +38747,17 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
0) {
TLSX* extension;
#ifdef HAVE_SECURE_RENEGOTIATION
/* SCSV not allowed on a renegotiation ClientHello (RFC 5746 3.5). */
if (ssl->secure_renegotiation &&
ssl->secure_renegotiation->enabled &&
ssl->secure_renegotiation->verifySet) {
WOLFSSL_MSG("SCSV received on renegotiation ClientHello");
SendAlert(ssl, alert_fatal, handshake_failure);
ret = SECURE_RENEGOTIATION_E;
goto out;
}
#endif
/* check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV suite */
ret = TLSX_AddEmptyRenegotiationInfo(&ssl->extensions, ssl->heap);
if (ret != WOLFSSL_SUCCESS) {
@@ -38989,6 +39002,19 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
*inOutIdx = begin + helloSz; /* skip extensions */
}
#ifdef HAVE_SECURE_RENEGOTIATION
/* renegotiation_info MUST be present on a renegotiation (RFC 5746 3.7). */
if (ssl->secure_renegotiation &&
ssl->secure_renegotiation->enabled &&
ssl->secure_renegotiation->verifySet &&
!ssl->secure_renegotiation->renegInfoSeen) {
WOLFSSL_MSG("Renegotiation ClientHello missing renegotiation_info");
SendAlert(ssl, alert_fatal, handshake_failure);
ret = SECURE_RENEGOTIATION_E;
goto out;
}
#endif /* HAVE_SECURE_RENEGOTIATION */
#ifdef WOLFSSL_DTLS_CID
if (ssl->options.useDtlsCID)
DtlsCIDOnExtensionsParsed(ssl);
+3
View File
@@ -6234,6 +6234,9 @@ static int TLSX_SecureRenegotiation_Parse(WOLFSSL* ssl, const byte* input,
if (ret == WOLFSSL_SUCCESS)
ret = 0;
}
/* renegotiation_info seen (checked by DoClientHello, RFC 5746 3.7) */
if (ssl->secure_renegotiation != NULL)
ssl->secure_renegotiation->renegInfoSeen = 1;
if (ret != 0 && ret != WC_NO_ERR_TRACE(SECURE_RENEGOTIATION_E)) {
}
else if (ssl->secure_renegotiation == NULL) {
+7 -4
View File
@@ -3498,13 +3498,16 @@ enum key_cache_state {
/* Additional Connection State according to rfc5746 section 3.1 */
typedef struct SecureRenegotiation {
byte enabled; /* secure_renegotiation flag in rfc */
byte verifySet;
byte startScr; /* server requested client to start scr */
/* Single-bit flags grouped together so they pack into one storage unit. */
WC_BITFIELD enabled:1; /* secure_renegotiation flag in rfc */
WC_BITFIELD verifySet:1;
WC_BITFIELD startScr:1; /* server requested client to start scr */
WC_BITFIELD renegInfoSeen:1; /* renegotiation_info ext seen this
* handshake (RFC 5746 3.7) */
WC_BITFIELD subject_hash_set:1; /* if peer cert hash is set */
enum key_cache_state cache_status; /* track key cache state */
byte client_verify_data[TLS_FINISHED_SZ]; /* cached */
byte server_verify_data[TLS_FINISHED_SZ]; /* cached */
byte subject_hash_set; /* if peer cert hash is set */
byte subject_hash[KEYID_SIZE]; /* peer cert hash */
Keys tmp_keys; /* can't overwrite real keys yet */
} SecureRenegotiation;