diff --git a/src/internal.c b/src/internal.c index b27403ad3b..221ab40a94 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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); diff --git a/src/tls.c b/src/tls.c index f9ca896ae3..023a610e30 100644 --- a/src/tls.c +++ b/src/tls.c @@ -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) { diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 8b3231227b..899e695ffc 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -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;