diff options
author | Adam Langley <agl@chromium.org> | 2014-08-13 15:03:58 -0700 |
---|---|---|
committer | Adam Langley <agl@chromium.org> | 2014-08-13 15:03:58 -0700 |
commit | d5eb4fde2791537b8eb842740e378b321623b361 (patch) | |
tree | c485bfcdd9c86534d258560396f52c414d449f24 /lib | |
parent | c9822821c155238ded94c6aa6535d54a5112e826 (diff) | |
download | nss-hg-d5eb4fde2791537b8eb842740e378b321623b361.tar.gz |
Bug 1036735: Add TLS_FALLBACK_SCSV cipher suite to version fallback
connections (draft-ietf-tls-downgrade-scsv). r=wtc,martin.thomson.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ssl/SSLerrs.h | 6 | ||||
-rw-r--r-- | lib/ssl/ssl.h | 3 | ||||
-rw-r--r-- | lib/ssl/ssl3con.c | 36 | ||||
-rw-r--r-- | lib/ssl/ssl3prot.h | 1 | ||||
-rw-r--r-- | lib/ssl/sslerr.h | 2 | ||||
-rw-r--r-- | lib/ssl/sslimpl.h | 1 | ||||
-rw-r--r-- | lib/ssl/sslproto.h | 5 | ||||
-rw-r--r-- | lib/ssl/sslsock.c | 15 |
8 files changed, 66 insertions, 3 deletions
diff --git a/lib/ssl/SSLerrs.h b/lib/ssl/SSLerrs.h index 120258fa1..174037b15 100644 --- a/lib/ssl/SSLerrs.h +++ b/lib/ssl/SSLerrs.h @@ -417,4 +417,8 @@ ER3(SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK, (SSL_ERROR_BASE + 129), "The next protocol negotiation extension was enabled, but the callback was cleared prior to being needed.") ER3(SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL, (SSL_ERROR_BASE + 130), -"The next protocol callback picked a default protocol for ALPN.") +"The server supports no protocols that the client advertises in the ALPN extension.") + +ER3(SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT, (SSL_ERROR_BASE + 131), +"The server rejected the handshake because the client downgraded to a lower " +"TLS version than the server supports.") diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h index 4e408f76c..91a47a697 100644 --- a/lib/ssl/ssl.h +++ b/lib/ssl/ssl.h @@ -188,6 +188,9 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); */ #define SSL_REUSE_SERVER_ECDHE_KEY 27 +#define SSL_ENABLE_FALLBACK_SCSV 28 /* Send fallback SCSV in + * handshakes. */ + #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on); diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index efc192097..030dd078d 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -3352,6 +3352,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; @@ -4873,6 +4876,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) 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; @@ -5015,6 +5019,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) } if (sid) { + requestingResume = PR_TRUE; SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits ); PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl3.sessionID, @@ -5129,8 +5134,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) 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 */ @@ -5236,6 +5248,15 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) } 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)) { @@ -7711,6 +7732,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/lib/ssl/ssl3prot.h b/lib/ssl/ssl3prot.h index 4d4aa10bc..223b240df 100644 --- a/lib/ssl/ssl3prot.h +++ b/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/lib/ssl/sslerr.h b/lib/ssl/sslerr.h index 385208591..12dbb1d87 100644 --- a/lib/ssl/sslerr.h +++ b/lib/ssl/sslerr.h @@ -196,6 +196,8 @@ SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM = (SSL_ERROR_BASE + 128), SSL_ERROR_NEXT_PROTOCOL_NO_CALLBACK = (SSL_ERROR_BASE + 129), SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL = (SSL_ERROR_BASE + 130), +SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT = (SSL_ERROR_BASE + 131), + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h index edbd43ffc..7a4bd6109 100644 --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -327,6 +327,7 @@ typedef struct sslOptionsStr { unsigned int enableNPN : 1; /* 26 */ unsigned int enableALPN : 1; /* 27 */ unsigned int reuseServerECDHEKey : 1; /* 28 */ + unsigned int enableFallbackSCSV : 1; /* 29 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, diff --git a/lib/ssl/sslproto.h b/lib/ssl/sslproto.h index 7a283c73c..fff0ab8cb 100644 --- a/lib/ssl/sslproto.h +++ b/lib/ssl/sslproto.h @@ -208,6 +208,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. + */ +#define TLS_FALLBACK_SCSV 0x5600 + /* Cipher Suite Values starting with 0xC000 are defined in informational * RFCs. */ diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c index 72017941e..dfa7a2c7c 100644 --- a/lib/ssl/sslsock.c +++ b/lib/ssl/sslsock.c @@ -81,7 +81,8 @@ static sslOptions ssl_defaults = { PR_FALSE, /* enableOCSPStapling */ PR_TRUE, /* enableNPN */ PR_FALSE, /* enableALPN */ - PR_TRUE /* reuseServerECDHEKey */ + PR_TRUE, /* reuseServerECDHEKey */ + PR_FALSE /* enableFallbackSCSV */ }; /* @@ -789,6 +790,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) ss->opt.reuseServerECDHEKey = on; break; + case SSL_ENABLE_FALLBACK_SCSV: + ss->opt.enableFallbackSCSV = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -863,6 +868,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) case SSL_ENABLE_ALPN: on = ss->opt.enableALPN; break; case SSL_REUSE_SERVER_ECDHE_KEY: on = ss->opt.reuseServerECDHEKey; break; + case SSL_ENABLE_FALLBACK_SCSV: on = ss->opt.enableFallbackSCSV; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -929,6 +935,9 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) case SSL_REUSE_SERVER_ECDHE_KEY: on = ssl_defaults.reuseServerECDHEKey; break; + case SSL_ENABLE_FALLBACK_SCSV: + on = ssl_defaults.enableFallbackSCSV; + break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1108,6 +1117,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) ssl_defaults.reuseServerECDHEKey = on; break; + case SSL_ENABLE_FALLBACK_SCSV: + ssl_defaults.enableFallbackSCSV = on; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; |