summaryrefslogtreecommitdiff
path: root/security/nss/lib/ssl/sslcon.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/sslcon.c')
-rw-r--r--security/nss/lib/ssl/sslcon.c181
1 files changed, 105 insertions, 76 deletions
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index 06ec09813..1cfe54220 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -230,7 +230,7 @@ ssl2_ConstructCipherSpecs(sslSocket *ss)
(ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED);
for (i = 0; i < ssl2_NUM_SUITES_IMPLEMENTED * 3; i += 3) {
const PRUint8 * hs = implementedCipherSuites + i;
- int ok = allowed & (1U << hs[0]);
+ unsigned int ok = allowed & (1U << hs[0]);
if (ok) {
cs[0] = hs[0];
cs[1] = hs[1];
@@ -679,7 +679,7 @@ done:
* Acquires and releases the socket's xmitBufLock.
*/
static SECStatus
-ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keySize,
+ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keyBits,
PRUint8 *ca, int caLen,
PRUint8 *ck, int ckLen,
PRUint8 *ek, int ekLen)
@@ -704,8 +704,8 @@ ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keySize,
msg = ss->sec.ci.sendBuf.buf;
msg[0] = SSL_MT_CLIENT_MASTER_KEY;
msg[1] = cipher;
- msg[2] = MSB(keySize);
- msg[3] = LSB(keySize);
+ msg[2] = MSB(keyBits);
+ msg[3] = LSB(keyBits);
msg[4] = MSB(ckLen);
msg[5] = LSB(ckLen);
msg[6] = MSB(ekLen);
@@ -926,8 +926,8 @@ ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
if ((unsigned)rv < (amount + 2)) {
/* Short write. Save the data and return. */
- if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,
- amount + 2 - rv) == SECFailure) {
+ if (ssl_SaveWriteData(ss, out + rv, amount + 2 - rv)
+ == SECFailure) {
count = SECFailure;
} else {
count += amount;
@@ -1023,8 +1023,7 @@ ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
if ((unsigned)rv < buflen) {
/* Short write. Save the data and return. */
- if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,
- buflen - rv) == SECFailure) {
+ if (ssl_SaveWriteData(ss, out + rv, buflen - rv) == SECFailure) {
count = SECFailure;
} else {
count += amount;
@@ -1152,8 +1151,7 @@ ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags)
if (rv < (op - out)) {
/* Short write. Save the data and return. */
- if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv,
- op - out - rv) == SECFailure) {
+ if (ssl_SaveWriteData(ss, out + rv, op - out - rv) == SECFailure) {
count = SECFailure;
} else {
count += amount;
@@ -1581,15 +1579,17 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,
PRUint8 *ek, unsigned int ekLen,
PRUint8 *ca, unsigned int caLen)
{
- PRUint8 *kk = NULL;
+ PRUint8 * dk = NULL; /* decrypted master key */
sslSessionID * sid;
+ sslServerCerts * sc = ss->serverCerts + kt_rsa;
PRUint8 * kbuf = 0; /* buffer for RSA decrypted data. */
- unsigned int el1; /* length of RSA decrypted data in kbuf */
+ unsigned int ddLen; /* length of RSA decrypted data in kbuf */
unsigned int keySize;
- unsigned int modulusLen;
+ unsigned int dkLen; /* decrypted key length in bytes */
+ int modulusLen;
SECStatus rv;
+ PRUint16 allowed; /* cipher kinds enabled and allowed by policy */
PRUint8 mkbuf[SSL_MAX_MASTER_KEY_BYTES];
- sslServerCerts * sc = ss->serverCerts + kt_rsa;
PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
@@ -1597,18 +1597,6 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,
PORT_Assert((ss->sec.ci.sid != 0));
sid = ss->sec.ci.sid;
- keySize = (keyBits + 7) >> 3;
- /* Is the message just way too big? */
- if (keySize > SSL_MAX_MASTER_KEY_BYTES) {
- /* bummer */
- SSL_DBG(("%d: SSL[%d]: keySize=%d ckLen=%d max session key size=%d",
- SSL_GETPID(), ss->fd, keySize, ckLen,
- SSL_MAX_MASTER_KEY_BYTES));
- PORT_SetError(SSL_ERROR_BAD_CLIENT);
- goto loser;
- }
-
-
/* Trying to cut down on all these switch statements that should be tables.
* So, test cipherType once, here, and then use tables below.
*/
@@ -1628,50 +1616,72 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,
goto loser;
}
- /* For export ciphers, make sure they didn't send too much key data. */
+ allowed = ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED;
+ if (!(allowed & (1U << cipher))) {
+ /* client chose a kind we don't allow! */
+ SSL_DBG(("%d: SSL[%d]: disallowed cipher=%d",
+ SSL_GETPID(), ss->fd, cipher));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ keySize = ssl_Specs[cipher].keyLen;
+ if (keyBits != keySize * BPB) {
+ SSL_DBG(("%d: SSL[%d]: invalid master secret key length=%d (bits)!",
+ SSL_GETPID(), ss->fd, keyBits));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
if (ckLen != ssl_Specs[cipher].pubLen) {
- SSL_DBG(("%d: SSL[%d]: odd secret key size, keySize=%d ckLen=%d!",
- SSL_GETPID(), ss->fd, keySize, ckLen));
- /* Somebody tried to sneak by a strange secret key */
+ SSL_DBG(("%d: SSL[%d]: invalid clear key length, ckLen=%d (bytes)!",
+ SSL_GETPID(), ss->fd, ckLen));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ if (caLen != ssl_Specs[cipher].ivLen) {
+ SSL_DBG(("%d: SSL[%d]: invalid key args length, caLen=%d (bytes)!",
+ SSL_GETPID(), ss->fd, caLen));
+ PORT_SetError(SSL_ERROR_BAD_CLIENT);
+ goto loser;
+ }
+
+ modulusLen = PK11_GetPrivateModulusLen(sc->SERVERKEY);
+ if (modulusLen == -1) {
+ /* If the key is bad, then PK11_PubDecryptRaw will fail below. */
+ modulusLen = ekLen;
+ }
+ /* RSA modulus size presently limited to 8k bits maximum */
+ if (ekLen > modulusLen || ekLen > 1024 || ekLen + ckLen < keySize) {
+ SSL_DBG(("%d: SSL[%d]: invalid encrypted key length, ekLen=%d (bytes)!",
+ SSL_GETPID(), ss->fd, ekLen));
PORT_SetError(SSL_ERROR_BAD_CLIENT);
goto loser;
}
/* allocate the buffer to hold the decrypted portion of the key. */
- /* XXX Haven't done any range check on ekLen. */
- kbuf = (PRUint8*) PORT_Alloc(ekLen);
+ kbuf = (PRUint8*)PORT_Alloc(modulusLen);
if (!kbuf) {
goto loser;
}
+ dkLen = keySize - ckLen;
+ dk = kbuf + modulusLen - dkLen;
- /*
- ** Decrypt encrypted half of the key. Note that encrypted half has
- ** been made to match the modulus size of our public key using
- ** PKCS#1. keySize is the real size of the data that is interesting.
+ /* Decrypt encrypted half of the key.
** NOTE: PK11_PubDecryptRaw will barf on a non-RSA key. This is
** desired behavior here.
*/
- rv = PK11_PubDecryptRaw(sc->SERVERKEY, kbuf, &el1, ekLen, ek, ekLen);
+ rv = PK11_PubDecryptRaw(sc->SERVERKEY, kbuf, &ddLen, modulusLen, ek, ekLen);
if (rv != SECSuccess)
goto hide_loser;
- modulusLen = PK11_GetPrivateModulusLen(sc->SERVERKEY);
- if (modulusLen == -1) {
- /* If the key was really bad, then PK11_pubDecryptRaw
- * would have failed, therefore the we must assume that the card
- * is just being a pain and not giving us the modulus... but it
- * should be the same size as the encrypted key length, so use it
- * and keep cranking */
- modulusLen = ekLen;
- }
- /* Is the length of the decrypted data (el1) the expected value? */
- if (modulusLen != el1)
+ /* Is the length of the decrypted data (ddLen) the expected value? */
+ if (modulusLen != ddLen)
goto hide_loser;
/* Cheaply verify that PKCS#1 was used to format the encryption block */
- kk = kbuf + modulusLen - (keySize - ckLen);
- if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (kk[-1] != 0x00)) {
- /* Tsk tsk. */
+ if ((kbuf[0] != 0x00) || (kbuf[1] != 0x02) || (dk[-1] != 0x00)) {
SSL_DBG(("%d: SSL[%d]: strange encryption block",
SSL_GETPID(), ss->fd));
PORT_SetError(SSL_ERROR_BAD_CLIENT);
@@ -1680,10 +1690,10 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits,
/* Make sure we're not subject to a version rollback attack. */
if (ss->opt.enableSSL3 || ss->opt.enableTLS) {
- PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x03 };
+ static const PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03,
+ 0x03, 0x03, 0x03, 0x03 };
- if (PORT_Memcmp(kk - 8 - 1, threes, 8) == 0) {
+ if (PORT_Memcmp(dk - 8 - 1, threes, 8) == 0) {
PORT_SetError(SSL_ERROR_BAD_CLIENT);
goto hide_loser;
}
@@ -1695,10 +1705,7 @@ hide_loser:
* was erroneous. Don't send any error messages.
* Instead, Generate a completely bogus master key .
*/
- PK11_GenerateRandom(kbuf, ekLen);
- if (!kk) {
- kk = kbuf + ekLen - (keySize-ckLen);
- }
+ PK11_GenerateRandom(dk, dkLen);
}
/*
@@ -1707,7 +1714,7 @@ hide_loser:
if (ckLen) {
PORT_Memcpy(mkbuf, ck, ckLen);
}
- PORT_Memcpy(mkbuf+ckLen, kk, keySize-ckLen);
+ PORT_Memcpy(mkbuf + ckLen, dk, dkLen);
/* Fill in session-id */
rv = ssl2_FillInSID(sid, cipher, mkbuf, keySize, ca, caLen,
@@ -1750,6 +1757,8 @@ hide_loser:
* in the first byte, and none of the SSLv2 ciphers do.
*
* Called from ssl2_HandleClientHelloMessage().
+* Returns the number of bytes of "qualified cipher specs",
+* which is typically a multiple of 3, but will be zero if there are none.
*/
static int
ssl2_QualifyCypherSpecs(sslSocket *ss,
@@ -1767,7 +1776,9 @@ ssl2_QualifyCypherSpecs(sslSocket *ss,
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
if (!ss->cipherSpecs) {
- ssl2_ConstructCipherSpecs(ss);
+ SECStatus rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv != SECSuccess || !ss->cipherSpecs)
+ return 0;
}
PRINT_BUF(10, (ss, "specs from client:", cs, csLen));
@@ -1823,19 +1834,23 @@ ssl2_ChooseSessionCypher(sslSocket *ss,
int keySize;
int realKeySize;
PRUint8 * ohs = hs;
+ const PRUint8 * preferred;
+ static const PRUint8 noneSuch[3] = { 0, 0, 0 };
PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
if (!ss->cipherSpecs) {
- ssl2_ConstructCipherSpecs(ss);
+ SECStatus rv = ssl2_ConstructCipherSpecs(ss);
+ if (rv != SECSuccess || !ss->cipherSpecs)
+ goto loser;
}
if (!ss->preferredCipher) {
- const PRUint8 * preferred = implementedCipherSuites;
- unsigned int allowed = ss->allowedByPolicy & ss->chosenPreference &
+ unsigned int allowed = ss->allowedByPolicy & ss->chosenPreference &
SSL_CB_IMPLEMENTED;
if (allowed) {
+ preferred = implementedCipherSuites;
for (i = ssl2_NUM_SUITES_IMPLEMENTED; i > 0; --i) {
if (0 != (allowed & (1U << preferred[0]))) {
ss->preferredCipher = preferred;
@@ -1845,6 +1860,7 @@ ssl2_ChooseSessionCypher(sslSocket *ss,
}
}
}
+ preferred = ss->preferredCipher ? ss->preferredCipher : noneSuch;
/*
** Scan list of ciphers recieved from peer and look for a match in
** our list.
@@ -1857,9 +1873,9 @@ ssl2_ChooseSessionCypher(sslSocket *ss,
bestCypher = -1;
while (--hc >= 0) {
for (i = 0, ms = ss->cipherSpecs; i < ss->sizeCipherSpecs; i += 3, ms += 3) {
- if ((hs[0] == ss->preferredCipher[0]) &&
- (hs[1] == ss->preferredCipher[1]) &&
- (hs[2] == ss->preferredCipher[2]) &&
+ if ((hs[0] == preferred[0]) &&
+ (hs[1] == preferred[1]) &&
+ (hs[2] == preferred[2]) &&
hs[0] != 0) {
/* Pick this cipher immediately! */
*pKeyLen = (((hs[1] << 8) | hs[2]) + 7) >> 3;
@@ -1974,7 +1990,10 @@ ssl_FormatSSL2Block(unsigned modulusLen, SECItem *data)
SECStatus rv;
int i;
- PORT_Assert (data->len <= (modulusLen - (3 + RSA_BLOCK_MIN_PAD_LEN)));
+ if (modulusLen < data->len + (3 + RSA_BLOCK_MIN_PAD_LEN)) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ return NULL;
+ }
block = (unsigned char *) PORT_Alloc(modulusLen);
if (block == NULL)
return NULL;
@@ -3113,7 +3132,16 @@ ssl2_BeginClientHandshake(sslSocket *ss)
return rv;
}
-
+#if defined(NSS_ENABLE_ECC) && !defined(NSS_ECC_MORE_THAN_SUITE_B)
+ /* ensure we don't neogtiate ECC cipher suites with SSL2 hello */
+ ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */
+ if (ss->cipherSpecs != NULL) {
+ PORT_Free(ss->cipherSpecs);
+ ss->cipherSpecs = NULL;
+ ss->sizeCipherSpecs = 0;
+ }
+#endif
+
if (!ss->cipherSpecs) {
rv = ssl2_ConstructCipherSpecs(ss);
if (rv < 0) {
@@ -3207,7 +3235,7 @@ ssl2_HandleClientSessionKeyMessage(sslSocket *ss)
unsigned int caLen;
unsigned int ckLen;
unsigned int ekLen;
- unsigned int keySize;
+ unsigned int keyBits;
int cipher;
SECStatus rv;
@@ -3222,13 +3250,13 @@ ssl2_HandleClientSessionKeyMessage(sslSocket *ss)
goto bad_client;
}
cipher = data[1];
- keySize = (data[2] << 8) | data[3];
+ keyBits = (data[2] << 8) | data[3];
ckLen = (data[4] << 8) | data[5];
ekLen = (data[6] << 8) | data[7];
caLen = (data[8] << 8) | data[9];
- SSL_TRC(5, ("%d: SSL[%d]: session-key, cipher=%d keySize=%d ckLen=%d ekLen=%d caLen=%d",
- SSL_GETPID(), ss->fd, cipher, keySize, ckLen, ekLen, caLen));
+ SSL_TRC(5, ("%d: SSL[%d]: session-key, cipher=%d keyBits=%d ckLen=%d ekLen=%d caLen=%d",
+ SSL_GETPID(), ss->fd, cipher, keyBits, ckLen, ekLen, caLen));
if (ss->gs.recordLen <
SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen + caLen) {
@@ -3238,8 +3266,7 @@ ssl2_HandleClientSessionKeyMessage(sslSocket *ss)
}
/* Use info from client to setup session key */
- /* XXX should validate cipher&keySize are in our array */
- rv = ssl2_ServerSetupSessionCypher(ss, cipher, keySize,
+ rv = ssl2_ServerSetupSessionCypher(ss, cipher, keyBits,
data + SSL_HL_CLIENT_MASTER_KEY_HBYTES, ckLen,
data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen, ekLen,
data + SSL_HL_CLIENT_MASTER_KEY_HBYTES + ckLen + ekLen, caLen);
@@ -3266,7 +3293,8 @@ ssl2_HandleClientSessionKeyMessage(sslSocket *ss)
}
SSL_TRC(5, ("%d: SSL[%d]: server: waiting for elements=0x%d",
- SSL_GETPID(), ss->fd, ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
+ SSL_GETPID(), ss->fd,
+ ss->sec.ci.requiredElements ^ ss->sec.ci.elements));
ss->handshake = ssl_GatherRecord1stHandshake;
ss->nextHandshake = ssl2_HandleMessage;
@@ -3742,7 +3770,8 @@ ssl2_BeginServerHandshake(sslSocket *ss)
ss->sec.rcvSequence = 0;
/* don't turn on SSL2 if we don't have an RSA key and cert */
- if (!rsaAuth->SERVERKEY || !rsaAuth->serverCert) {
+ if (!rsaAuth->serverKeyPair || !rsaAuth->SERVERKEY ||
+ !rsaAuth->serverCert) {
ss->opt.enableSSL2 = PR_FALSE;
}