| diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c |
| --- a/nss/lib/ssl/ssl3con.c 2014-01-17 18:46:51.999581198 -0800 |
| +++ b/nss/lib/ssl/ssl3con.c 2014-01-17 18:47:05.509804656 -0800 |
| @@ -3473,6 +3473,9 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffe |
| 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; |
| @@ -4986,6 +4989,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBo |
| int num_suites; |
| int actual_count = 0; |
| PRBool isTLS = PR_FALSE; |
| + PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; |
| PRInt32 total_exten_len = 0; |
| unsigned paddingExtensionLen; |
| unsigned numCompressionMethods; |
| @@ -5128,6 +5132,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBo |
| } |
| |
| if (sid) { |
| + requestingResume = PR_TRUE; |
| SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits ); |
| |
| PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl3.sessionID, |
| @@ -5246,8 +5251,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBo |
| if (sid->u.ssl3.lock) { PR_RWLock_Unlock(sid->u.ssl3.lock); } |
| 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 */ |
| @@ -5353,6 +5365,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBo |
| } |
| actual_count++; |
| } |
| + if (fallbackSCSV) { |
| + rv = ssl3_AppendHandshakeNumber(ss, TLS_FALLBACK_SCSV, |
| + sizeof(ssl3CipherSuite)); |
| + if (rv != SECSuccess) { |
| + if (sid->u.ssl3.lock) { PR_RWLock_Unlock(sid->u.ssl3.lock); } |
| + 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)) { |
| @@ -8084,6 +8105,19 @@ ssl3_HandleClientHello(sslSocket *ss, SS |
| 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 -pu a/nss/lib/ssl/ssl3prot.h b/nss/lib/ssl/ssl3prot.h |
| --- a/nss/lib/ssl/ssl3prot.h 2014-01-17 17:59:03.242109996 -0800 |
| +++ b/nss/lib/ssl/ssl3prot.h 2014-01-17 18:47:05.509804656 -0800 |
| @@ -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 -pu a/nss/lib/ssl/sslerr.h b/nss/lib/ssl/sslerr.h |
| --- a/nss/lib/ssl/sslerr.h 2014-01-17 17:59:03.242109996 -0800 |
| +++ b/nss/lib/ssl/sslerr.h 2014-01-17 18:47:05.509804656 -0800 |
| @@ -196,6 +196,7 @@ SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM |
| 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 -pu a/nss/lib/ssl/SSLerrs.h b/nss/lib/ssl/SSLerrs.h |
| --- a/nss/lib/ssl/SSLerrs.h 2014-01-17 17:59:03.242109996 -0800 |
| +++ b/nss/lib/ssl/SSLerrs.h 2014-01-17 18:47:05.509804656 -0800 |
| @@ -421,3 +421,8 @@ ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (S |
| |
| 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 -pu a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h |
| --- a/nss/lib/ssl/ssl.h 2014-01-17 18:46:51.999581198 -0800 |
| +++ b/nss/lib/ssl/ssl.h 2014-01-17 18:48:54.971613341 -0800 |
| @@ -183,6 +183,8 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF |
| |
| /* Request Signed Certificate Timestamps via TLS extension (client) */ |
| #define SSL_ENABLE_SIGNED_CERT_TIMESTAMPS 27 |
| +#define SSL_ENABLE_FALLBACK_SCSV 28 /* Send fallback SCSV in |
| + * handshakes. */ |
| |
| #ifdef SSL_DEPRECATED_FUNCTION |
| /* Old deprecated function names */ |
| diff -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h |
| --- a/nss/lib/ssl/sslimpl.h 2014-01-17 18:46:51.999581198 -0800 |
| +++ b/nss/lib/ssl/sslimpl.h 2014-01-17 18:51:17.963962287 -0800 |
| @@ -338,6 +338,7 @@ typedef struct sslOptionsStr { |
| unsigned int enableNPN : 1; /* 26 */ |
| unsigned int enableALPN : 1; /* 27 */ |
| unsigned int enableSignedCertTimestamps : 1; /* 28 */ |
| + unsigned int enableFallbackSCSV : 1; /* 29 */ |
| } sslOptions; |
| |
| typedef enum { sslHandshakingUndetermined = 0, |
| diff -pu a/nss/lib/ssl/sslproto.h b/nss/lib/ssl/sslproto.h |
| --- a/nss/lib/ssl/sslproto.h 2014-01-17 18:10:16.793281867 -0800 |
| +++ b/nss/lib/ssl/sslproto.h 2014-01-17 18:47:05.509804656 -0800 |
| @@ -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 -pu a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c |
| --- a/nss/lib/ssl/sslsock.c 2014-01-17 18:46:52.009581364 -0800 |
| +++ b/nss/lib/ssl/sslsock.c 2014-01-17 18:59:17.931852364 -0800 |
| @@ -88,7 +88,8 @@ static sslOptions ssl_defaults = { |
| PR_FALSE, /* enableOCSPStapling */ |
| PR_TRUE, /* enableNPN */ |
| PR_FALSE, /* enableALPN */ |
| - PR_FALSE /* enableSignedCertTimestamps */ |
| + PR_FALSE, /* enableSignedCertTimestamps */ |
| + PR_FALSE /* enableFallbackSCSV */ |
| }; |
| |
| /* |
| @@ -792,6 +793,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh |
| ss->opt.enableSignedCertTimestamps = on; |
| break; |
| |
| + case SSL_ENABLE_FALLBACK_SCSV: |
| + ss->opt.enableFallbackSCSV = on; |
| + break; |
| + |
| default: |
| PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| rv = SECFailure; |
| @@ -867,6 +872,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh |
| 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); |
| @@ -933,6 +939,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBo |
| 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); |
| @@ -1112,6 +1121,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBo |
| ssl_defaults.enableSignedCertTimestamps = on; |
| break; |
| |
| + case SSL_ENABLE_FALLBACK_SCSV: |
| + ssl_defaults.enableFallbackSCSV = on; |
| + break; |
| + |
| default: |
| PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| return SECFailure; |