summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Langley <agl@chromium.org>2013-09-25 12:45:06 -0700
committerAdam Langley <agl@chromium.org>2013-09-25 12:45:06 -0700
commit1ce4a945cf11be2df3a2104fbab717706455b0cf (patch)
tree9fca979480f95a7f3cb28cfcff435224eeec5969
parent19d99ac07cc0cc26535a95e0aac7ff29f7dedbed (diff)
downloadnss-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.c61
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;