diff options
author | nelson%bolyard.com <devnull@localhost> | 2009-11-06 20:11:29 +0000 |
---|---|---|
committer | nelson%bolyard.com <devnull@localhost> | 2009-11-06 20:11:29 +0000 |
commit | b3cab804fa9dc23bb0d06ee8500c10534f4dc9be (patch) | |
tree | 6799a20117e95c74e1b679fa8b6c53222763e8c2 | |
parent | 4ae737cb2f8e4855ff7f8fd9953ae5b8244d2cb8 (diff) | |
download | nss-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.h | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl.h | 15 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 25 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslerr.h | 1 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsock.c | 55 |
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) |