diff --git a/nss/lib/ssl/SSLerrs.h b/nss/lib/ssl/SSLerrs.h index c0d26cc..4ff0b7d 100644 --- a/nss/lib/ssl/SSLerrs.h +++ b/nss/lib/ssl/SSLerrs.h @@ -421,3 +421,8 @@ ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 130), ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 131), "The application could not get a TLS Channel ID.") + +ER3(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, (SSL_ERROR_BASE + 132), +"The connection was using a lesser TLS version as a result of a previous" +" handshake failure, but the server indicated that it should not have been" +" needed.") diff --git a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h index 24627ed..067938c 100644 --- a/nss/lib/ssl/ssl.h +++ b/nss/lib/ssl/ssl.h @@ -163,6 +163,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); #define SSL_ENABLE_OCSP_STAPLING 24 /* Request OCSP stapling (client) */ /* Request Signed Certificate Timestamps via TLS extension (client) */ #define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 25 +#define SSL_ENABLE_FALLBACK_SCSV 26 /* Send fallback SCSV in + * handshakes. */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c index cf7ef32..946f780 100644 --- a/nss/lib/ssl/ssl3con.c +++ b/nss/lib/ssl/ssl3con.c @@ -3469,6 +3469,9 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) case certificate_unknown: error = SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT; break; case illegal_parameter: error = SSL_ERROR_ILLEGAL_PARAMETER_ALERT;break; + case inappropriate_fallback: + error = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; + break; /* All alerts below are TLS only. */ case unknown_ca: error = SSL_ERROR_UNKNOWN_CA_ALERT; break; @@ -4973,7 +4976,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) int num_suites; int actual_count = 0; PRBool isTLS = PR_FALSE; - PRBool requestingResume = PR_FALSE; + PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; PRInt32 total_exten_len = 0; unsigned paddingExtensionLen; unsigned numCompressionMethods; @@ -5223,8 +5226,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) return SECFailure; /* count_cipher_suites has set error code. */ + + fallbackSCSV = ss->opt.enableFallbackSCSV && (!requestingResume || + ss->version < sid->version); + /* make room for SCSV */ if (ss->ssl3.hs.sendingSCSV) { - ++num_suites; /* make room for SCSV */ + ++num_suites; + } + if (fallbackSCSV) { + ++num_suites; } /* count compression methods */ @@ -5322,6 +5332,14 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) } actual_count++; } + if (fallbackSCSV) { + rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, + sizeof(ssl3CipherSuite)); + if (rv != SECSuccess) { + return rv; /* err set by ssl3_AppendHandshake* */ + } + actual_count++; + } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange)) { @@ -8037,6 +8055,19 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } + /* If the ClientHello version is less than our maximum version, check for a + * TLS_FALLBACK_SCSV and reject the connection if found. */ + if (ss->vrange.max > ss->clientHelloVersion) { + for (i = 0; i + 1 < suites.len; i += 2) { + PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; + if (suite_i != TLS_FALLBACK_SCSV) + continue; + desc = inappropriate_fallback; + errCode = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT; + goto alert_loser; + } + } + /* grab the list of compression methods. */ rv = ssl3_ConsumeHandshakeVariable(ss, &comps, 1, &b, &length); if (rv != SECSuccess) { diff --git a/nss/lib/ssl/ssl3prot.h b/nss/lib/ssl/ssl3prot.h index 0eab970..4c19ade 100644 --- a/nss/lib/ssl/ssl3prot.h +++ b/nss/lib/ssl/ssl3prot.h @@ -98,6 +98,7 @@ typedef enum { protocol_version = 70, insufficient_security = 71, internal_error = 80, + inappropriate_fallback = 86, /* could also be sent for SSLv3 */ user_canceled = 90, no_renegotiation = 100, diff --git a/nss/lib/ssl/sslerr.h b/nss/lib/ssl/sslerr.h index 5a949c9..82ae7df 100644 --- a/nss/lib/ssl/sslerr.h +++ b/nss/lib/ssl/sslerr.h @@ -196,6 +196,7 @@ SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128), SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 129), SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 130), SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 131), +SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT = (SSL_ERROR_BASE + 132), SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h index 7521dba..6d0bc15 100644 --- a/nss/lib/ssl/sslimpl.h +++ b/nss/lib/ssl/sslimpl.h @@ -336,6 +336,7 @@ typedef struct sslOptionsStr { unsigned int cbcRandomIV : 1; /* 24 */ unsigned int enableOCSPStapling : 1; /* 25 */ unsigned int enableSignedCertTimestamps : 1; /* 26 */ + unsigned int enableFallbackSCSV : 1; /* 27 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, diff --git a/nss/lib/ssl/sslproto.h b/nss/lib/ssl/sslproto.h index 6b60a28..621ef37 100644 --- a/nss/lib/ssl/sslproto.h +++ b/nss/lib/ssl/sslproto.h @@ -172,6 +172,11 @@ */ #define TLS_EMPTY_RENEGOTIATION_INFO_SCSV 0x00FF +/* TLS_FALLBACK_SCSV is a signaling cipher suite value that indicates that a + * handshake is the result of TLS version fallback. This value is not IANA + * assigned. */ +#define TLS_FALLBACK_SCSV 0x5600 + /* Cipher Suite Values starting with 0xC000 are defined in informational * RFCs. */ diff --git a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c index 9f8286c..f7d44d4 100644 --- a/nss/lib/ssl/sslsock.c +++ b/nss/lib/ssl/sslsock.c @@ -174,7 +174,8 @@ static sslOptions ssl_defaults = { PR_FALSE, /* enableFalseStart */ PR_TRUE, /* cbcRandomIV */ PR_FALSE, /* enableOCSPStapling */ - PR_FALSE /* enableSignedCertTimestamps */ + PR_FALSE, /* enableSignedCertTimestamps */ + PR_FALSE /* enableFallbackSCSV */ }; /* @@ -870,6 +871,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) ss->opt.enableSignedCertTimestamps = on; break; + case SSL_ENABLE_FALLBACK_SCSV: + ss->opt.enableFallbackSCSV = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -943,6 +948,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: on = ss->opt.enableSignedCertTimestamps; break; + case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1007,6 +1013,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) case SSL_ENABLE_SIGNED_CERT_TIMESTAMPS: on = ssl_defaults.enableSignedCertTimestamps; break; + case SSL_ENABLE_FALLBACK_SCSV: + on = ssl_defaults.enableFallbackSCSV; + break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1178,6 +1187,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) ssl_defaults.enableSignedCertTimestamps = on; break; + case SSL_ENABLE_FALLBACK_SCSV: + ssl_defaults.enableFallbackSCSV = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure;