summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAdam Langley <agl@chromium.org>2014-08-13 15:03:58 -0700
committerAdam Langley <agl@chromium.org>2014-08-13 15:03:58 -0700
commitd5eb4fde2791537b8eb842740e378b321623b361 (patch)
treec485bfcdd9c86534d258560396f52c414d449f24 /lib
parentc9822821c155238ded94c6aa6535d54a5112e826 (diff)
downloadnss-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.h6
-rw-r--r--lib/ssl/ssl.h3
-rw-r--r--lib/ssl/ssl3con.c36
-rw-r--r--lib/ssl/ssl3prot.h1
-rw-r--r--lib/ssl/sslerr.h2
-rw-r--r--lib/ssl/sslimpl.h1
-rw-r--r--lib/ssl/sslproto.h5
-rw-r--r--lib/ssl/sslsock.c15
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;