summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornelson%bolyard.com <devnull@localhost>2009-11-06 20:11:29 +0000
committernelson%bolyard.com <devnull@localhost>2009-11-06 20:11:29 +0000
commitb3cab804fa9dc23bb0d06ee8500c10534f4dc9be (patch)
tree6799a20117e95c74e1b679fa8b6c53222763e8c2
parent4ae737cb2f8e4855ff7f8fd9953ae5b8244d2cb8 (diff)
downloadnss-hg-b3cab804fa9dc23bb0d06ee8500c10534f4dc9be.tar.gz
Bug 526689: (CVE-2009-3555) SSL3 & TLS Renegotiation Vulnerability
Disable SSL 3.x renegotiation by default. Add new options to re-enable. r=wtc,rrelyea
-rw-r--r--security/nss/cmd/lib/SSLerrs.h6
-rw-r--r--security/nss/lib/ssl/ssl.h15
-rw-r--r--security/nss/lib/ssl/ssl3con.c25
-rw-r--r--security/nss/lib/ssl/sslerr.h1
-rw-r--r--security/nss/lib/ssl/sslimpl.h2
-rw-r--r--security/nss/lib/ssl/sslsock.c55
6 files changed, 102 insertions, 2 deletions
diff --git a/security/nss/cmd/lib/SSLerrs.h b/security/nss/cmd/lib/SSLerrs.h
index 023524929..bde19b0a7 100644
--- a/security/nss/cmd/lib/SSLerrs.h
+++ b/security/nss/cmd/lib/SSLerrs.h
@@ -390,3 +390,9 @@ ER3(SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 109),
ER3(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, (SSL_ERROR_BASE + 110),
"SSL received a malformed New Session Ticket handshake message.")
+
+ER3(SSL_ERROR_DECOMPRESSION_FAILURE, (SSL_ERROR_BASE + 111),
+"SSL received a compressed record that could not be decompressed.")
+
+ER3(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, (SSL_ERROR_BASE + 112),
+"Renegotiation is not allowed on this SSL socket.")
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
index 12e7cba87..25fb7f825 100644
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -116,6 +116,11 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd);
/* extension (off by default) */
#define SSL_ENABLE_DEFLATE 19 /* Enable TLS compression with */
/* DEFLATE (off by default) */
+#define SSL_ENABLE_RENEGOTIATION 20 /* Values below (default: never) */
+#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must use renegotiation */
+ /* extension in ALL handshakes. */
+ /* default: off */
+ /* NOT YET IMPLEMENTED in 3.12.5 */
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
@@ -163,6 +168,16 @@ SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy);
#define SSL_REQUIRE_FIRST_HANDSHAKE ((PRBool)2)
#define SSL_REQUIRE_NO_ERROR ((PRBool)3)
+/* Values for "on" with SSL_ENABLE_RENEGOTIATION */
+/* Never renegotiate at all. */
+#define SSL_RENEGOTIATE_NEVER ((PRBool)0)
+/* Renegotiate without restriction, whether or not the peer's client hello */
+/* bears the renegotiation info extension (like we always did in the past).*/
+#define SSL_RENEGOTIATE_UNRESTRICTED ((PRBool)1)
+/* Only renegotiate if the peer's hello bears the TLS renegotiation_info */
+/* extension. Cannot renegotiate in SSL 3.0 sessions. */
+#define SSL_RENEGOTIATE_REQUIRES_XTN ((PRBool)2) /* (NOT YET IMPLEMENTED) */
+
/*
** Reset the handshake state for fd. This will make the complete SSL
** handshake protocol execute from the ground up on the next i/o
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 8e0947a18..67f04e5be 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -3990,6 +3990,14 @@ ssl3_HandleHelloRequest(sslSocket *ss)
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
return SECFailure;
}
+ if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+ ssl_GetXmitBufLock(ss);
+ rv = SSL3_SendAlert(ss, alert_warning, no_renegotiation);
+ ssl_ReleaseXmitBufLock(ss);
+ PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
+ return SECFailure;
+ }
+
if (sid) {
ss->sec.uncache(sid);
ssl_FreeSID(sid);
@@ -5777,6 +5785,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
SECStatus rv;
int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO;
SSL3AlertDescription desc = illegal_parameter;
+ SSL3AlertLevel level = alert_fatal;
SSL3ProtocolVersion version;
SECItem sidBytes = {siBuffer, NULL, 0};
SECItem suites = {siBuffer, NULL, 0};
@@ -5813,6 +5822,13 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO;
goto alert_loser;
}
+ if (ss->ssl3.hs.ws == idle_handshake &&
+ ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+ desc = no_renegotiation;
+ level = alert_warning;
+ errCode = SSL_ERROR_RENEGOTIATION_NOT_ALLOWED;
+ goto alert_loser;
+ }
tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
if (tmp < 0)
@@ -5820,7 +5836,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
rv = ssl3_NegotiateVersion(ss, version);
if (rv != SECSuccess) {
- desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version : handshake_failure;
+ desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
+ : handshake_failure;
errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
goto alert_loser;
}
@@ -6248,7 +6265,7 @@ alert_loser:
ssl_ReleaseSpecWriteLock(ss);
haveSpecWriteLock = PR_FALSE;
}
- (void)SSL3_SendAlert(ss, alert_fatal, desc);
+ (void)SSL3_SendAlert(ss, level, desc);
/* FALLTHRU */
loser:
if (haveSpecWriteLock) {
@@ -8951,6 +8968,10 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED);
return SECFailure;
}
+ if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
+ PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
+ return SECFailure;
+ }
if (sid && flushCache) {
ss->sec.uncache(sid); /* remove it from whichever cache it's in. */
ssl_FreeSID(sid); /* dec ref count and free if zero. */
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index 751691ada..f55bdf1e5 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -196,6 +196,7 @@ SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 109),
SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET = (SSL_ERROR_BASE + 110),
SSL_ERROR_DECOMPRESSION_FAILURE = (SSL_ERROR_BASE + 111),
+SSL_ERROR_RENEGOTIATION_NOT_ALLOWED = (SSL_ERROR_BASE + 112),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index ebb4d9628..6eb14be04 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -335,6 +335,8 @@ typedef struct sslOptionsStr {
unsigned int noLocks : 1; /* 17 */
unsigned int enableSessionTickets : 1; /* 18 */
unsigned int enableDeflate : 1; /* 19 */
+ unsigned int enableRenegotiation : 2; /* 20-21 */
+ unsigned int requireSafeNegotiation : 1; /* 22 */
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index feb6629be..a945d1f73 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -181,6 +181,8 @@ static sslOptions ssl_defaults = {
PR_FALSE, /* noLocks */
PR_FALSE, /* enableSessionTickets */
PR_FALSE, /* enableDeflate */
+ 0, /* enableRenegotiation (default: never) */
+ PR_FALSE, /* requireSafeNegotiation */
};
sslSessionIDLookupFunc ssl_sid_lookup;
@@ -710,6 +712,14 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
ss->opt.enableDeflate = on;
break;
+ case SSL_ENABLE_RENEGOTIATION:
+ ss->opt.enableRenegotiation = on;
+ break;
+
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ ss->opt.requireSafeNegotiation = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -769,6 +779,10 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
on = ss->opt.enableSessionTickets;
break;
case SSL_ENABLE_DEFLATE: on = ss->opt.enableDeflate; break;
+ case SSL_ENABLE_RENEGOTIATION:
+ on = ss->opt.enableRenegotiation; break;
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ on = ss->opt.requireSafeNegotiation; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -814,6 +828,11 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
on = ssl_defaults.enableSessionTickets;
break;
case SSL_ENABLE_DEFLATE: on = ssl_defaults.enableDeflate; break;
+ case SSL_ENABLE_RENEGOTIATION:
+ on = ssl_defaults.enableRenegotiation; break;
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ on = ssl_defaults.requireSafeNegotiation;
+ break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -949,6 +968,14 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
ssl_defaults.enableDeflate = on;
break;
+ case SSL_ENABLE_RENEGOTIATION:
+ ssl_defaults.enableRenegotiation = on;
+ break;
+
+ case SSL_REQUIRE_SAFE_NEGOTIATION:
+ ssl_defaults.requireSafeNegotiation = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -2093,6 +2120,8 @@ loser:
#define NSS_HAVE_GETENV 1
#endif
+#define LOWER(x) (x | 0x20) /* cheap ToLower function ignores LOCALE */
+
/*
** Create a newsocket structure for a file descriptor.
*/
@@ -2140,6 +2169,32 @@ ssl_NewSocket(PRBool makeLocks)
strcpy(lockStatus + LOCKSTATUS_OFFSET, "FORCED. ");
SSL_TRACE(("SSL: force_locks set to %d", ssl_force_locks));
}
+ ev = getenv("NSS_SSL_ENABLE_RENEGOTIATION");
+ if (ev) {
+ if (ev[0] == '1' || LOWER(ev[0]) == 'u')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_UNRESTRICTED;
+#ifdef LATER
+ /* When SSL_RENEGOTIATE_REQUIRES_XTN is implemented, it will be
+ * the default. Until then, NEVER will be the default.
+ */
+ else if (ev[0] == '0' || LOWER(ev[0]) == 'n')
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER;
+ else
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN;
+#else
+ else
+ ssl_defaults.enableRenegotiation = SSL_RENEGOTIATE_NEVER;
+#endif
+
+ SSL_TRACE(("SSL: enableRenegotiation set to %d",
+ ssl_defaults.enableRenegotiation));
+ }
+ ev = getenv("NSS_SSL_REQUIRE_SAFE_NEGOTIATION");
+ if (ev && ev[0] == '1') {
+ ssl_defaults.requireSafeNegotiation = PR_TRUE;
+ SSL_TRACE(("SSL: requireSafeNegotiation set to %d",
+ PR_TRUE));
+ }
}
#endif /* NSS_HAVE_GETENV */
if (ssl_force_locks)