diff options
author | Adam Langley <agl@chromium.org> | 2013-09-25 12:45:06 -0700 |
---|---|---|
committer | Adam Langley <agl@chromium.org> | 2013-09-25 12:45:06 -0700 |
commit | 1ce4a945cf11be2df3a2104fbab717706455b0cf (patch) | |
tree | 9fca979480f95a7f3cb28cfcff435224eeec5969 | |
parent | 19d99ac07cc0cc26535a95e0aac7ff29f7dedbed (diff) | |
download | nss-hg-1ce4a945cf11be2df3a2104fbab717706455b0cf.tar.gz |
Bug 919677: don't advertise TLS 1.2-only ciphersuites in a TLS 1.1
ClientHello. r=wtc.
-rw-r--r-- | lib/ssl/ssl3con.c | 61 |
1 files changed, 36 insertions, 25 deletions
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index 5129a36b4..b5dafbaa1 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -593,8 +593,9 @@ void SSL_AtomicIncrementLong(long * x) } static PRBool -ssl3_CipherSuiteAllowedForVersion(ssl3CipherSuite cipherSuite, - SSL3ProtocolVersion version) +ssl3_CipherSuiteAllowedForVersionRange( + ssl3CipherSuite cipherSuite, + const SSLVersionRange *vrange) { switch (cipherSuite) { /* See RFC 4346 A.5. Export cipher suites must not be used in TLS 1.1 or @@ -611,7 +612,7 @@ ssl3_CipherSuiteAllowedForVersion(ssl3CipherSuite cipherSuite, * SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5: never implemented * SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA: never implemented */ - return version <= SSL_LIBRARY_VERSION_TLS_1_0; + return vrange->min <= SSL_LIBRARY_VERSION_TLS_1_0; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: case TLS_RSA_WITH_AES_256_CBC_SHA256: case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: @@ -623,7 +624,7 @@ ssl3_CipherSuiteAllowedForVersion(ssl3CipherSuite cipherSuite, case TLS_RSA_WITH_AES_128_CBC_SHA256: case TLS_RSA_WITH_AES_128_GCM_SHA256: case TLS_RSA_WITH_NULL_SHA256: - return version >= SSL_LIBRARY_VERSION_TLS_1_2; + return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2; default: return PR_TRUE; } @@ -766,7 +767,8 @@ ssl3_config_match_init(sslSocket *ss) } -/* return PR_TRUE if suite matches policy and enabled state */ +/* return PR_TRUE if suite matches policy, enabled state and is applicable to + * the given version range. */ /* It would be a REALLY BAD THING (tm) if we ever permitted the use ** of a cipher that was NOT_ALLOWED. So, if this is ever called with ** policy == SSL_NOT_ALLOWED, report no match. @@ -774,7 +776,8 @@ ssl3_config_match_init(sslSocket *ss) /* adjust suite enabled to the availability of a token that can do the * cipher suite. */ static PRBool -config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled) +config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled, + const SSLVersionRange *vrange) { PORT_Assert(policy != SSL_NOT_ALLOWED && enabled != PR_FALSE); if (policy == SSL_NOT_ALLOWED || !enabled) @@ -782,10 +785,13 @@ config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled) return (PRBool)(suite->enabled && suite->isPresent && suite->policy != SSL_NOT_ALLOWED && - suite->policy <= policy); + suite->policy <= policy && + ssl3_CipherSuiteAllowedForVersionRange( + suite->cipher_suite, vrange)); } -/* return number of cipher suites that match policy and enabled state */ +/* return number of cipher suites that match policy, enabled state and are + * applicable for the configured protocol version range. */ /* called from ssl3_SendClientHello and ssl3_ConstructV2CipherSpecsHack */ static int count_cipher_suites(sslSocket *ss, int policy, PRBool enabled) @@ -796,7 +802,7 @@ count_cipher_suites(sslSocket *ss, int policy, PRBool enabled) return 0; } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { - if (config_match(&ss->cipherSuites[i], policy, enabled)) + if (config_match(&ss->cipherSuites[i], policy, enabled, &ss->vrange)) count++; } if (count <= 0) { @@ -5089,7 +5095,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending) } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (config_match(suite, ss->ssl3.policy, PR_TRUE)) { + if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange)) { actual_count++; if (actual_count > num_suites) { /* set error card removal/insertion error */ @@ -6124,15 +6130,19 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; if (temp == suite->cipher_suite) { - if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) { + SSLVersionRange vrange = {ss->version, ss->version}; + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) { + /* config_match already checks whether the cipher suite is + * acceptable for the version, but the check is repeated here + * in order to give a more precise error code. */ + if (!ssl3_CipherSuiteAllowedForVersionRange(temp, &vrange)) { + desc = handshake_failure; + errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION; + goto alert_loser; + } + break; /* failure */ } - if (!ssl3_CipherSuiteAllowedForVersion(suite->cipher_suite, - ss->version)) { - desc = handshake_failure; - errCode = SSL_ERROR_CIPHER_DISALLOWED_FOR_VERSION; - goto alert_loser; - } suite_found = PR_TRUE; break; /* success */ @@ -7521,6 +7531,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) */ if (sid) do { ssl3CipherSuiteCfg *suite; +#ifdef PARANOID + SSLVersionRange vrange = {ss->version, ss->version}; +#endif /* Check that the cached compression method is still enabled. */ if (!compressionEnabled(ss, sid->u.ssl3.compression)) @@ -7549,7 +7562,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * The product policy won't change during the process lifetime. * Implemented ("isPresent") shouldn't change for servers. */ - if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) break; #else if (!suite->enabled) @@ -7597,9 +7610,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) */ for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; - if (!config_match(suite, ss->ssl3.policy, PR_TRUE) || - !ssl3_CipherSuiteAllowedForVersion(suite->cipher_suite, - ss->version)) { + SSLVersionRange vrange = {ss->version, ss->version}; + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) { continue; } for (i = 0; i + 1 < suites.len; i += 2) { @@ -8131,9 +8143,8 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) */ for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j]; - if (!config_match(suite, ss->ssl3.policy, PR_TRUE) || - !ssl3_CipherSuiteAllowedForVersion(suite->cipher_suite, - ss->version)) { + SSLVersionRange vrange = {ss->version, ss->version}; + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) { continue; } for (i = 0; i+2 < suite_length; i += 3) { @@ -11569,7 +11580,7 @@ ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, unsigned char *cs, int *size) /* ssl3_config_match_init was called by the caller of this function. */ for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i]; - if (config_match(suite, SSL_ALLOWED, PR_TRUE)) { + if (config_match(suite, SSL_ALLOWED, PR_TRUE, &ss->vrange)) { if (cs != NULL) { *cs++ = 0x00; *cs++ = (suite->cipher_suite >> 8) & 0xFF; |