summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornelsonb%netscape.com <devnull@localhost>2000-05-24 03:35:23 +0000
committernelsonb%netscape.com <devnull@localhost>2000-05-24 03:35:23 +0000
commit065d4a55f094775d6542b63d76830a2a0770c64f (patch)
tree2c4068a9be4f9972280a07f09dfbc7947d3c1474
parent3dbb48e7be67b2872965c52d8c4cdde166003593 (diff)
downloadnss-hg-065d4a55f094775d6542b63d76830a2a0770c64f.tar.gz
Fix the logic in client and server to detect version roll-back attack,
rolling back from TLS (SSL 3.1) to SSL 3.0. Provide a new SSL socket option to disable roll-back detection in servers, since certain TLS clients are doing it incorrectly.
-rw-r--r--security/nss/lib/ssl/ssl3con.c27
-rw-r--r--security/nss/lib/ssl/sslcon.c11
-rw-r--r--security/nss/lib/ssl/sslimpl.h18
-rw-r--r--security/nss/lib/ssl/sslsock.c30
4 files changed, 59 insertions, 27 deletions
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index d2826ca09..93d5b2773 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -1813,6 +1813,7 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms)
SECItem params;
int keySize;
CK_FLAGS keyFlags;
+ CK_VERSION pms_version;
CK_SSL3_KEY_MAT_PARAMS key_material_params;
CK_SSL3_KEY_MAT_OUT returnedKeys;
CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
@@ -1832,7 +1833,7 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms)
}
if (pms || !pwSpec->master_secret) {
- master_params.pVersion = NULL;
+ master_params.pVersion = &pms_version;
master_params.RandomInfo.pClientRandom = cr;
master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
master_params.RandomInfo.pServerRandom = sr;
@@ -1846,6 +1847,15 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms)
pwSpec->master_secret = PK11_DeriveWithFlags((PK11SymKey *)pms,
master_derive, &params, key_derive,
CKA_DERIVE, 0, keyFlags);
+ if (pwSpec->master_secret != NULL && ss->detectRollBack) {
+ SSL3ProtocolVersion client_version;
+ client_version = pms_version.major << 8 | pms_version.minor;
+ if (client_version != ss->clientHelloVersion) {
+ /* Destroy it. Version roll-back detected. */
+ PK11_FreeSymKey(pwSpec->master_secret);
+ pwSpec->master_secret = NULL;
+ }
+ }
if (pwSpec->master_secret == NULL) {
/* Generate a faux master secret in the same slot as the old one. */
PK11SlotInfo * slot = PK11_GetSlotFromKey((PK11SymKey *)pms);
@@ -2556,7 +2566,8 @@ ssl3_SendClientHello(sslSocket *ss)
return rv; /* err set by ssl3_AppendHandshake* */
}
- rv = ssl3_AppendHandshakeNumber(ss, ss->version, 2);
+ ss->clientHelloVersion = ss->version;
+ rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2);
if (rv != SECSuccess) {
return rv; /* err set by ssl3_AppendHandshake* */
}
@@ -4545,7 +4556,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
if (tmp < 0)
goto loser; /* malformed, alert already sent */
- version = (SSL3ProtocolVersion)tmp;
+ ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp;
rv = ssl3_NegotiateVersion(ss, version);
if (rv != SECSuccess) {
/* We can't do the usual isTLS test here, because the negotiated
@@ -4968,6 +4979,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length)
suite_length = (buffer[3] << 8) | buffer[4];
sid_length = (buffer[5] << 8) | buffer[6];
rand_length = (buffer[7] << 8) | buffer[8];
+ ss->clientHelloVersion = version;
rv = ssl3_NegotiateVersion(ss, version);
if (rv != SECSuccess) {
@@ -5722,8 +5734,8 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
}
/* Generate the pre-master secret ... */
- version.major = MSB(ss->version);
- version.minor = LSB(ss->version);
+ version.major = MSB(ss->clientHelloVersion);
+ version.minor = LSB(ss->clientHelloVersion);
param.data = (unsigned char *)&version;
param.len = sizeof version;
@@ -5777,7 +5789,10 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
}
}
/*
- * decrypt out of the incoming buffer
+ * decrypt pms out of the incoming buffer
+ * Note: CKM_SSL3_PRE_MASTER_KEY_GEN is NOT the mechanism used to do
+ * the unwrap. Rather, it is the mechanism with which the unwrapped
+ * pms will be used.
*/
pms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
CKM_SSL3_PRE_MASTER_KEY_GEN, CKA_DERIVE, 0);
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index 1f3069c5f..16b1c8570 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -3075,16 +3075,15 @@ invalid:
cp = msg = ci->sendBuf.buf;
msg[0] = SSL_MT_CLIENT_HELLO;
if ( ss->enableTLS ) {
- msg[1] = MSB(SSL_LIBRARY_VERSION_3_1_TLS);
- msg[2] = LSB(SSL_LIBRARY_VERSION_3_1_TLS);
+ ss->clientHelloVersion = SSL_LIBRARY_VERSION_3_1_TLS;
} else if ( ss->enableSSL3 ) {
- msg[1] = MSB(SSL_LIBRARY_VERSION_3_0);
- msg[2] = LSB(SSL_LIBRARY_VERSION_3_0);
+ ss->clientHelloVersion = SSL_LIBRARY_VERSION_3_0;
} else {
- msg[1] = MSB(SSL_LIBRARY_VERSION_2);
- msg[2] = LSB(SSL_LIBRARY_VERSION_2);
+ ss->clientHelloVersion = SSL_LIBRARY_VERSION_2;
}
+ msg[1] = MSB(ss->clientHelloVersion);
+ msg[2] = LSB(ss->clientHelloVersion);
msg[3] = MSB(localCipherSize);
msg[4] = LSB(localCipherSize);
msg[5] = MSB(sidLen);
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index db5d7a83b..fe4a68f27 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -222,6 +222,22 @@ typedef struct {
#define ssl_V3_SUITES_IMPLEMENTED 13
+typedef struct sslOptionsStr {
+ unsigned int useSecurity : 1; /* 1 */
+ unsigned int useSocks : 1; /* 2 */
+ unsigned int requestCertificate : 1; /* 3 */
+ unsigned int requireCertificate : 2; /* 4-5 */
+ unsigned int handshakeAsClient : 1; /* 6 */
+ unsigned int handshakeAsServer : 1; /* 7 */
+ unsigned int enableSSL2 : 1; /* 8 */
+ unsigned int enableSSL3 : 1; /* 9 */
+ unsigned int enableTLS : 1; /* 10 */
+ unsigned int noCache : 1; /* 11 */
+ unsigned int fdx : 1; /* 12 */
+ unsigned int v2CompatibleHello : 1; /* 13 */
+ unsigned int detectRollBack : 1; /* 14 */
+} sslOptions;
+
/*
** SSL Socket struct
**
@@ -249,11 +265,13 @@ struct sslSocketStr {
unsigned int noCache : 1;
unsigned int fdx : 1; /* simultaneous read/write threads */
unsigned int v2CompatibleHello : 1; /* Send v3+ client hello in v2 format */
+ unsigned int detectRollBack : 1; /* Detect rollback to SSL v3 */
unsigned int connected : 1; /* initial handshake is complete. */
unsigned int recvdCloseNotify : 1; /* received SSL EOF. */
/* version of the protocol to use */
SSL3ProtocolVersion version;
+ SSL3ProtocolVersion clientHelloVersion; /* version sent in client hello. */
/* Non-zero if socks is enabled */
sslSocksInfo * socks;
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index bafae8554..2921e3b6c 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -145,20 +145,7 @@ sslSocketOps ssl_secure_socks_ops = { /* Both SSL and Socks. */
/*
** default settings for socket enables
*/
-static struct {
- unsigned int useSecurity : 1;
- unsigned int useSocks : 1;
- unsigned int requestCertificate : 1;
- unsigned int requireCertificate : 2;
- unsigned int handshakeAsClient : 1;
- unsigned int handshakeAsServer : 1;
- unsigned int enableSSL2 : 1;
- unsigned int enableSSL3 : 1;
- unsigned int enableTLS : 1;
- unsigned int noCache : 1;
- unsigned int fdx : 1;
- unsigned int v2CompatibleHello : 1;
-} ssl_defaults = {
+static sslOptions ssl_defaults = {
PR_TRUE, /* useSecurity */
PR_FALSE, /* useSocks */
PR_FALSE, /* requestCertificate */
@@ -167,10 +154,11 @@ static struct {
PR_FALSE, /* handshakeAsServer */
PR_TRUE, /* enableSSL2 */
PR_TRUE, /* enableSSL3 */
- PR_FALSE, /* enableTLS */
+ PR_TRUE, /* enableTLS */ /* now defaults to on in NSS 3.0 */
PR_FALSE, /* noCache */
PR_FALSE, /* fdx */
PR_TRUE, /* v2CompatibleHello */
+ PR_TRUE, /* detectRollBack */
};
sslSessionIDLookupFunc ssl_sid_lookup;
@@ -260,6 +248,7 @@ ssl_DupSocket(sslSocket *os)
ss->noCache = os->noCache;
ss->fdx = os->fdx;
ss->v2CompatibleHello = os->v2CompatibleHello;
+ ss->detectRollBack = os->detectRollBack;
ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID);
ss->url = !os->url ? NULL : PORT_Strdup(os->url);
@@ -596,6 +585,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on)
}
break;
+ case SSL_ROLLBACK_DETECTION:
+ ss->detectRollBack = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
@@ -641,6 +634,7 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn)
case SSL_NO_CACHE: on = ss->noCache; break;
case SSL_ENABLE_FDX: on = ss->fdx; break;
case SSL_V2_COMPATIBLE_HELLO: on = ss->v2CompatibleHello; break;
+ case SSL_ROLLBACK_DETECTION: on = ss->detectRollBack; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -678,6 +672,7 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn)
case SSL_NO_CACHE: on = ssl_defaults.noCache; break;
case SSL_ENABLE_FDX: on = ssl_defaults.fdx; break;
case SSL_V2_COMPATIBLE_HELLO: on = ssl_defaults.v2CompatibleHello; break;
+ case SSL_ROLLBACK_DETECTION: on = ssl_defaults.detectRollBack; break;
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -760,6 +755,10 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on)
}
break;
+ case SSL_ROLLBACK_DETECTION:
+ ssl_defaults.detectRollBack = on;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
@@ -1769,6 +1768,7 @@ ssl_NewSocket(void)
ss->enableTLS = ssl_defaults.enableTLS ;
ss->fdx = ssl_defaults.fdx;
ss->v2CompatibleHello = ssl_defaults.v2CompatibleHello;
+ ss->detectRollBack = ssl_defaults.detectRollBack;
ss->peer = 0;
ss->port = 0;
ss->noCache = ssl_defaults.noCache;