diff options
author | nelsonb%netscape.com <devnull@localhost> | 2005-09-09 03:02:16 +0000 |
---|---|---|
committer | nelsonb%netscape.com <devnull@localhost> | 2005-09-09 03:02:16 +0000 |
commit | f59e7526a5d51e013b67fc941834f13ba287c20b (patch) | |
tree | 7baf34aee75ddbbdf41221865b1d72bb47307171 /security/nss | |
parent | 6242fe586becba4948627534d825cec0fc6c3b65 (diff) | |
download | nss-hg-f59e7526a5d51e013b67fc941834f13ba287c20b.tar.gz |
Implement two new SSL socket options: SSL_BYPASS_PKCS11 and SSL_NO_LOCKS.
Reorganize the SSL Socket structure contents to obviate ssl3 pointer.
Move much of the ECC code from ssl3con to new file ssl3ecc.c. derive.c
implements derivation of the SSL/TLS master secret and the encryption and
MAC keys and IVs without using PKCS11. Bug 305147. r=rrelyea.
Modified Files: ssl/config.mk ssl/manifest.mn ssl/ssl.h ssl/ssl3con.c
ssl/ssl3gthr.c ssl/sslauth.c ssl/sslcon.c ssl/ssldef.c ssl/sslgathr.c
ssl/sslimpl.h ssl/sslinfo.c ssl/sslnonce.c ssl/sslsecur.c ssl/sslsnce.c
ssl/sslsock.c
Added Files: ssl/derive.c ssl/ssl3ecc.c
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/lib/ssl/config.mk | 25 | ||||
-rw-r--r-- | security/nss/lib/ssl/derive.c | 481 | ||||
-rw-r--r-- | security/nss/lib/ssl/manifest.mn | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl.h | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 3312 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3ecc.c | 675 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssl3gthr.c | 8 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslauth.c | 6 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslcon.c | 122 | ||||
-rw-r--r-- | security/nss/lib/ssl/ssldef.c | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslgathr.c | 14 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslimpl.h | 237 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslinfo.c | 9 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslnonce.c | 2 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsecur.c | 94 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsnce.c | 14 | ||||
-rw-r--r-- | security/nss/lib/ssl/sslsock.c | 274 |
17 files changed, 3303 insertions, 1980 deletions
diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk index f1d8e31e1..c33d3604f 100644 --- a/security/nss/lib/ssl/config.mk +++ b/security/nss/lib/ssl/config.mk @@ -66,8 +66,32 @@ EXTRA_SHARED_LIBS += \ $(NULL) endif # NS_USE_GCC +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) +CRYPTODIR=../freebl +ifdef MOZILLA_SECURITY_BUILD + CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)crypto.$(LIB_SUFFIX) + CRYPTODIR=../crypto +endif + +EXTRA_LIBS += \ + $(CRYPTOLIB) \ + $(NULL) + else +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) +CRYPTODIR=../freebl +ifdef MOZILLA_SECURITY_BUILD + CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)crypto.$(LIB_SUFFIX) + CRYPTODIR=../crypto +endif + +EXTRA_LIBS += \ + $(CRYPTOLIB) \ + $(NULL) + # $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS) # $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX. @@ -92,6 +116,7 @@ ifeq ($(OS_TARGET),SunOS) # The -R '$ORIGIN' linker option instructs this library to search for its # dependencies in the same directory where it resides. MKSHLIB += -R '$$ORIGIN' +#EXTRA_SHARED_LIBS += -ldl -lrt -lc -z defs endif endif diff --git a/security/nss/lib/ssl/derive.c b/security/nss/lib/ssl/derive.c new file mode 100644 index 000000000..44d5eeb40 --- /dev/null +++ b/security/nss/lib/ssl/derive.c @@ -0,0 +1,481 @@ +/* + * Key Derivation that doesn't use PKCS11 + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* $Id$ */ + +#include "ssl.h" /* prereq to sslimpl.h */ +#include "certt.h" /* prereq to sslimpl.h */ +#include "keythi.h" /* prereq to sslimpl.h */ +#include "sslimpl.h" +#include "blapi.h" + +/* make this a macro! */ +#ifdef NOT_A_MACRO +static void +buildSSLKey(unsigned char * keyBlock, unsigned int keyLen, SECItem * result) +{ + result->type = siBuffer; + result->data = keyBlock; + result->len = keyLen; +} +#else +#define buildSSLKey(keyBlock, keyLen, result) \ +{ \ + (result)->type = siBuffer; \ + (result)->data = keyBlock; \ + (result)->len = keyLen; \ +} +#endif + +/* + * SSL Key generation given pre master secret + */ +#ifndef NUM_MIXERS +#define NUM_MIXERS 9 +#endif +static const char * const mixers[NUM_MIXERS] = { + "A", + "BB", + "CCC", + "DDDD", + "EEEEE", + "FFFFFF", + "GGGGGGG", + "HHHHHHHH", + "IIIIIIIII" +}; + + +SECStatus +ssl3_KeyAndMacDeriveBypass( + ssl3CipherSpec * pwSpec, + const unsigned char * cr, + const unsigned char * sr, + PRBool isTLS, + PRBool isExport) +{ + const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; + unsigned char * key_block = pwSpec->key_block; + unsigned char * key_block2 = NULL; + unsigned int block_bytes = 0; + unsigned int block_needed = 0; + unsigned int i; + unsigned int keySize; /* actual size of cipher keys */ + unsigned int effKeySize; /* effective size of cipher keys */ + unsigned int macSize; /* size of MAC secret */ + unsigned int IVSize; /* size of IV */ + SECStatus rv = SECFailure; + SECStatus status = SECSuccess; + PRBool isFIPS = PR_FALSE; + + SECItem srcr; + SECItem crsr; + + unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; + unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; + PRUint64 md5buf[22]; + PRUint64 shabuf[40]; + +#define md5Ctx ((MD5Context *)md5buf) +#define shaCtx ((SHA1Context *)shabuf) + + static const SECItem zed = { siBuffer, NULL, 0 }; + + if (pwSpec->msItem.data == NULL || + pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return rv; + } + + /* figure out how much is needed */ + macSize = pwSpec->mac_size; + keySize = cipher_def->key_size; + effKeySize = cipher_def->secret_key_size; + IVSize = cipher_def->iv_size; + if (keySize == 0) { + effKeySize = IVSize = 0; /* only MACing */ + } + block_needed = 2 * (macSize + effKeySize + ((!isExport) * IVSize)); + + /* + * clear out our returned keys so we can recover on failure + */ + pwSpec->client.write_key_item = zed; + pwSpec->client.write_mac_key_item = zed; + pwSpec->server.write_key_item = zed; + pwSpec->server.write_mac_key_item = zed; + + /* initialize the server random, client random block */ + srcr.type = siBuffer; + srcr.data = srcrdata; + srcr.len = sizeof srcrdata; + PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH); + PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH); + + /* initialize the client random, server random block */ + crsr.type = siBuffer; + crsr.data = crsrdata; + crsr.len = sizeof crsrdata; + PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); + PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); + + /* + * generate the key material: + */ + if (isTLS) { + SECItem keyblk; + + keyblk.type = siBuffer; + keyblk.data = key_block; + keyblk.len = block_needed; + + status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk, + isFIPS); + if (status != SECSuccess) { + goto key_and_mac_derive_fail; + } + block_bytes = keyblk.len; + } else { + /* key_block = + * MD5(master_secret + SHA('A' + master_secret + + * ServerHello.random + ClientHello.random)) + + * MD5(master_secret + SHA('BB' + master_secret + + * ServerHello.random + ClientHello.random)) + + * MD5(master_secret + SHA('CCC' + master_secret + + * ServerHello.random + ClientHello.random)) + + * [...]; + */ + int made = 0; + for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) { + unsigned int outLen; + unsigned char sha_out[SHA1_LENGTH]; + + SHA1_Begin(shaCtx); + SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1); + SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len); + SHA1_Update(shaCtx, srcr.data, srcr.len); + SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); + PORT_Assert(outLen == SHA1_LENGTH); + + MD5_Begin(md5Ctx); + MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len); + MD5_Update(md5Ctx, sha_out, outLen); + MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); + PORT_Assert(outLen == MD5_LENGTH); + made += MD5_LENGTH; + } + block_bytes = made; + } + PORT_Assert(block_bytes >= block_needed); + PORT_Assert(block_bytes <= sizeof pwSpec->key_block); + + /* + * Put the key material where it goes. + */ + key_block2 = key_block + block_bytes; + i = 0; /* now shows how much consumed */ + + /* + * The key_block is partitioned as follows: + * client_write_MAC_secret[CipherSpec.hash_size] + */ + buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item); + i += macSize; + + /* + * server_write_MAC_secret[CipherSpec.hash_size] + */ + buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item); + i += macSize; + + if (!keySize) { + /* only MACing */ + buildSSLKey(NULL, 0, &pwSpec->client.write_key_item); + buildSSLKey(NULL, 0, &pwSpec->server.write_key_item); + buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item); + buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item); + } else if (!isExport) { + /* + ** Generate Domestic write keys and IVs. + ** client_write_key[CipherSpec.key_material] + */ + buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item); + i += keySize; + + /* + ** server_write_key[CipherSpec.key_material] + */ + buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item); + i += keySize; + + if (IVSize > 0) { + /* + ** client_write_IV[CipherSpec.IV_size] + */ + buildSSLKey(&key_block[i], IVSize, &pwSpec->client.write_iv_item); + i += IVSize; + + /* + ** server_write_IV[CipherSpec.IV_size] + */ + buildSSLKey(&key_block[i], IVSize, &pwSpec->server.write_iv_item); + i += IVSize; + } + PORT_Assert(i <= block_bytes); + + } else if (!isTLS) { + /* + ** Generate SSL3 Export write keys and IVs. + */ + unsigned int outLen; + + /* + ** client_write_key[CipherSpec.key_material] + ** final_client_write_key = MD5(client_write_key + + ** ClientHello.random + ServerHello.random); + */ + MD5_Begin(md5Ctx); + MD5_Update(md5Ctx, &key_block[i], effKeySize); + MD5_Update(md5Ctx, crsr.data, crsr.len); + MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); + i += effKeySize; + buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item); + key_block2 += keySize; + + /* + ** server_write_key[CipherSpec.key_material] + ** final_server_write_key = MD5(server_write_key + + ** ServerHello.random + ClientHello.random); + */ + MD5_Begin(md5Ctx); + MD5_Update(md5Ctx, &key_block[i], effKeySize); + MD5_Update(md5Ctx, srcr.data, srcr.len); + MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); + i += effKeySize; + buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item); + key_block2 += keySize; + PORT_Assert(i <= block_bytes); + + if (IVSize) { + /* + ** client_write_IV = + ** MD5(ClientHello.random + ServerHello.random); + */ + MD5_Begin(md5Ctx); + MD5_Update(md5Ctx, crsr.data, crsr.len); + MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); + buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item); + key_block2 += IVSize; + + /* + ** server_write_IV = + ** MD5(ServerHello.random + ClientHello.random); + */ + MD5_Begin(md5Ctx); + MD5_Update(md5Ctx, srcr.data, srcr.len); + MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH); + buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item); + key_block2 += IVSize; + } + + PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); + } else { + /* + ** Generate TLS Export write keys and IVs. + */ + SECItem secret ; + SECItem keyblk ; + + secret.type = siBuffer; + keyblk.type = siBuffer; + /* + ** client_write_key[CipherSpec.key_material] + ** final_client_write_key = PRF(client_write_key, + ** "client write key", + ** client_random + server_random); + */ + secret.data = &key_block[i]; + secret.len = effKeySize; + i += effKeySize; + keyblk.data = key_block2; + keyblk.len = keySize; + status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS); + if (status != SECSuccess) { + goto key_and_mac_derive_fail; + } + buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item); + key_block2 += keySize; + + /* + ** server_write_key[CipherSpec.key_material] + ** final_server_write_key = PRF(server_write_key, + ** "server write key", + ** client_random + server_random); + */ + secret.data = &key_block[i]; + secret.len = effKeySize; + i += effKeySize; + keyblk.data = key_block2; + keyblk.len = keySize; + status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS); + if (status != SECSuccess) { + goto key_and_mac_derive_fail; + } + buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item); + key_block2 += keySize; + + /* + ** iv_block = PRF("", "IV block", client_random + server_random); + ** client_write_IV[SecurityParameters.IV_size] + ** server_write_IV[SecurityParameters.IV_size] + */ + if (IVSize) { + secret.data = NULL; + secret.len = 0; + keyblk.data = key_block2; + keyblk.len = 2 * IVSize; + status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS); + if (status != SECSuccess) { + goto key_and_mac_derive_fail; + } + buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item); + buildSSLKey(key_block2 + IVSize, IVSize, &pwSpec->server.write_iv_item); + key_block2 += 2 * IVSize; + } + PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block); + } + rv = SECSuccess; + +key_and_mac_derive_fail: + + MD5_DestroyContext(md5Ctx, PR_FALSE); + SHA1_DestroyContext(shaCtx, PR_FALSE); + + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + } + + return rv; +} + + +/* derive the Master Secret from the PMS */ +/* Presently, this is only done wtih RSA PMS, os isRSA is always true. */ +SECStatus +ssl3_MasterKeyDeriveBypass( + ssl3CipherSpec * pwSpec, + const unsigned char * cr, + const unsigned char * sr, + const SECItem * pms, + PRBool isTLS, + PRBool isRSA) +{ + unsigned char * key_block = pwSpec->key_block; + SECStatus rv = SECSuccess; + PRBool isFIPS = PR_FALSE; + + SECItem crsr; + + unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; + PRUint64 md5buf[22]; + PRUint64 shabuf[40]; + +#define md5Ctx ((MD5Context *)md5buf) +#define shaCtx ((SHA1Context *)shabuf) + + /* first do the consistancy checks */ + if (isRSA) { + PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH); + if (pms->len != SSL3_RSA_PMS_LENGTH) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + /* test PMS version for rollback here? or in caller? */ + } + + /* initialize the client random, server random block */ + crsr.type = siBuffer; + crsr.data = crsrdata; + crsr.len = sizeof crsrdata; + PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH); + PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH); + + /* finally do the key gen */ + if (isTLS) { + SECItem master = { siBuffer, NULL, 0 }; + + master.data = key_block; + master.len = SSL3_MASTER_SECRET_LENGTH; + + rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + } + } else { + int i; + int made = 0; + for (i = 0; i < 3; i++) { + unsigned int outLen; + unsigned char sha_out[SHA1_LENGTH]; + + SHA1_Begin(shaCtx); + SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1); + SHA1_Update(shaCtx, pms->data, pms->len); + SHA1_Update(shaCtx, crsr.data, crsr.len); + SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH); + PORT_Assert(outLen == SHA1_LENGTH); + + MD5_Begin(md5Ctx); + MD5_Update(md5Ctx, pms->data, pms->len); + MD5_Update(md5Ctx, sha_out, outLen); + MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH); + PORT_Assert(outLen == MD5_LENGTH); + made += outLen; + } + } + + /* store the results */ + PORT_Memcpy(pwSpec->raw_master_secret, key_block, + SSL3_MASTER_SECRET_LENGTH); + pwSpec->msItem.data = pwSpec->raw_master_secret; + pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH; + + return rv; +} + + diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index f49a8e038..6428ce5c7 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -55,6 +55,7 @@ MODULE = nss MAPFILE = $(OBJDIR)/ssl.def CSRCS = \ + derive.c \ emulate.c \ prelib.c \ ssl3con.c \ @@ -77,14 +78,13 @@ CSRCS = \ cmpcert.c \ nsskea.c \ sslinfo.c \ + ssl3ecc.c \ $(NULL) - -REQUIRES = dbm - ifdef NSS_ENABLE_ECC DEFINES += -DNSS_ENABLE_ECC endif LIBRARY_NAME = ssl LIBRARY_VERSION = 3 + diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index e22c70504..6c0a16d4b 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -110,6 +110,8 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd); /* if step-down keys are needed. */ /* default: off, generate */ /* step-down keys if needed. */ +#define SSL_BYPASS_PKCS11 16 /* use PKCS#11 for pub key only */ +#define SSL_NO_LOCKS 17 /* Don't use locks for protection */ #ifdef SSL_DEPRECATED_FUNCTION /* Old deprecated function names */ diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 669060bc2..6b64e441d 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -62,6 +62,7 @@ #include "secmod.h" #include "nsslocks.h" #include "ec.h" +#include "blapi.h" #include <stdio.h> @@ -70,10 +71,11 @@ (x)->pValue=(v); (x)->ulValueLen = (l); #endif -static void ssl3_CleanupPeerCerts(ssl3State *ssl3); +static void ssl3_CleanupPeerCerts(sslSocket *ss); static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, PK11SlotInfo * serverKeySlot); -static SECStatus ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms); +static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, const PK11SymKey *pms); +static SECStatus ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss); static SECStatus ssl3_HandshakeFailure( sslSocket *ss); static SECStatus ssl3_InitState( sslSocket *ss); static sslSessionID *ssl3_NewSessionID( sslSocket *ss, PRBool is_server); @@ -181,11 +183,6 @@ static const /*SSL3ClientCertificateType */ uint8 certificate_types [] = { */ #define SSL3_BUFFER_FUDGE 100 -#define SET_ERROR_CODE /* reminder */ -#define SEND_ALERT /* reminder */ -#define TEST_FOR_FAILURE /* reminder */ -#define DEAL_WITH_FAILURE /* reminder */ - #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */ @@ -398,108 +395,6 @@ const char * const ssl3_cipherName[] = { "missing" }; -#ifdef NSS_ENABLE_ECC -/* Types and names of elliptic curves used in TLS */ -typedef enum { ec_type_explicitPrime = 1, - ec_type_explicitChar2Curve, - ec_type_named -} ECType; - -typedef enum { ec_noName = 0, - ec_sect163k1, ec_sect163r1, ec_sect163r2, - ec_sect193r1, ec_sect193r2, ec_sect233k1, - ec_sect233r1, ec_sect239k1, ec_sect283k1, - ec_sect283r1, ec_sect409k1, ec_sect409r1, - ec_sect571k1, ec_sect571r1, ec_secp160k1, - ec_secp160r1, ec_secp160r2, ec_secp192k1, - ec_secp192r1, ec_secp224k1, ec_secp224r1, - ec_secp256k1, ec_secp256r1, ec_secp384r1, - ec_secp521r1, - ec_pastLastName -} ECName; - -#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName)) - -/* Table containing OID tags for elliptic curves named in the - * ECC-TLS IETF draft. - */ -static const SECOidTag ecName2OIDTag[] = { - 0, - SEC_OID_SECG_EC_SECT163K1, /* 1 */ - SEC_OID_SECG_EC_SECT163R1, /* 2 */ - SEC_OID_SECG_EC_SECT163R2, /* 3 */ - SEC_OID_SECG_EC_SECT193R1, /* 4 */ - SEC_OID_SECG_EC_SECT193R2, /* 5 */ - SEC_OID_SECG_EC_SECT233K1, /* 6 */ - SEC_OID_SECG_EC_SECT233R1, /* 7 */ - SEC_OID_SECG_EC_SECT239K1, /* 8 */ - SEC_OID_SECG_EC_SECT283K1, /* 9 */ - SEC_OID_SECG_EC_SECT283R1, /* 10 */ - SEC_OID_SECG_EC_SECT409K1, /* 11 */ - SEC_OID_SECG_EC_SECT409R1, /* 12 */ - SEC_OID_SECG_EC_SECT571K1, /* 13 */ - SEC_OID_SECG_EC_SECT571R1, /* 14 */ - SEC_OID_SECG_EC_SECP160K1, /* 15 */ - SEC_OID_SECG_EC_SECP160R1, /* 16 */ - SEC_OID_SECG_EC_SECP160R2, /* 17 */ - SEC_OID_SECG_EC_SECP192K1, /* 18 */ - SEC_OID_SECG_EC_SECP192R1, /* 19 */ - SEC_OID_SECG_EC_SECP224K1, /* 20 */ - SEC_OID_SECG_EC_SECP224R1, /* 21 */ - SEC_OID_SECG_EC_SECP256K1, /* 22 */ - SEC_OID_SECG_EC_SECP256R1, /* 23 */ - SEC_OID_SECG_EC_SECP384R1, /* 24 */ - SEC_OID_SECG_EC_SECP521R1, /* 25 */ -}; - -static SECStatus -ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params) -{ - SECOidData *oidData = NULL; - - if ((curve <= ec_noName) || (curve >= ec_pastLastName) || - ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) { - PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - return SECFailure; - } - - SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)); - /* - * params->data needs to contain the ASN encoding of an object ID (OID) - * representing the named curve. The actual OID is in - * oidData->oid.data so we simply prepend 0x06 and OID length - */ - params->data[0] = SEC_ASN1_OBJECT_ID; - params->data[1] = oidData->oid.len; - memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); - - return SECSuccess; -} - -static ECName -params2ecName(SECKEYECParams * params) -{ - SECItem oid = { siBuffer, NULL, 0}; - SECOidData *oidData = NULL; - ECName i; - - /* - * params->data needs to contain the ASN encoding of an object ID (OID) - * representing a named curve. Here, we strip away everything - * before the actual OID and use the OID to look up a named curve. - */ - if (params->data[0] != SEC_ASN1_OBJECT_ID) return ec_noName; - oid.len = params->len - 2; - oid.data = params->data + 2; - if ((oidData = SECOID_FindOID(&oid)) == NULL) return ec_noName; - for (i = ec_noName + 1; i < ec_pastLastName; i++) { - if (ecName2OIDTag[i] == oidData->offset) - return i; - } - - return ec_noName; -} -#endif /* NSS_ENABLE_ECC */ #if defined(TRACE) @@ -609,7 +504,7 @@ ssl3_config_match_init(sslSocket *ss) PRBool isServer; sslServerCerts *svrAuth; - if (!ss->enableSSL3 && !ss->enableTLS) { + if (!ss->opt.enableSSL3 && !ss->opt.enableTLS) { return 0; } isServer = (PRBool)( ss && ss->sec.isServer ); @@ -662,7 +557,7 @@ ssl3_config_match_init(sslSocket *ss) /* Mark the suites that are backed by real tokens, certs and keys */ suite->isPresent = (PRBool) (((exchKeyType == kt_null) || - ((!isServer || (svrAuth->serverKey && + ((!isServer || (svrAuth->SERVERKEY && svrAuth->serverCertChain)) && PK11_TokenExists(kea_alg_defs[exchKeyType]))) && ((cipher_alg == calg_null) || PK11_TokenExists(cipher_mech))); @@ -704,7 +599,7 @@ count_cipher_suites(sslSocket *ss, int policy, PRBool enabled) { int i, count = 0; - if (!ss->enableSSL3 && !ss->enableTLS) { + if (!ss->opt.enableSSL3 && !ss->opt.enableTLS) { return 0; } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { @@ -722,7 +617,7 @@ anyRestrictedEnabled(sslSocket *ss) { int i; - if (!ss->enableSSL3 && !ss->enableTLS) { + if (!ss->opt.enableSSL3 && !ss->opt.enableTLS) { return PR_FALSE; } for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { @@ -749,7 +644,6 @@ Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, return SECSuccess; } - /* * SSL3 Utility functions */ @@ -760,21 +654,21 @@ ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion) SSL3ProtocolVersion version; SSL3ProtocolVersion maxVersion; - if (ss->enableTLS) { + if (ss->opt.enableTLS) { maxVersion = SSL_LIBRARY_VERSION_3_1_TLS; - } else if (ss->enableSSL3) { + } else if (ss->opt.enableSSL3) { maxVersion = SSL_LIBRARY_VERSION_3_0; } else { /* what are we doing here? */ - PORT_Assert(ss->enableSSL3 || ss->enableTLS); + PORT_Assert(ss->opt.enableSSL3 || ss->opt.enableTLS); PORT_SetError(SSL_ERROR_SSL_DISABLED); return SECFailure; } ss->version = version = PR_MIN(maxVersion, peerVersion); - if ((version == SSL_LIBRARY_VERSION_3_1_TLS && ss->enableTLS) || - (version == SSL_LIBRARY_VERSION_3_0 && ss->enableSSL3)) { + if ((version == SSL_LIBRARY_VERSION_3_1_TLS && ss->opt.enableTLS) || + (version == SSL_LIBRARY_VERSION_3_0 && ss->opt.enableSSL3)) { return SECSuccess; } @@ -802,7 +696,8 @@ ssl3_GetNewRandom(SSL3Random *random) return rv; } -static SECStatus +/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */ +SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, PRBool isTLS) { @@ -871,8 +766,8 @@ done: return rv; } - -static SECStatus +/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */ +SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, SECItem *buf, PRBool isTLS, void *pwArg) { @@ -959,17 +854,49 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, /* Caller must set hiLevel error code. */ +/* Called from ssl3_ComputeExportRSAKeyHash + * ssl3_ComputeDHKeyHash + * which are called from ssl3_HandleServerKeyExchange. + */ +SECStatus +ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, unsigned int bufLen, + SSL3Hashes *hashes, PRBool bypassPKCS11) +{ + SECStatus rv = SECSuccess; + + if (bypassPKCS11) { + MD5_HashBuf (hashes->md5, hashBuf, bufLen); + SHA1_HashBuf(hashes->sha, hashBuf, bufLen); + } else { + rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + rv = SECFailure; + goto done; + } + + rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + rv = SECFailure; + } + } +done: + return rv; +} + +/* Caller must set hiLevel error code. +** Called from ssl3_SendServerKeyExchange and +** ssl3_HandleServerKeyExchange. +*/ static SECStatus ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes) + SSL3Hashes *hashes, PRBool bypassPKCS11) { - PK11Context * md5 = NULL; - PK11Context * sha = NULL; PRUint8 * hashBuf; PRUint8 * pBuf; SECStatus rv = SECSuccess; - unsigned int outLen; unsigned int bufLen; PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 4096/8 + 2 + 4096/8]; @@ -983,19 +910,6 @@ ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, } } - md5 = PK11_CreateDigestContext(SEC_OID_MD5); - if (md5 == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; /* Caller must set hiLevel error code. */ - goto done; - } - sha = PK11_CreateDigestContext(SEC_OID_SHA1); - if (sha == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; /* Caller must set hiLevel error code. */ - goto done; - } - memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); pBuf = hashBuf + SSL3_RANDOM_LENGTH; memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); @@ -1012,50 +926,27 @@ ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent, pBuf += publicExponent.len; PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - rv = PK11_DigestBegin(md5); - rv |= PK11_DigestOp(md5, hashBuf, bufLen); - rv |= PK11_DigestFinal(md5, hashes->md5, &outLen, MD5_LENGTH); - PORT_Assert(rv != SECSuccess || outLen == MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } - - rv = PK11_DigestBegin(sha); - rv |= PK11_DigestOp(sha, hashBuf, bufLen); - rv |= PK11_DigestFinal(sha, hashes->sha, &outLen, SHA1_LENGTH); - PORT_Assert(rv != SECSuccess || outLen == SHA1_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } + rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen)); PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", hashes->md5, MD5_LENGTH)); PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); -done: - if (md5 != NULL) PK11_DestroyContext(md5, PR_TRUE); - if (sha != NULL) PK11_DestroyContext(sha, PR_TRUE); if (hashBuf != buf && hashBuf != NULL) PORT_Free(hashBuf); return rv; } /* Caller must set hiLevel error code. */ +/* Called from ssl3_HandleServerKeyExchange. */ static SECStatus ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes) + SSL3Hashes *hashes, PRBool bypassPKCS11) { - PK11Context * md5 = NULL; - PK11Context * sha = NULL; PRUint8 * hashBuf; PRUint8 * pBuf; SECStatus rv = SECSuccess; - unsigned int outLen; unsigned int bufLen; PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 4096/8 + 2 + 4096/8]; @@ -1069,19 +960,6 @@ ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, } } - md5 = PK11_CreateDigestContext(SEC_OID_MD5); - if (md5 == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; /* Caller must set hiLevel error code. */ - goto done; - } - sha = PK11_CreateDigestContext(SEC_OID_SHA1); - if (sha == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; /* Caller must set hiLevel error code. */ - goto done; - } - memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); pBuf = hashBuf + SSL3_RANDOM_LENGTH; memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); @@ -1103,105 +981,17 @@ ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys, pBuf += dh_Ys.len; PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - rv = PK11_DigestBegin(md5); - rv |= PK11_DigestOp(md5, hashBuf, bufLen); - rv |= PK11_DigestFinal(md5, hashes->md5, &outLen, MD5_LENGTH); - PORT_Assert(rv != SECSuccess || outLen == MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } - - rv = PK11_DigestBegin(sha); - rv |= PK11_DigestOp(sha, hashBuf, bufLen); - rv |= PK11_DigestFinal(sha, hashes->sha, &outLen, SHA1_LENGTH); - PORT_Assert(rv != SECSuccess || outLen == SHA1_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } + rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen)); PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); -done: - if (md5 != NULL) PK11_DestroyContext(md5, PR_TRUE); - if (sha != NULL) PK11_DestroyContext(sha, PR_TRUE); if (hashBuf != buf && hashBuf != NULL) PORT_Free(hashBuf); return rv; } -#ifdef NSS_ENABLE_ECC -/* Caller must set hiLevel error code. */ -static SECStatus -ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, - SSL3Random *client_rand, SSL3Random *server_rand, - SSL3Hashes *hashes) -{ - PRUint8 * hashBuf; - PRUint8 * pBuf; - SECStatus rv = SECSuccess; - unsigned int bufLen; - /* - * XXX For now, we only support named curves (the appropriate - * checks are made before this method is called) so ec_params - * takes up only two bytes. ECPoint needs to fit in 256 bytes - * (because the spec says the length must fit in one byte) - */ - PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 1 + 256]; - - bufLen = 2*SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len; - if (bufLen <= sizeof buf) { - hashBuf = buf; - } else { - hashBuf = PORT_Alloc(bufLen); - if (!hashBuf) { - return SECFailure; - } - } - - memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); - pBuf = hashBuf + SSL3_RANDOM_LENGTH; - memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); - pBuf += SSL3_RANDOM_LENGTH; - memcpy(pBuf, ec_params.data, ec_params.len); - pBuf += ec_params.len; - pBuf[0] = (PRUint8)(server_ecpoint.len); - pBuf += 1; - memcpy(pBuf, server_ecpoint.data, server_ecpoint.len); - pBuf += server_ecpoint.len; - PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); - - rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } - - rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto done; - } - - PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); - PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); - -done: - if (hashBuf != buf && hashBuf != NULL) - PORT_Free(hashBuf); - return rv; -} -#endif /* NSS_ENABLE_ECC */ - - static void ssl3_BumpSequenceNumber(SSL3SequenceNumber *num) { @@ -1210,7 +1000,7 @@ ssl3_BumpSequenceNumber(SSL3SequenceNumber *num) num->high++; } -/* Called only from ssl3_DestroyCipherSpec (immediately below). */ +/* Called twice, only from ssl3_DestroyCipherSpec (immediately below). */ static void ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) { @@ -1228,18 +1018,19 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) } } -/* Called from ssl3_SendChangeCipherSpecs() and ssl3_HandleChangeCipherSpecs() +/* Called from ssl3_SendChangeCipherSpecs() and +** ssl3_HandleChangeCipherSpecs() +** ssl3_DestroySSL3Info ** Caller must hold SpecWriteLock. */ static void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec) { - -/* PORT_Assert( ssl_HaveSpecWriteLock(ss)); Don't have ss! */ - + PRBool freeit = (PRBool)(!spec->bypassCiphers); +/* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ if (spec->destroy) { - spec->destroy(spec->encodeContext,PR_TRUE); - spec->destroy(spec->decodeContext,PR_TRUE); + spec->destroy(spec->encodeContext, freeit); + spec->destroy(spec->decodeContext, freeit); spec->encodeContext = NULL; /* paranoia */ spec->decodeContext = NULL; } @@ -1247,36 +1038,41 @@ ssl3_DestroyCipherSpec(ssl3CipherSpec *spec) PK11_FreeSymKey(spec->master_secret); spec->master_secret = NULL; } + spec->msItem.data = NULL; + spec->msItem.len = 0; ssl3_CleanupKeyMaterial(&spec->client); ssl3_CleanupKeyMaterial(&spec->server); + spec->bypassCiphers = PR_FALSE; spec->destroy=NULL; } -/* Called from ssl3_HandleServerHello(), ssl3_SendServerHello() +/* Fill in the pending cipher spec with info from the selected ciphersuite. +** This is as much initialization as we can do without having key material. +** Called from ssl3_HandleServerHello(), ssl3_SendServerHello() ** Caller must hold the ssl3 handshake lock. ** Acquires & releases SpecWriteLock. */ static SECStatus -ssl3_SetupPendingCipherSpec(sslSocket *ss, ssl3State *ssl3) +ssl3_SetupPendingCipherSpec(sslSocket *ss) { ssl3CipherSpec * pwSpec; ssl3CipherSpec * cwSpec; - ssl3CipherSuite suite = ssl3->hs.cipher_suite; + ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite; SSL3MACAlgorithm mac; SSL3BulkCipher cipher; SSL3KeyExchangeAlgorithm kea; const ssl3CipherSuiteDef *suite_def; PRBool isTLS; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); ssl_GetSpecWriteLock(ss); /*******************************/ - pwSpec = ssl3->pwSpec; - PORT_Assert(pwSpec == ssl3->prSpec); + pwSpec = ss->ssl3.pwSpec; + PORT_Assert(pwSpec == ss->ssl3.prSpec); /* This hack provides maximal interoperability with SSL 3 servers. */ - cwSpec = ss->ssl3->cwSpec; + cwSpec = ss->ssl3.cwSpec; if (cwSpec->mac_def->mac == mac_null) { /* SSL records are not being MACed. */ cwSpec->version = ss->version; @@ -1301,9 +1097,9 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, ssl3State *ssl3) if (isTLS) mac += 2; - ssl3->hs.suite_def = suite_def; - ssl3->hs.kea_def = &kea_defs[kea]; - PORT_Assert(ssl3->hs.kea_def->kea == kea); + ss->ssl3.hs.suite_def = suite_def; + ss->ssl3.hs.kea_def = &kea_defs[kea]; + PORT_Assert(ss->ssl3.hs.kea_def->kea == kea); pwSpec->cipher_def = &bulk_cipher_defs[cipher]; PORT_Assert(pwSpec->cipher_def->cipher == cipher); @@ -1311,7 +1107,6 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, ssl3State *ssl3) pwSpec->mac_def = &mac_defs[mac]; PORT_Assert(pwSpec->mac_def->mac == mac); - ss->sec.keyBits = pwSpec->cipher_def->key_size * BPB; ss->sec.secretKeyBits = pwSpec->cipher_def->secret_key_size * BPB; ss->sec.cipherType = cipher; @@ -1325,83 +1120,233 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss, ssl3State *ssl3) return SECSuccess; } -/* - * Called from: ssl3_SendClientKeyExchange (for Full handshake) - * ssl3_HandleClientKeyExchange (for Full handshake) - * ssl3_HandleServerHello (for session restart) - * ssl3_HandleClientHello (for session restart) - * Sets error code, but caller probably should override to disambiguate. - * NULL pms means re-use old master_secret. +/* Initialize encryption and MAC contexts for pending spec. + * Master Secret already is derived in spec->msItem + * Caller holds Spec write lock. */ static SECStatus -ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) +ssl3_InitPendingContextsBypass(sslSocket *ss) { ssl3CipherSpec * pwSpec; const ssl3BulkCipherDef *cipher_def; - PK11Context * serverContext = NULL; - PK11Context * clientContext = NULL; - SECItem * param; + void * serverContext = NULL; + void * clientContext = NULL; + BLapiInitContextFunc initFn = (BLapiInitContextFunc)NULL; + int mode = 0; + unsigned int optArg1 = 0; + unsigned int optArg2 = 0; + PRBool server_encrypts = ss->sec.isServer; CK_ULONG macLength; SSLCipherAlgorithm calg; SECStatus rv; + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); + + pwSpec = ss->ssl3.pwSpec; + cipher_def = pwSpec->cipher_def; + macLength = pwSpec->mac_size; + + /* MAC setup is done when computing the mac, not here. + * Now setup the crypto contexts. + */ + + calg = cipher_def->calg; + + serverContext = pwSpec->server.cipher_context; + clientContext = pwSpec->client.cipher_context; + + switch (calg) { + case ssl_calg_null: + pwSpec->encode = Null_Cipher; + pwSpec->decode = Null_Cipher; + pwSpec->destroy = NULL; + goto success; + + case ssl_calg_rc4: + initFn = (BLapiInitContextFunc)RC4_InitContext; + pwSpec->encode = (SSLCipher) RC4_Encrypt; + pwSpec->decode = (SSLCipher) RC4_Decrypt; + pwSpec->destroy = (SSLDestroy) RC4_DestroyContext; + break; + case ssl_calg_rc2: + initFn = (BLapiInitContextFunc)RC2_InitContext; + mode = NSS_RC2_CBC; + optArg1 = cipher_def->key_size; + pwSpec->encode = (SSLCipher) RC2_Encrypt; + pwSpec->decode = (SSLCipher) RC2_Decrypt; + pwSpec->destroy = (SSLDestroy) RC2_DestroyContext; + break; + case ssl_calg_des: + initFn = (BLapiInitContextFunc)DES_InitContext; + mode = NSS_DES_CBC; + optArg1 = server_encrypts; + pwSpec->encode = (SSLCipher) DES_Encrypt; + pwSpec->decode = (SSLCipher) DES_Decrypt; + pwSpec->destroy = (SSLDestroy) DES_DestroyContext; + break; + case ssl_calg_3des: + initFn = (BLapiInitContextFunc)DES_InitContext; + mode = NSS_DES_EDE3_CBC; + optArg1 = server_encrypts; + pwSpec->encode = (SSLCipher) DES_Encrypt; + pwSpec->decode = (SSLCipher) DES_Decrypt; + pwSpec->destroy = (SSLDestroy) DES_DestroyContext; + break; + case ssl_calg_aes: + initFn = (BLapiInitContextFunc)AES_InitContext; + mode = NSS_AES_CBC; + optArg1 = server_encrypts; + optArg2 = AES_BLOCK_SIZE; + pwSpec->encode = (SSLCipher) AES_Encrypt; + pwSpec->decode = (SSLCipher) AES_Decrypt; + pwSpec->destroy = (SSLDestroy) AES_DestroyContext; + break; + + case ssl_calg_idea: + case ssl_calg_fortezza : + default: + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto bail_out; + } + rv = (*initFn)(serverContext, + pwSpec->server.write_key_item.data, + pwSpec->server.write_key_item.len, + pwSpec->server.write_iv_item.data, + mode, optArg1, optArg2); + if (rv != SECSuccess) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto bail_out; + } + + if (calg == ssl_calg_des || calg == ssl_calg_3des || calg == ssl_calg_aes) { + /* For block ciphers, if the server is encrypting, then the client + * is decrypting, and vice versa. + */ + optArg1 = !optArg1; + } + + rv = (*initFn)(clientContext, + pwSpec->client.write_key_item.data, + pwSpec->client.write_key_item.len, + pwSpec->client.write_iv_item.data, + mode, optArg1, optArg2); + if (rv != SECSuccess) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto bail_out; + } + + pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext; + pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext; + +success: + return SECSuccess; + +bail_out: + return SECFailure; +} + +/* This function should probably be moved to pk11wrap and be named + * PK11_ParamFromIVAndEffectiveKeyBits + */ +static SECItem * +ssl3_ParamFromIV(CK_MECHANISM_TYPE mtype, SECItem *iv, CK_ULONG ulEffectiveBits) +{ + SECItem * param = PK11_ParamFromIV(mtype, iv); + if (param && param->data && param->len >= sizeof(CK_RC2_PARAMS)) { + switch (mtype) { + case CKM_RC2_KEY_GEN: + case CKM_RC2_ECB: + case CKM_RC2_CBC: + case CKM_RC2_MAC: + case CKM_RC2_MAC_GENERAL: + case CKM_RC2_CBC_PAD: + *(CK_RC2_PARAMS *)param->data = ulEffectiveBits; + default: break; + } + } + return param; +} + +/* Initialize encryption and MAC contexts for pending spec. + * Master Secret already is derived. + * Caller holds Spec write lock. + */ +static SECStatus +ssl3_InitPendingContextsPKCS11(sslSocket *ss) +{ + ssl3CipherSpec * pwSpec; +const ssl3BulkCipherDef *cipher_def; + PK11Context * serverContext = NULL; + PK11Context * clientContext = NULL; + SECItem * param; CK_MECHANISM_TYPE mechanism; CK_MECHANISM_TYPE mac_mech; + CK_ULONG macLength; + CK_ULONG effKeyBits; SECItem iv; SECItem mac_param; + SSLCipherAlgorithm calg; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - ssl_GetSpecWriteLock(ss); /**************************************/ + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); - PORT_Assert(ss->ssl3->prSpec == ss->ssl3->pwSpec); - - pwSpec = ss->ssl3->pwSpec; + pwSpec = ss->ssl3.pwSpec; cipher_def = pwSpec->cipher_def; macLength = pwSpec->mac_size; - /* generate session keys from pms (if pms is not NULL) or ms */ - rv = ssl3_GenerateSessionKeys(ss, pms); - if (rv != SECSuccess) { - goto bail_out; /* err code set by ssl3_GenerateSessionKeys */ - } + /* + ** Now setup the MAC contexts, + ** crypto contexts are setup below. + */ pwSpec->client.write_mac_context = NULL; pwSpec->server.write_mac_context = NULL; - + mac_mech = pwSpec->mac_def->mmech; mac_param.data = (unsigned char *)&macLength; mac_param.len = sizeof(macLength); mac_param.type = 0; - mac_mech = pwSpec->mac_def->mmech; - if (cipher_def->calg == calg_null) { - pwSpec->encode = Null_Cipher; - pwSpec->decode = Null_Cipher; - pwSpec->destroy = NULL; - pwSpec->client.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->client.write_mac_key, &mac_param); - if (pwSpec->client.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - pwSpec->server.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->server.write_mac_key, &mac_param); - if (pwSpec->server.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - goto success; + pwSpec->client.write_mac_context = PK11_CreateContextBySymKey( + mac_mech, CKA_SIGN, pwSpec->client.write_mac_key, &mac_param); + if (pwSpec->client.write_mac_context == NULL) { + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); + goto fail; + } + pwSpec->server.write_mac_context = PK11_CreateContextBySymKey( + mac_mech, CKA_SIGN, pwSpec->server.write_mac_key, &mac_param); + if (pwSpec->server.write_mac_context == NULL) { + ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); + goto fail; } + /* + ** Now setup the crypto contexts. + */ + calg = cipher_def->calg; PORT_Assert(alg2Mech[calg].calg == calg); + + if (calg == calg_null) { + pwSpec->encode = Null_Cipher; + pwSpec->decode = Null_Cipher; + pwSpec->destroy = NULL; + return SECSuccess; + } mechanism = alg2Mech[calg].cmech; + effKeyBits = cipher_def->key_size * BPB; /* * build the server context */ iv.data = pwSpec->server.write_iv; iv.len = cipher_def->iv_size; - param = PK11_ParamFromIV(mechanism, &iv); + param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits); if (param == NULL) { ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); goto fail; @@ -1423,7 +1368,8 @@ const ssl3BulkCipherDef *cipher_def; */ iv.data = pwSpec->client.write_iv; iv.len = cipher_def->iv_size; - param = PK11_ParamFromIV(mechanism, &iv); + + param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits); if (param == NULL) { ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); goto fail; @@ -1439,30 +1385,16 @@ const ssl3BulkCipherDef *cipher_def; ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); goto fail; } - - pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext; - pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext; pwSpec->encode = (SSLCipher) PK11_CipherOp; pwSpec->decode = (SSLCipher) PK11_CipherOp; pwSpec->destroy = (SSLDestroy) PK11_DestroyContext; + pwSpec->encodeContext = (ss->sec.isServer) ? serverContext : clientContext; + pwSpec->decodeContext = (ss->sec.isServer) ? clientContext : serverContext; + serverContext = NULL; clientContext = NULL; - pwSpec->client.write_mac_context = PK11_CreateContextBySymKey( - mac_mech,CKA_SIGN, pwSpec->client.write_mac_key,&mac_param); - if (pwSpec->client.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } - pwSpec->server.write_mac_context = PK11_CreateContextBySymKey( - mac_mech, CKA_SIGN, pwSpec->server.write_mac_key,&mac_param); - if (pwSpec->server.write_mac_context == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE); - goto fail; - } -success: - ssl_ReleaseSpecWriteLock(ss); /******************************/ return SECSuccess; fail: @@ -1476,11 +1408,74 @@ fail: PK11_DestroyContext(pwSpec->server.write_mac_context,PR_TRUE); pwSpec->server.write_mac_context = NULL; } -bail_out: - ssl_ReleaseSpecWriteLock(ss); + return SECFailure; } +/* Complete the initialization of all keys, ciphers, MACs and their contexts + * for the pending Cipher Spec. + * Called from: ssl3_SendClientKeyExchange (for Full handshake) + * ssl3_HandleRSAClientKeyExchange (for Full handshake) + * ssl3_HandleServerHello (for session restart) + * ssl3_HandleClientHello (for session restart) + * Sets error code, but caller probably should override to disambiguate. + * NULL pms means re-use old master_secret. + * + * This code is common to the bypass and PKCS11 execution paths. + * For the bypass case, pms is NULL. + */ +SECStatus +ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) +{ + ssl3CipherSpec * pwSpec; + SECStatus rv; + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + ssl_GetSpecWriteLock(ss); /**************************************/ + + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); + + pwSpec = ss->ssl3.pwSpec; + + if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) { + rv = ssl3_DeriveMasterSecret(ss, pms); + if (rv != SECSuccess) { + goto done; /* err code set by ssl3_DeriveMasterSecret */ + } + } + if (pwSpec->msItem.len && pwSpec->msItem.data) { + /* Double Bypass */ + const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; + PRBool isTLS = (PRBool)(kea_def->tls_keygen || + (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); + pwSpec->bypassCiphers = PR_TRUE; + rv = ssl3_KeyAndMacDeriveBypass( pwSpec, + (const unsigned char *)&ss->ssl3.hs.client_random, + (const unsigned char *)&ss->ssl3.hs.server_random, + isTLS, + (PRBool)(kea_def->is_limited)); + if (rv == SECSuccess) { + rv = ssl3_InitPendingContextsBypass(ss); + } + } else if (pwSpec->master_secret) { + rv = ssl3_DeriveConnectionKeysPKCS11(ss); + if (rv == SECSuccess) { + rv = ssl3_InitPendingContextsPKCS11(ss); + } + } else { + PORT_Assert(pwSpec->master_secret); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } + +done: + ssl_ReleaseSpecWriteLock(ss); /******************************/ + if (rv != SECSuccess) + ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + return rv; +} + /* * 60 bytes is 3 times the maximum length MAC size that is supported. */ @@ -1512,29 +1507,21 @@ static const unsigned char mac_pad_2 [60] = { static SECStatus ssl3_ComputeRecordMAC( ssl3CipherSpec * spec, - PK11Context * mac_context, + PRBool useServerMacKey, SSL3ContentType type, SSL3ProtocolVersion version, SSL3SequenceNumber seq_num, - SSL3Opaque * input, + const SSL3Opaque * input, int inputLength, unsigned char * outbuf, unsigned int * outLength) { const ssl3MACDef * mac_def; SECStatus rv; + PRBool isTLS; unsigned int tempLen; unsigned char temp[MAX_MAC_LENGTH]; -/* ssl_GetSpecReadLock(ss); Don't have "ss"! */ - - mac_def = spec->mac_def; - if (mac_def->mac == mac_null) { - *outLength = 0; -/* ssl_ReleaseSpecReadLock(ss); */ - return SECSuccess; - } - temp[0] = (unsigned char)(seq_num.high >> 24); temp[1] = (unsigned char)(seq_num.high >> 16); temp[2] = (unsigned char)(seq_num.high >> 8); @@ -1546,7 +1533,7 @@ ssl3_ComputeRecordMAC( temp[8] = type; /* TLS MAC includes the record's version field, SSL's doesn't. - ** We decide which MAC defintion to use based on the version of + ** We decide which MAC defintiion to use based on the version of ** the protocol that was negotiated when the spec became current, ** NOT based on the version value in the record itself. ** But, we use the record'v version value in the computation. @@ -1555,6 +1542,7 @@ ssl3_ComputeRecordMAC( temp[9] = MSB(inputLength); temp[10] = LSB(inputLength); tempLen = 11; + isTLS = PR_FALSE; } else { /* New TLS hash includes version. */ temp[9] = MSB(version); @@ -1562,19 +1550,110 @@ ssl3_ComputeRecordMAC( temp[11] = MSB(inputLength); temp[12] = LSB(inputLength); tempLen = 13; + isTLS = PR_TRUE; } PRINT_BUF(95, (NULL, "frag hash1: temp", temp, tempLen)); PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength)); - rv = PK11_DigestBegin(mac_context); - rv |= PK11_DigestOp(mac_context, temp, tempLen); - rv |= PK11_DigestOp(mac_context, input, inputLength); + mac_def = spec->mac_def; + if (mac_def->mac == mac_null) { + *outLength = 0; + return SECSuccess; + } + if (! spec->bypassCiphers) { + PK11Context *mac_context = + (useServerMacKey ? spec->server.write_mac_context + : spec->client.write_mac_context); + rv = PK11_DigestBegin(mac_context); + rv |= PK11_DigestOp(mac_context, temp, tempLen); + rv |= PK11_DigestOp(mac_context, input, inputLength); + rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size); + } else { + /* bypass version */ + const SECHashObject *hashObj = NULL; + unsigned int pad_bytes; + PRUint64 write_mac_context[MAX_MAC_CONTEXT_LLONGS]; + + switch (mac_def->mac) { + case ssl_mac_null: + *outLength = 0; + return SECSuccess; + case ssl_mac_md5: + pad_bytes = 48; + hashObj = HASH_GetRawHashObject(HASH_AlgMD5); + break; + case ssl_mac_sha: + pad_bytes = 40; + hashObj = HASH_GetRawHashObject(HASH_AlgSHA1); + break; + case ssl_hmac_md5: /* used with TLS */ + hashObj = HASH_GetRawHashObject(HASH_AlgMD5); + break; + case ssl_hmac_sha: /* used with TLS */ + hashObj = HASH_GetRawHashObject(HASH_AlgSHA1); + break; + default: + break; + } + if (!hashObj) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } - rv |= PK11_DigestFinal(mac_context, outbuf, outLength, spec->mac_size); - PORT_Assert(rv != SECSuccess || *outLength == (unsigned)spec->mac_size); + if (!isTLS) { + /* compute "inner" part of SSL3 MAC */ + hashObj->begin(write_mac_context); + if (useServerMacKey) + hashObj->update(write_mac_context, + spec->server.write_mac_key_item.data, + spec->server.write_mac_key_item.len); + else + hashObj->update(write_mac_context, + spec->client.write_mac_key_item.data, + spec->client.write_mac_key_item.len); + hashObj->update(write_mac_context, mac_pad_1, pad_bytes); + hashObj->update(write_mac_context, temp, tempLen); + hashObj->update(write_mac_context, input, inputLength); + hashObj->end(write_mac_context, temp, &tempLen, sizeof temp); + + /* compute "outer" part of SSL3 MAC */ + hashObj->begin(write_mac_context); + if (useServerMacKey) + hashObj->update(write_mac_context, + spec->server.write_mac_key_item.data, + spec->server.write_mac_key_item.len); + else + hashObj->update(write_mac_context, + spec->client.write_mac_key_item.data, + spec->client.write_mac_key_item.len); + hashObj->update(write_mac_context, mac_pad_2, pad_bytes); + hashObj->update(write_mac_context, temp, tempLen); + hashObj->end(write_mac_context, outbuf, outLength, spec->mac_size); + rv = SECSuccess; + } else { /* is TLS */ +#define cx ((HMACContext *)write_mac_context) + if (useServerMacKey) { + rv = HMAC_Init(cx, hashObj, + spec->server.write_mac_key_item.data, + spec->server.write_mac_key_item.len, PR_FALSE); + } else { + rv = HMAC_Init(cx, hashObj, + spec->client.write_mac_key_item.data, + spec->client.write_mac_key_item.len, PR_FALSE); + } + if (rv == SECSuccess) { + HMAC_Begin(cx); + HMAC_Update(cx, temp, tempLen); + HMAC_Update(cx, input, inputLength); + rv = HMAC_Finish(cx, outbuf, outLength, spec->mac_size); + } +#undef cx + } + } -/* ssl_ReleaseSpecReadLock(ss); */ + PORT_Assert(rv != SECSuccess || *outLength == (unsigned)spec->mac_size); PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLength)); @@ -1632,23 +1711,20 @@ ssl3_SendRecord( sslSocket * ss, SECStatus rv; PRUint32 bufSize = 0; PRInt32 sent = 0; - PRInt32 cipherBytes = -1; PRBool isBlocking = ssl_SocketIsBlocking(ss); - PRBool ssl3WasNull = PR_FALSE; SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s bytes=%d", SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), bytes)); PRINT_BUF(3, (ss, "Send record (plain text)", buf, bytes)); - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); - if (ss->ssl3 == NULL) { + if (ss->ssl3.initialized == PR_FALSE) { /* This can happen on a server if the very first incoming record ** looks like a defective ssl3 record (e.g. too long), and we're ** trying to send an alert. */ - ssl3WasNull = PR_TRUE; PR_ASSERT(type == content_alert); rv = ssl3_InitState(ss); if (rv != SECSuccess) { @@ -1667,6 +1743,8 @@ ssl3_SendRecord( sslSocket * ss, PRUint32 contentLen; PRUint32 fragLen; PRUint32 macLen; + PRInt32 cipherBytes = 0; + PRUint32 p1Len, p2Len, oddLen = 0; contentLen = PR_MIN(bytes, MAX_FRAGMENT_LENGTH); if (write->space < contentLen + SSL3_BUFFER_FUDGE) { @@ -1687,29 +1765,25 @@ ssl3_SendRecord( sslSocket * ss, /* * null compression is easy to do - */ PORT_Memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH, buf, contentLen); - buf += contentLen; - bytes -= contentLen; - PORT_Assert( bytes >= 0 ); + */ ssl_GetSpecReadLock(ss); /********************************/ - cwSpec = ss->ssl3->cwSpec; + cwSpec = ss->ssl3.cwSpec; cipher_def = cwSpec->cipher_def; /* * Add the MAC */ - rv = ssl3_ComputeRecordMAC( - cwSpec, (ss->sec.isServer) ? cwSpec->server.write_mac_context - : cwSpec->client.write_mac_context, - type, cwSpec->version, cwSpec->write_seq_num, - write->buf + SSL3_RECORD_HEADER_LENGTH, contentLen, + rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer), + type, cwSpec->version, cwSpec->write_seq_num, buf, contentLen, write->buf + contentLen + SSL3_RECORD_HEADER_LENGTH, &macLen); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); goto spec_locked_loser; } + p1Len = contentLen; + p2Len = macLen; fragLen = contentLen + macLen; /* needs to be encrypted */ PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024); @@ -1718,10 +1792,11 @@ ssl3_SendRecord( sslSocket * ss, * then Encrypt it */ if (cipher_def->type == type_block) { + unsigned char * pBuf; int padding_length; int i; - unsigned char * pBuf; + oddLen = contentLen % cipher_def->block_size; /* Assume blockSize is a power of two */ padding_length = cipher_def->block_size - 1 - ((fragLen) & (cipher_def->block_size - 1)); @@ -1733,11 +1808,49 @@ ssl3_SendRecord( sslSocket * ss, for (i = padding_length + 1; i > 0; --i) { *pBuf-- = padding_length; } + /* now, if contentLen is not a multiple of block size, fix it */ + p2Len = fragLen - p1Len; } - rv = cwSpec->encode( - cwSpec->encodeContext, write->buf + SSL3_RECORD_HEADER_LENGTH, - &cipherBytes, bufSize, write->buf + SSL3_RECORD_HEADER_LENGTH, - fragLen); + if (p1Len < 256) { + oddLen = p1Len; + p1Len = 0; + } else { + p1Len -= oddLen; + } + if (oddLen) { + p2Len += oddLen; + PORT_Assert( (cipher_def->block_size < 2) || \ + (p2Len % cipher_def->block_size) == 0); + memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + buf + p1Len, oddLen); + } + if (p1Len > 0) { + rv = cwSpec->encode( cwSpec->encodeContext, + write->buf + SSL3_RECORD_HEADER_LENGTH, /* output */ + &cipherBytes, /* actual outlen */ + p1Len, /* max outlen */ + buf, p1Len); /* input, and inputlen */ + PORT_Assert(rv == SECSuccess && cipherBytes == p1Len); + if (rv != SECSuccess || cipherBytes != p1Len) { + PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); + goto spec_locked_loser; + } + } + if (p2Len > 0) { + PRInt32 cipherBytesPart2 = -1; + rv = cwSpec->encode( cwSpec->encodeContext, + write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + &cipherBytesPart2, /* output and actual outLen */ + p2Len, /* max outlen */ + write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + p2Len); /* input and inputLen*/ + PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len); + if (rv != SECSuccess || cipherBytesPart2 != p2Len) { + PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); + goto spec_locked_loser; + } + cipherBytes += cipherBytesPart2; + } if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_ENCRYPTION_FAILURE); spec_locked_loser: @@ -1755,6 +1868,10 @@ spec_locked_loser: ssl_ReleaseSpecReadLock(ss); /************************************/ + buf += contentLen; + bytes -= contentLen; + PORT_Assert( bytes >= 0 ); + /* PORT_Assert(fragLen == cipherBytes); */ write->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; write->buf[0] = type; @@ -1834,7 +1951,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, { PRInt32 sent = 0; - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); while (len > 0) { PRInt32 count; @@ -1878,8 +1995,8 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) { PRInt32 rv; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) return SECSuccess; @@ -1910,7 +2027,7 @@ ssl3_HandleNoCertificate(sslSocket *ss) CERT_DestroyCertificate(ss->sec.peerCert); ss->sec.peerCert = NULL; } - ssl3_CleanupPeerCerts(ss->ssl3); + ssl3_CleanupPeerCerts(ss); /* If the server has required client-auth blindly but doesn't * actually look at the certificate it won't know that no @@ -1919,9 +2036,9 @@ ssl3_HandleNoCertificate(sslSocket *ss) * first handshake because if we're redoing the handshake we * know the server is paying attention to the certificate. */ - if ((ss->requireCertificate == SSL_REQUIRE_ALWAYS) || + if ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) || (!ss->firstHsDone && - (ss->requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) { + (ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) { PRFileDesc * lower; ss->sec.uncache(ss->sec.ci.sid); @@ -2005,7 +2122,7 @@ ssl3_IllegalParameter(sslSocket *ss) { PRBool isTLS; - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT : SSL_ERROR_BAD_SERVER ); @@ -2048,8 +2165,8 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) SSL3AlertDescription desc; int error; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); SSL_TRC(3, ("%d: SSL3[%d]: handle alert record", SSL_GETPID(), ss->fd)); @@ -2103,7 +2220,7 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) } if (level == alert_fatal) { ss->sec.uncache(ss->sec.ci.sid); - if ((ss->ssl3->hs.ws == wait_server_hello) && + if ((ss->ssl3.hs.ws == wait_server_hello) && (desc == handshake_failure)) { /* XXX This is a hack. We're assuming that any handshake failure * XXX on the client hello is a failure to match ciphers. @@ -2113,12 +2230,12 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) PORT_SetError(error); return SECFailure; } - if ((desc == no_certificate) && (ss->ssl3->hs.ws == wait_client_cert)) { + if ((desc == no_certificate) && (ss->ssl3.hs.ws == wait_client_cert)) { /* I'm a server. I've requested a client cert. He hasn't got one. */ SECStatus rv; PORT_Assert(ss->sec.isServer); - ss->ssl3->hs.ws = wait_client_key; + ss->ssl3.hs.ws = wait_client_key; rv = ssl3_HandleNoCertificate(ss); return rv; } @@ -2139,7 +2256,6 @@ static SECStatus ssl3_SendChangeCipherSpecs(sslSocket *ss) { uint8 change = change_cipher_spec_choice; - ssl3State * ssl3 = ss->ssl3; ssl3CipherSpec * pwSpec; SECStatus rv; PRInt32 sent; @@ -2147,8 +2263,8 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (rv != SECSuccess) { @@ -2162,12 +2278,12 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) /* swap the pending and current write specs. */ ssl_GetSpecWriteLock(ss); /**************************************/ - pwSpec = ss->ssl3->pwSpec; + pwSpec = ss->ssl3.pwSpec; pwSpec->write_seq_num.high = 0; pwSpec->write_seq_num.low = 0; - ssl3->pwSpec = ssl3->cwSpec; - ssl3->cwSpec = pwSpec; + ss->ssl3.pwSpec = ss->ssl3.cwSpec; + ss->ssl3.cwSpec = pwSpec; SSL_TRC(3, ("%d: SSL3[%d] Set Current Write Cipher Suite to Pending", SSL_GETPID(), ss->fd )); @@ -2176,8 +2292,8 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) /* If we are really through with the old cipher spec * (Both the read and write sides have changed) destroy it. */ - if (ss->ssl3->prSpec == ss->ssl3->pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3->pwSpec); + if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec); } ssl_ReleaseSpecWriteLock(ss); /**************************************/ @@ -2194,11 +2310,11 @@ static SECStatus ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) { ssl3CipherSpec * prSpec; - SSL3WaitState ws = ss->ssl3->hs.ws; + SSL3WaitState ws = ss->ssl3.hs.ws; SSL3ChangeCipherSpecChoice change; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); SSL_TRC(3, ("%d: SSL3[%d]: handle change_cipher_spec record", SSL_GETPID(), ss->fd)); @@ -2225,12 +2341,12 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) /* Swap the pending and current read specs. */ ssl_GetSpecWriteLock(ss); /*************************************/ - prSpec = ss->ssl3->prSpec; + prSpec = ss->ssl3.prSpec; prSpec->read_seq_num.high = prSpec->read_seq_num.low = 0; - ss->ssl3->prSpec = ss->ssl3->crSpec; - ss->ssl3->crSpec = prSpec; - ss->ssl3->hs.ws = wait_finished; + ss->ssl3.prSpec = ss->ssl3.crSpec; + ss->ssl3.crSpec = prSpec; + ss->ssl3.hs.ws = wait_finished; SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", SSL_GETPID(), ss->fd )); @@ -2238,63 +2354,45 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) /* If we are really through with the old cipher prSpec * (Both the read and write sides have changed) destroy it. */ - if (ss->ssl3->prSpec == ss->ssl3->pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3->prSpec); + if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { + ssl3_DestroyCipherSpec(ss->ssl3.prSpec); } ssl_ReleaseSpecWriteLock(ss); /*************************************/ return SECSuccess; } -/* - * Key generation given pre master secret, or master secret (if !pms). - * Sets a useful error code when returning SECFailure. - * - * Called only from ssl3_InitPendingCipherSpec(), - * - * which in turn is called from - * ssl3_SendClientKeyExchange (for Full handshake) - * ssl3_HandleClientKeyExchange (for Full handshake) - * ssl3_HandleServerHello (for session restart) - * ssl3_HandleClientHello (for session restart) - * Caller MUST hold the specWriteLock, and SSL3HandshakeLock. - * ssl3_InitPendingCipherSpec does that. - */ +/* This method uses PKCS11 to derive the MS from the PMS, where PMS +** is a PKCS11 symkey. This is used in all cases except the +** "triple bypass" with RSA key exchange. +** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec. +*/ static SECStatus -ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms) +ssl3_DeriveMasterSecret(sslSocket *ss, const PK11SymKey *pms) { - ssl3CipherSpec * pwSpec = ss->ssl3->pwSpec; - const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; - const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; - unsigned char * cr = (unsigned char *)&ss->ssl3->hs.client_random; - unsigned char * sr = (unsigned char *)&ss->ssl3->hs.server_random; - PK11SymKey * symKey = NULL; - PK11SlotInfo * slot = NULL; - void * pwArg = ss->pkcs11PinArg; + ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec; + const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def; + unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random; + unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; PRBool isTLS = (PRBool)(kea_def->tls_keygen || (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); - PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null); /* * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size * data into a 48-byte value. */ - PRBool isDH = (PRBool) ((ss->ssl3->hs.kea_def->exchKeyType == kt_dh) || - (ss->ssl3->hs.kea_def->exchKeyType == kt_ecdh)); + PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) || + (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh)); + SECStatus rv = SECFailure; CK_MECHANISM_TYPE master_derive; CK_MECHANISM_TYPE key_derive; - CK_MECHANISM_TYPE bulk_mechanism; 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; - SSLCipherAlgorithm calg; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert( ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3->prSpec == ss->ssl3->pwSpec); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); if (isTLS) { if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH; else master_derive = CKM_TLS_MASTER_KEY_DERIVE; @@ -2322,7 +2420,7 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms) pwSpec->master_secret = PK11_DeriveWithFlags((PK11SymKey *)pms, master_derive, ¶ms, key_derive, CKA_DERIVE, 0, keyFlags); - if (!isDH && pwSpec->master_secret && ss->detectRollBack) { + if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) { SSL3ProtocolVersion client_version; client_version = pms_version.major << 8 | pms_version.minor; if (client_version != ss->clientHelloVersion) { @@ -2366,9 +2464,81 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms) } if (pwSpec->master_secret == NULL) { ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); - return SECFailure; + return rv; } + if (ss->opt.bypassPKCS11) { + SECItem * keydata; + /* In hope of doing a "double bypass", + * need to extract the master secret's value from the key object + * and store it raw in the sslSocket struct. + */ + rv = PK11_ExtractKeyValue(pwSpec->master_secret); + if (rv != SECSuccess) { + return rv; + } + /* This returns the address of the secItem inside the key struct, + * not a copy or a reference. So, there's no need to free it. + */ + keydata = PK11_GetKeyData(pwSpec->master_secret); + if (keydata && keydata->len <= sizeof pwSpec->raw_master_secret) { + memcpy(pwSpec->raw_master_secret, keydata->data, keydata->len); + pwSpec->msItem.data = pwSpec->raw_master_secret; + pwSpec->msItem.len = keydata->len; + } else { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + } + return SECSuccess; +} + +/* + * Derive encryption and MAC Keys (and IVs) from master secret + * Sets a useful error code when returning SECFailure. + * + * Called only from ssl3_InitPendingCipherSpec(), + * which in turn is called from + * sendRSAClientKeyExchange (for Full handshake) + * sendDHClientKeyExchange (for Full handshake) + * ssl3_HandleClientKeyExchange (for Full handshake) + * ssl3_HandleServerHello (for session restart) + * ssl3_HandleClientHello (for session restart) + * Caller MUST hold the specWriteLock, and SSL3HandshakeLock. + * ssl3_InitPendingCipherSpec does that. + * + */ +static SECStatus +ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss) +{ + ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec; + const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; + unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random; + unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; + PRBool isTLS = (PRBool)(kea_def->tls_keygen || + (pwSpec->version > SSL_LIBRARY_VERSION_3_0)); + /* following variables used in PKCS11 path */ + const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def; + PK11SlotInfo * slot = NULL; + PK11SymKey * symKey = NULL; + void * pwArg = ss->pkcs11PinArg; + int keySize; + CK_SSL3_KEY_MAT_PARAMS key_material_params; + CK_SSL3_KEY_MAT_OUT returnedKeys; + CK_MECHANISM_TYPE key_derive; + CK_MECHANISM_TYPE bulk_mechanism; + SSLCipherAlgorithm calg; + SECItem params; + PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == calg_null); + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); + + if (!pwSpec->master_secret) { + PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE); + return SECFailure; + } /* * generate the key material */ @@ -2404,6 +2574,12 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms) params.data = (unsigned char *)&key_material_params; params.len = sizeof(key_material_params); + if (isTLS) { + key_derive = CKM_TLS_KEY_AND_MAC_DERIVE; + } else { + key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE; + } + /* CKM_SSL3_KEY_AND_MAC_DERIVE is defined to set ENCRYPT, DECRYPT, and * DERIVE by DEFAULT */ symKey = PK11_Derive(pwSpec->master_secret, key_derive, ¶ms, @@ -2467,19 +2643,23 @@ loser: static SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss, unsigned char *b, unsigned int l) { - ssl3State *ssl3 = ss->ssl3; - SECStatus rv; + SECStatus rv = SECSuccess; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); PRINT_BUF(90, (NULL, "MD5 & SHA handshake hash input:", b, l)); - rv = PK11_DigestOp(ssl3->hs.md5, b, l); + if (ss->opt.bypassPKCS11) { + MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l); + SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l); + return rv; + } + rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); return rv; } - rv = PK11_DigestOp(ssl3->hs.sha, b, l); + rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); return rv; @@ -2492,14 +2672,14 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss, unsigned char *b, unsigned int l) * All these functions set appropriate error codes. * Most rely on ssl3_AppendHandshake to set the error code. **************************************************************************/ -static SECStatus +SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes) { unsigned char * src = (unsigned char *)void_src; int room = ss->sec.ci.sendBuf.space - ss->sec.ci.sendBuf.len; SECStatus rv; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); /* protects sendBuf. */ + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); /* protects sendBuf. */ if (ss->sec.ci.sendBuf.space < MAX_SEND_BUF_LENGTH && room < bytes) { rv = sslBuffer_Grow(&ss->sec.ci.sendBuf, PR_MAX(MIN_SEND_BUF_LENGTH, @@ -2555,7 +2735,7 @@ ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize) return rv; /* error code set by AppendHandshake, if applicable. */ } -static SECStatus +SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss, const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize) { @@ -2575,7 +2755,7 @@ ssl3_AppendHandshakeVariable( return rv; /* error code set by AppendHandshake, if applicable. */ } -static SECStatus +SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) { SECStatus rv; @@ -2583,9 +2763,9 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) SSL_TRC(30,("%d: SSL3[%d]: append handshake header: type %s", SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(t))); PRINT_BUF(60, (ss, "MD5 handshake hash:", - (unsigned char*)ss->ssl3->hs.md5, MD5_LENGTH)); + (unsigned char*)ss->ssl3.hs.md5_cx, MD5_LENGTH)); PRINT_BUF(95, (ss, "SHA handshake hash:", - (unsigned char*)ss->ssl3->hs.sha, SHA1_LENGTH)); + (unsigned char*)ss->ssl3.hs.sha_cx, SHA1_LENGTH)); rv = ssl3_AppendHandshakeNumber(ss, t, 1); if (rv != SECSuccess) { @@ -2610,12 +2790,12 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) * and has set a generic error code. The caller should probably * override the generic error code by setting another. */ -static SECStatus +SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length) { - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); if ((PRUint32)bytes > *length) { return ssl3_DecodeError(ss); @@ -2642,18 +2822,23 @@ static PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length) { - PRInt32 num = 0; + uint8 *buf = *b; int i; - SECStatus status; - uint8 buf[4]; + PRInt32 num = 0; - status = ssl3_ConsumeHandshake(ss, buf, bytes, b, length); - if (status != SECSuccess) { - /* ssl3_DecodeError has already been called */ - return SECFailure; + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( bytes <= sizeof num); + + if ((PRUint32)bytes > *length) { + return ssl3_DecodeError(ss); } + PRINT_BUF(60, (ss, "consume bytes:", *b, bytes)); + for (i = 0; i < bytes; i++) num = (num << 8) + buf[i]; + *b += bytes; + *length -= bytes; return num; } @@ -2665,13 +2850,17 @@ ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, * * Returns SECFailure (-1) on failure. * On error, an alert has been sent, and a generic error code has been set. + * + * RADICAL CHANGE for NSS 3.11. All callers of this function make copies + * of the data returned in the SECItem *i, so making a copy of it here + * is simply wasteful. So, This function now just sets SECItem *i to + * point to the values in the buffer **b. */ -static SECStatus +SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length) { PRInt32 count; - SECStatus rv; PORT_Assert(bytes <= 3); i->len = 0; @@ -2681,21 +2870,13 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, return SECFailure; } if (count > 0) { - i->data = (unsigned char*)PORT_Alloc(count); - if (i->data == NULL) { - /* XXX inconsistent. In other places, we don't send alerts for - * our own memory failures. But here we do... */ - (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - i->len = count; - rv = ssl3_ConsumeHandshake(ss, i->data, i->len, b, length); - if (rv != SECSuccess) { - PORT_Free(i->data); - i->data = NULL; - return rv; /* alert has already been sent. */ + if ((PRUint32)count > *length) { + return ssl3_DecodeError(ss); } + i->data = *b; + i->len = count; + *b += count; + *length -= count; } return SECSuccess; } @@ -2719,155 +2900,241 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss, SSL3Hashes * hashes, /* output goes here. */ uint32 sender) { - ssl3State * ssl3 = ss->ssl3; - PK11Context * md5; - PK11Context * sha = NULL; SECStatus rv = SECSuccess; + PRBool isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); unsigned int outLength; - PRBool isTLS; SSL3Opaque md5_inner[MAX_MAC_LENGTH]; SSL3Opaque sha_inner[MAX_MAC_LENGTH]; - unsigned char s[4]; - unsigned char md5StackBuf[256]; - unsigned char shaStackBuf[512]; - unsigned char *md5StateBuf = NULL; - unsigned char *shaStateBuf = NULL; - unsigned int md5StateLen, shaStateLen; - - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - - isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); - if (!spec->master_secret) { - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); - return SECFailure; - } - md5StateBuf = PK11_SaveContextAlloc(ssl3->hs.md5, md5StackBuf, - sizeof md5StackBuf, &md5StateLen); - if (md5StateBuf == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - goto loser; - } - md5 = ssl3->hs.md5; + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - shaStateBuf = PK11_SaveContextAlloc(ssl3->hs.sha, shaStackBuf, - sizeof shaStackBuf, &shaStateLen); - if (shaStateBuf == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; - } - sha = ssl3->hs.sha; + if (ss->opt.bypassPKCS11) { + /* compute them without PKCS11 */ + PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS]; + PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; - if (!isTLS) { - /* compute hashes for SSL3. */ +#define md5cx ((MD5Context *)md5_cx) +#define shacx ((SHA1Context *)sha_cx) - s[0] = (unsigned char)(sender >> 24); - s[1] = (unsigned char)(sender >> 16); - s[2] = (unsigned char)(sender >> 8); - s[3] = (unsigned char)sender; - - if (sender != 0) { - rv |= PK11_DigestOp(md5, s, 4); - PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4)); + if (!spec->msItem.data) { + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); + return SECFailure; } - PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, mac_defs[mac_md5].pad_size)); + MD5_Clone (md5cx, (MD5Context *)ss->ssl3.hs.md5_cx); + SHA1_Clone(shacx, (SHA1Context *)ss->ssl3.hs.sha_cx); - rv |= PK11_DigestKey(md5,spec->master_secret); - rv |= PK11_DigestOp(md5, mac_pad_1, mac_defs[mac_md5].pad_size); - rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto loser; + if (!isTLS) { + /* compute hashes for SSL3. */ + unsigned char s[4]; + + s[0] = (unsigned char)(sender >> 24); + s[1] = (unsigned char)(sender >> 16); + s[2] = (unsigned char)(sender >> 8); + s[3] = (unsigned char)sender; + + if (sender != 0) { + MD5_Update(md5cx, s, 4); + PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4)); + } + + PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, + mac_defs[mac_md5].pad_size)); + + MD5_Update(md5cx, spec->msItem.data, spec->msItem.len); + MD5_Update(md5cx, mac_pad_1, mac_defs[mac_md5].pad_size); + MD5_End(md5cx, md5_inner, &outLength, MD5_LENGTH); + + PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength)); + + if (sender != 0) { + SHA1_Update(shacx, s, 4); + PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4)); + } + + PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, + mac_defs[mac_sha].pad_size)); + + SHA1_Update(shacx, spec->msItem.data, spec->msItem.len); + SHA1_Update(shacx, mac_pad_1, mac_defs[mac_sha].pad_size); + SHA1_End(shacx, sha_inner, &outLength, SHA1_LENGTH); + + PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength)); + PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, + mac_defs[mac_md5].pad_size)); + PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); + + MD5_Begin(md5cx); + MD5_Update(md5cx, spec->msItem.data, spec->msItem.len); + MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size); + MD5_Update(md5cx, md5_inner, MD5_LENGTH); } + MD5_End(md5cx, hashes->md5, &outLength, MD5_LENGTH); + + PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); - PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength)); + if (!isTLS) { + PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, + mac_defs[mac_sha].pad_size)); + PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); - if (sender != 0) { - rv |= PK11_DigestOp(sha, s, 4); - PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4)); + SHA1_Begin(shacx); + SHA1_Update(shacx, spec->msItem.data, spec->msItem.len); + SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size); + SHA1_Update(shacx, sha_inner, SHA1_LENGTH); } + SHA1_End(shacx, hashes->sha, &outLength, SHA1_LENGTH); - PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, mac_defs[mac_sha].pad_size)); + PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); + + rv = SECSuccess; +#undef md5cx +#undef shacx + } else { + /* compute hases with PKCS11 */ + PK11Context * md5; + PK11Context * sha = NULL; + unsigned char *md5StateBuf = NULL; + unsigned char *shaStateBuf = NULL; + unsigned int md5StateLen, shaStateLen; + unsigned char md5StackBuf[256]; + unsigned char shaStackBuf[512]; + + if (!spec->master_secret) { + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE); + return SECFailure; + } + md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf, + sizeof md5StackBuf, &md5StateLen); + if (md5StateBuf == NULL) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + goto loser; + } + md5 = ss->ssl3.hs.md5; - rv |= PK11_DigestKey(sha, spec->master_secret); - rv |= PK11_DigestOp(sha, mac_pad_1, mac_defs[mac_sha].pad_size); - rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); - if (rv != SECSuccess) { + shaStateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.sha, shaStackBuf, + sizeof shaStackBuf, &shaStateLen); + if (shaStateBuf == NULL) { ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; goto loser; } + sha = ss->ssl3.hs.sha; - PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength)); + if (!isTLS) { + /* compute hashes for SSL3. */ + unsigned char s[4]; - PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, mac_defs[mac_md5].pad_size)); - PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); + s[0] = (unsigned char)(sender >> 24); + s[1] = (unsigned char)(sender >> 16); + s[2] = (unsigned char)(sender >> 8); + s[3] = (unsigned char)sender; - rv |= PK11_DigestBegin(md5); - rv |= PK11_DigestKey(md5, spec->master_secret); - rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); - rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); - } - rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } + if (sender != 0) { + rv |= PK11_DigestOp(md5, s, 4); + PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4)); + } - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, + mac_defs[mac_md5].pad_size)); - if (!isTLS) { - PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, mac_defs[mac_sha].pad_size)); - PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); + rv |= PK11_DigestKey(md5,spec->master_secret); + rv |= PK11_DigestOp(md5, mac_pad_1, mac_defs[mac_md5].pad_size); + rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH); + PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + rv = SECFailure; + goto loser; + } - rv |= PK11_DigestBegin(sha); - rv |= PK11_DigestKey(sha,spec->master_secret); - rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); - rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); - } - rv |= PK11_DigestFinal(sha, hashes->sha, &outLength, SHA1_LENGTH); - PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - rv = SECFailure; - goto loser; - } + PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength)); - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); + if (sender != 0) { + rv |= PK11_DigestOp(sha, s, 4); + PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4)); + } - rv = SECSuccess; + PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, + mac_defs[mac_sha].pad_size)); -loser: - if (md5StateBuf) { - if (PK11_RestoreContext(ssl3->hs.md5, md5StateBuf, md5StateLen) - != SECSuccess) - { + rv |= PK11_DigestKey(sha, spec->master_secret); + rv |= PK11_DigestOp(sha, mac_pad_1, mac_defs[mac_sha].pad_size); + rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH); + PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + rv = SECFailure; + goto loser; + } + + PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength)); + + PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, + mac_defs[mac_md5].pad_size)); + PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH)); + + rv |= PK11_DigestBegin(md5); + rv |= PK11_DigestKey(md5, spec->master_secret); + rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size); + rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH); + } + rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH); + PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH); + if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); rv = SECFailure; + goto loser; } - if (md5StateBuf != md5StackBuf) { - PORT_ZFree(md5StateBuf, md5StateLen); + + PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH)); + + if (!isTLS) { + PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, + mac_defs[mac_sha].pad_size)); + PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH)); + + rv |= PK11_DigestBegin(sha); + rv |= PK11_DigestKey(sha,spec->master_secret); + rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size); + rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH); } - } - if (shaStateBuf) { - if (PK11_RestoreContext(ssl3->hs.sha, shaStateBuf, shaStateLen) - != SECSuccess) - { + rv |= PK11_DigestFinal(sha, hashes->sha, &outLength, SHA1_LENGTH); + PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH); + if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); rv = SECFailure; + goto loser; } - if (shaStateBuf != shaStackBuf) { - PORT_ZFree(shaStateBuf, shaStateLen); + + PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH)); + + rv = SECSuccess; + + loser: + if (md5StateBuf) { + if (PK11_RestoreContext(ss->ssl3.hs.md5, md5StateBuf, md5StateLen) + != SECSuccess) + { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + rv = SECFailure; + } + if (md5StateBuf != md5StackBuf) { + PORT_ZFree(md5StateBuf, md5StateLen); + } + } + if (shaStateBuf) { + if (PK11_RestoreContext(ss->ssl3.hs.sha, shaStateBuf, shaStateLen) + != SECSuccess) + { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + rv = SECFailure; + } + if (shaStateBuf != shaStackBuf) { + PORT_ZFree(shaStateBuf, shaStateLen); + } } } - return rv; } @@ -2889,9 +3156,9 @@ ssl3_StartHandshakeHash(sslSocket *ss, unsigned char * buf, int length) goto done; /* ssl3_InitState has set the error code. */ } - PORT_Memset(&ss->ssl3->hs.client_random, 0, SSL3_RANDOM_LENGTH); + PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH); PORT_Memcpy( - &ss->ssl3->hs.client_random.rand[SSL3_RANDOM_LENGTH - SSL_CHALLENGE_BYTES], + &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - SSL_CHALLENGE_BYTES], &ss->sec.ci.clientChallenge, SSL_CHALLENGE_BYTES); @@ -2927,8 +3194,8 @@ ssl3_SendClientHello(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send client_hello handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); rv = ssl3_InitState(ss); if (rv != SECSuccess) { @@ -2937,23 +3204,27 @@ ssl3_SendClientHello(sslSocket *ss) SSL_TRC(30,("%d: SSL3[%d]: reset handshake hashes", SSL_GETPID(), ss->fd )); - rv = PK11_DigestBegin(ss->ssl3->hs.md5); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return rv; - } - rv = PK11_DigestBegin(ss->ssl3->hs.sha); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return rv; + if (ss->opt.bypassPKCS11) { + MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); + SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); + } else { + rv = PK11_DigestBegin(ss->ssl3.hs.md5); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + return rv; + } + rv = PK11_DigestBegin(ss->ssl3.hs.sha); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + return rv; + } } - /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup * handles expired entries and other details. * XXX If we've been called from ssl2_BeginClientHandshake, then * this lookup is duplicative and wasteful. */ - sid = (ss->noCache) ? NULL + sid = (ss->opt.noCache) ? NULL : ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url); /* We can't resume based on a different token. If the sid exists, @@ -2962,27 +3233,31 @@ ssl3_SendClientHello(sslSocket *ss) * the private key still exists, is logged in, hasn't been removed, etc. */ if (sid) { - PK11SlotInfo *slot; PRBool sidOK = PR_TRUE; - slot = (!sid->u.ssl3.masterValid) ? NULL : - SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, - sid->u.ssl3.masterSlotID); - if (slot == NULL) { - sidOK = PR_FALSE; - } else { - PK11SymKey *wrapKey = NULL; - if (!PK11_IsPresent(slot) || - ((wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex, - sid->u.ssl3.masterWrapMech, - sid->u.ssl3.masterWrapSeries, - ss->pkcs11PinArg)) == NULL) ) { - sidOK = PR_FALSE; + if (sid->u.ssl3.keys.msIsWrapped) { + /* Session key was wrapped, which means it was using PKCS11, */ + PK11SlotInfo *slot = NULL; + if (sid->u.ssl3.masterValid && !ss->opt.bypassPKCS11) { + slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, + sid->u.ssl3.masterSlotID); + } + if (slot == NULL) { + sidOK = PR_FALSE; + } else { + PK11SymKey *wrapKey = NULL; + if (!PK11_IsPresent(slot) || + ((wrapKey = PK11_GetWrapKey(slot, + sid->u.ssl3.masterWrapIndex, + sid->u.ssl3.masterWrapMech, + sid->u.ssl3.masterWrapSeries, + ss->pkcs11PinArg)) == NULL) ) { + sidOK = PR_FALSE; + } + if (wrapKey) PK11_FreeSymKey(wrapKey); + PK11_FreeSlot(slot); + slot = NULL; } - if (wrapKey) PK11_FreeSymKey(wrapKey); - PK11_FreeSlot(slot); - slot = NULL; } - /* If we previously did client-auth, make sure that the token that ** holds the private key still exists, is logged in, hasn't been ** removed, etc. @@ -3009,7 +3284,7 @@ ssl3_SendClientHello(sslSocket *ss) PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl3.sessionID, sid->u.ssl3.sessionIDLength)); - ss->ssl3->policy = sid->u.ssl3.policy; + ss->ssl3.policy = sid->u.ssl3.policy; } else { ++ssl3stats.sch_sid_cache_misses; @@ -3024,7 +3299,7 @@ ssl3_SendClientHello(sslSocket *ss) } ssl_GetSpecWriteLock(ss); - cwSpec = ss->ssl3->cwSpec; + cwSpec = ss->ssl3.cwSpec; if (cwSpec->mac_def->mac == mac_null) { /* SSL records are not being MACed. */ cwSpec->version = ss->version; @@ -3039,8 +3314,8 @@ ssl3_SendClientHello(sslSocket *ss) ss->sec.send = ssl3_SendApplicationData; /* shouldn't get here if SSL3 is disabled, but ... */ - PORT_Assert(ss->enableSSL3 || ss->enableTLS); - if (!ss->enableSSL3 && !ss->enableTLS) { + PORT_Assert(ss->opt.enableSSL3 || ss->opt.enableTLS); + if (!ss->opt.enableSSL3 && !ss->opt.enableTLS) { PORT_SetError(SSL_ERROR_SSL_DISABLED); return SECFailure; } @@ -3051,7 +3326,7 @@ ssl3_SendClientHello(sslSocket *ss) return SECFailure; /* ssl3_config_match_init has set error code. */ /* how many suites are permitted by policy and user preference? */ - num_suites = count_cipher_suites(ss, ss->ssl3->policy, PR_TRUE); + num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) return SECFailure; /* count_cipher_suites has set error code. */ @@ -3070,11 +3345,11 @@ ssl3_SendClientHello(sslSocket *ss) if (rv != SECSuccess) { return rv; /* err set by ssl3_AppendHandshake* */ } - rv = ssl3_GetNewRandom(&ss->ssl3->hs.client_random); + rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random); if (rv != SECSuccess) { return rv; /* err set by GetNewRandom. */ } - rv = ssl3_AppendHandshake(ss, &ss->ssl3->hs.client_random, + rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { return rv; /* err set by ssl3_AppendHandshake* */ @@ -3097,7 +3372,7 @@ ssl3_SendClientHello(sslSocket *ss) 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)) { actual_count++; if (actual_count > num_suites) { /* set error card removal/insertion error */ @@ -3137,7 +3412,7 @@ ssl3_SendClientHello(sslSocket *ss) return rv; /* error code set by ssl3_FlushHandshake */ } - ss->ssl3->hs.ws = wait_server_hello; + ss->ssl3.hs.ws = wait_server_hello; return rv; } @@ -3155,13 +3430,12 @@ ssl3_HandleHelloRequest(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: handle hello_request handshake", SSL_GETPID(), ss->fd)); - PORT_Assert(ss->ssl3); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - if (ss->ssl3->hs.ws == wait_server_hello) + if (ss->ssl3.hs.ws == wait_server_hello) return SECSuccess; - if (ss->ssl3->hs.ws != idle_handshake || ss->sec.isServer) { + if (ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer) { (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST); return SECFailure; @@ -3316,7 +3590,7 @@ getWrappingKey( sslSocket * ss, SECItem wrappedKey; SSLWrappedSymWrappingKey wswk; - svrPrivKey = ss->serverCerts[exchKeyType].serverKey; + svrPrivKey = ss->serverCerts[exchKeyType].SERVERKEY; PORT_Assert(svrPrivKey != NULL); if (!svrPrivKey) { return NULL; /* why are we here?!? */ @@ -3450,6 +3724,7 @@ done: /* Called from ssl3_SendClientKeyExchange(). */ +/* Presently, this always uses PKCS11. There is no bypass for this. */ static SECStatus sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) { @@ -3458,14 +3733,14 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) SECItem enc_pms = {siBuffer, NULL, 0}; PRBool isTLS; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); /* Generate the pre-master secret ... */ ssl_GetSpecWriteLock(ss); - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); - pms = ssl3_GenerateRSAPMS(ss, ss->ssl3->pwSpec, NULL); + pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL); ssl_ReleaseSpecWriteLock(ss); if (pms == NULL) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); @@ -3521,6 +3796,7 @@ loser: } /* Called from ssl3_SendClientKeyExchange(). */ +/* Presently, this always uses PKCS11. There is no bypass for this. */ static SECStatus sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) { @@ -3533,10 +3809,10 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) SECKEYPublicKey *pubKey = NULL; /* Ephemeral DH key */ SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */ - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); /* Copy DH parameters from server key */ @@ -3606,94 +3882,6 @@ loser: return rv; } -#ifdef NSS_ENABLE_ECC -/* Called from ssl3_SendClientKeyExchange(). */ -static SECStatus -sendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) -{ - PK11SymKey * pms = NULL; - SECStatus rv = SECFailure; - PRBool isTLS; - CK_MECHANISM_TYPE target; - SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ - SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ - CK_EC_KDF_TYPE kdf; - - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); - - /* Generate ephemeral EC keypair */ - privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, - &pubKey, NULL); - if (!privKey || !pubKey) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - goto loser; - } - PRINT_BUF(50, (ss, "ECDH public value:", - pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len)); - - if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; - else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - - /* If field size is not more than 24 octets, then use SHA-1 hash of result; - * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt). - */ - if ((pubKey->u.ec.publicValue.len - 1) / 2 <= 24) { - kdf = CKD_SHA1_KDF; - } else { - kdf = CKD_NULL; - } - - /* Determine the PMS */ - pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, - CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, - kdf, NULL, NULL); - - if (pms == NULL) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - SECKEY_DestroyPrivateKey(privKey); - privKey = NULL; - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); pms = NULL; - - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - goto loser; - } - - rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, - pubKey->u.ec.publicValue.len + 1); - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - - rv = ssl3_AppendHandshakeVariable(ss, - pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len, 1); - SECKEY_DestroyPublicKey(pubKey); - pubKey = NULL; - - if (rv != SECSuccess) { - goto loser; /* err set by ssl3_AppendHandshake* */ - } - - rv = SECSuccess; - -loser: - if(pms) PK11_FreeSymKey(pms); - if(privKey) SECKEY_DestroyPrivateKey(privKey); - if(pubKey) SECKEY_DestroyPublicKey(pubKey); - return rv; -} -#endif /* NSS_ENABLE_ECC */ @@ -3709,8 +3897,8 @@ ssl3_SendClientKeyExchange(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send client_key_exchange handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (ss->sec.peerKey == NULL) { serverKey = CERT_ExtractPublicKey(ss->sec.peerCert); @@ -3723,12 +3911,12 @@ ssl3_SendClientKeyExchange(sslSocket *ss) ss->sec.peerKey = NULL; /* we're done with it now */ } - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); /* enforce limits on kea key sizes. */ - if (ss->ssl3->hs.kea_def->is_limited) { + if (ss->ssl3.hs.kea_def->is_limited) { int keyLen = SECKEY_PublicKeyStrength(serverKey); /* bytes */ - if (keyLen * BPB > ss->ssl3->hs.kea_def->key_size_limit) { + if (keyLen * BPB > ss->ssl3.hs.kea_def->key_size_limit) { if (isTLS) (void)SSL3_SendAlert(ss, alert_fatal, export_restriction); else @@ -3738,10 +3926,10 @@ ssl3_SendClientKeyExchange(sslSocket *ss) } } - ss->sec.keaType = ss->ssl3->hs.kea_def->exchKeyType; + ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey); - switch (ss->ssl3->hs.kea_def->exchKeyType) { + switch (ss->ssl3.hs.kea_def->exchKeyType) { case kt_rsa: rv = sendRSAClientKeyExchange(ss, serverKey); break; @@ -3752,7 +3940,7 @@ ssl3_SendClientKeyExchange(sslSocket *ss) #ifdef NSS_ENABLE_ECC case kt_ecdh: - rv = sendECDHClientKeyExchange(ss, serverKey); + rv = ssl3_SendECDHClientKeyExchange(ss, serverKey); break; #endif /* NSS_ENABLE_ECC */ @@ -3776,27 +3964,26 @@ loser: static SECStatus ssl3_SendCertificateVerify(sslSocket *ss) { - ssl3State * ssl3 = ss->ssl3; SECStatus rv = SECFailure; PRBool isTLS; SECItem buf = {siBuffer, NULL, 0}; SSL3Hashes hashes; - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake", SSL_GETPID(), ss->fd)); ssl_GetSpecReadLock(ss); - rv = ssl3_ComputeHandshakeHashes(ss, ssl3->pwSpec, &hashes, 0); + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0); ssl_ReleaseSpecReadLock(ss); if (rv != SECSuccess) { goto done; /* err code was set by ssl3_ComputeHandshakeHashes */ } - isTLS = (PRBool)(ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_SignHashes(&hashes, ssl3->clientPrivateKey, &buf, isTLS); + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS); if (rv == SECSuccess) { PK11SlotInfo * slot; sslSessionID * sid = ss->sec.ci.sid; @@ -3805,7 +3992,7 @@ ssl3_SendCertificateVerify(sslSocket *ss) ** Later, when doing an SSL restart handshake, verify this. ** These calls are mere accessors, and can't fail. */ - slot = PK11_GetSlotFromPrivateKey(ss->ssl3->clientPrivateKey); + slot = PK11_GetSlotFromPrivateKey(ss->ssl3.clientPrivateKey); sid->u.ssl3.clAuthSeries = PK11_GetSlotSeries(slot); sid->u.ssl3.clAuthSlotID = PK11_GetSlotID(slot); sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot); @@ -3816,9 +4003,9 @@ ssl3_SendCertificateVerify(sslSocket *ss) * here. Diffie-Hellman key exchanges need the client's * private key for the key exchange. */ - if (ssl3->hs.kea_def->exchKeyType == kt_rsa) { - SECKEY_DestroyPrivateKey(ssl3->clientPrivateKey); - ssl3->clientPrivateKey = NULL; + if (ss->ssl3.hs.kea_def->exchKeyType == kt_rsa) { + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); + ss->ssl3.clientPrivateKey = NULL; } if (rv != SECSuccess) { goto done; /* err code was set by ssl3_SignHashes */ @@ -3860,15 +4047,15 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); rv = ssl3_InitState(ss); if (rv != SECSuccess) { errCode = PORT_GetError(); /* ssl3_InitState has set the error code. */ goto alert_loser; } - if (ss->ssl3->hs.ws != wait_server_hello) { + if (ss->ssl3.hs.ws != wait_server_hello) { errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO; desc = unexpected_message; goto alert_loser; @@ -3884,20 +4071,22 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ** know SSL 3.x. */ if (MSB(version) != MSB(SSL_LIBRARY_VERSION_3_0)) { - desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version : handshake_failure; + desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version + : handshake_failure; goto alert_loser; } 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; } isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ConsumeHandshake( - ss, &ss->ssl3->hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); + ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length); if (rv != SECSuccess) { goto loser; /* alert has been sent */ } @@ -3921,7 +4110,7 @@ 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) && - (config_match(suite, ss->ssl3->policy, PR_TRUE))) { + (config_match(suite, ss->ssl3.policy, PR_TRUE))) { suite_found = PR_TRUE; break; /* success */ } @@ -3931,10 +4120,10 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) errCode = SSL_ERROR_NO_CYPHER_OVERLAP; goto alert_loser; } - ss->ssl3->hs.cipher_suite = (ssl3CipherSuite)temp; - ss->ssl3->hs.suite_def = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp); - PORT_Assert(ss->ssl3->hs.suite_def); - if (!ss->ssl3->hs.suite_def) { + ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)temp; + ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp); + PORT_Assert(ss->ssl3.hs.suite_def); + if (!ss->ssl3.hs.suite_def) { PORT_SetError(errCode = SEC_ERROR_LIBRARY_FAILURE); goto loser; /* we don't send alerts for our screw-ups. */ } @@ -3956,18 +4145,20 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) errCode = SSL_ERROR_NO_COMPRESSION_OVERLAP; goto alert_loser; } - ss->ssl3->hs.compression = (SSL3CompressionMethod)temp; + ss->ssl3.hs.compression = (SSL3CompressionMethod)temp; +#ifdef DISALLOW_SERVER_HELLO_EXTENSIONS if (length != 0) { /* malformed */ goto alert_loser; } +#endif /* Any errors after this point are not "malformed" errors. */ desc = handshake_failure; /* we need to call ssl3_SetupPendingCipherSpec here so we can check the * key exchange algorithm. */ - rv = ssl3_SetupPendingCipherSpec(ss, ss->ssl3); + rv = ssl3_SetupPendingCipherSpec(ss); if (rv != SECSuccess) { goto alert_loser; /* error code is set. */ } @@ -3983,55 +4174,92 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (sid_match && sid->version == ss->version && - sid->u.ssl3.cipherSuite == ss->ssl3->hs.cipher_suite) do { + sid->u.ssl3.cipherSuite == ss->ssl3.hs.cipher_suite) do { + ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec; + PK11SlotInfo *slot; PK11SymKey * wrapKey; /* wrapping key */ - SECItem wrappedMS; /* wrapped master secret. */ CK_FLAGS keyFlags = 0; + SECItem wrappedMS; /* wrapped master secret. */ + ss->sec.authAlgorithm = sid->authAlgorithm; ss->sec.authKeyBits = sid->authKeyBits; ss->sec.keaType = sid->keaType; ss->sec.keaKeyBits = sid->keaKeyBits; - slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, - sid->u.ssl3.masterSlotID); - if (slot == NULL) { - break; /* not considered an error. */ - } - if (!PK11_IsPresent(slot)) { + /* 3 cases here: + * a) key is wrapped (implies using PKCS11) + * b) key is unwrapped, but we're still using PKCS11 + * c) key is unwrapped, and we're bypassing PKCS11. + */ + if (sid->u.ssl3.keys.msIsWrapped) { + if (ss->opt.bypassPKCS11) { + /* we cannot restart a non-bypass session in a + ** bypass socket. + */ + break; + } + /* unwrap master secret with PKCS11 */ + slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID, + sid->u.ssl3.masterSlotID); + if (slot == NULL) { + break; /* not considered an error. */ + } + if (!PK11_IsPresent(slot)) { + PK11_FreeSlot(slot); + break; /* not considered an error. */ + } + wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex, + sid->u.ssl3.masterWrapMech, + sid->u.ssl3.masterWrapSeries, + ss->pkcs11PinArg); PK11_FreeSlot(slot); - break; /* not considered an error. */ - } - wrapKey = PK11_GetWrapKey(slot, sid->u.ssl3.masterWrapIndex, - sid->u.ssl3.masterWrapMech, - sid->u.ssl3.masterWrapSeries, - ss->pkcs11PinArg); - PK11_FreeSlot(slot); - if (wrapKey == NULL) { - break; /* not considered an error. */ - } + if (wrapKey == NULL) { + break; /* not considered an error. */ + } - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - keyFlags = CKF_SIGN | CKF_VERIFY; - } + if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ + keyFlags = CKF_SIGN | CKF_VERIFY; + } - wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - ss->ssl3->pwSpec->master_secret = - PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, - NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, - CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); - errCode = PORT_GetError(); - PK11_FreeSymKey(wrapKey); - if (ss->ssl3->pwSpec->master_secret == NULL) { - break; /* errorCode set just after call to UnwrapSymKey. */ + wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; + wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; + pwSpec->master_secret = + PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, + NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, + CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); + errCode = PORT_GetError(); + PK11_FreeSymKey(wrapKey); + if (pwSpec->master_secret == NULL) { + break; /* errorCode set just after call to UnwrapSymKey. */ + } + } else if (ss->opt.bypassPKCS11) { + /* MS is not wrapped */ + wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; + wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; + memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len); + pwSpec->msItem.data = pwSpec->raw_master_secret; + pwSpec->msItem.len = wrappedMS.len; + } else { + /* We CAN restart a bypass session in a non-bypass socket. */ + /* need to import the raw master secret to session object */ + wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; + wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; + pwSpec->master_secret = + PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, + PK11_OriginUnwrap, CKA_ENCRYPT, + &wrappedMS, NULL); + PK11_FreeSlot(slot); + if (pwSpec->master_secret == NULL) { + break; + } } /* Got a Match */ ++ssl3stats.hsh_sid_cache_hits; - ss->ssl3->hs.ws = wait_change_cipher; - ss->ssl3->hs.isResuming = PR_TRUE; + ss->ssl3.hs.ws = wait_change_cipher; + ss->ssl3.hs.isResuming = PR_TRUE; /* copy the peer cert from the SID */ if (sid->peerCert != NULL) { @@ -4044,7 +4272,6 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (rv != SECSuccess) { goto alert_loser; /* err code was set */ } - SECITEM_ZfreeItem(&sidBytes, PR_FALSE); return SECSuccess; } while (0); @@ -4054,7 +4281,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ++ssl3stats.hsh_sid_cache_misses; /* throw the old one away */ - sid->u.ssl3.resumable = PR_FALSE; + sid->u.ssl3.keys.resumable = PR_FALSE; (*ss->sec.uncache)(sid); ssl_FreeSID(sid); @@ -4067,18 +4294,15 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) sid->version = ss->version; sid->u.ssl3.sessionIDLength = sidBytes.len; PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len); - SECITEM_ZfreeItem(&sidBytes, PR_FALSE); - ss->ssl3->hs.isResuming = PR_FALSE; - ss->ssl3->hs.ws = wait_server_cert; + ss->ssl3.hs.isResuming = PR_FALSE; + ss->ssl3.hs.ws = wait_server_cert; return SECSuccess; alert_loser: (void)SSL3_SendAlert(ss, alert_fatal, desc); loser: - if (sidBytes.data != NULL) - SECITEM_ZfreeItem(&sidBytes, PR_FALSE); errCode = ssl_MapLowLevelError(errCode); return SECFailure; } @@ -4096,25 +4320,16 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; SSL3AlertDescription desc = illegal_parameter; - SECItem modulus = {siBuffer, NULL, 0}; - SECItem exponent = {siBuffer, NULL, 0}; - SECItem signature = {siBuffer, NULL, 0}; - SECItem dh_p = {siBuffer, NULL, 0}; - SECItem dh_g = {siBuffer, NULL, 0}; - SECItem dh_Ys = {siBuffer, NULL, 0}; SSL3Hashes hashes; -#ifdef NSS_ENABLE_ECC - SECItem ec_params = {siBuffer, NULL, 0}; - SECItem ec_point = {siBuffer, NULL, 0}; -#endif /* NSS_ENABLE_ECC */ + SECItem signature = {siBuffer, NULL, 0}; SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - if (ss->ssl3->hs.ws != wait_server_key && - ss->ssl3->hs.ws != wait_server_cert) { + if (ss->ssl3.hs.ws != wait_server_key && + ss->ssl3.hs.ws != wait_server_cert) { errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH; desc = unexpected_message; goto alert_loser; @@ -4125,11 +4340,14 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto alert_loser; } - isTLS = (PRBool)(ss->ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - switch (ss->ssl3->hs.kea_def->exchKeyType) { + switch (ss->ssl3.hs.kea_def->exchKeyType) { + + case kt_rsa: { + SECItem modulus = {siBuffer, NULL, 0}; + SECItem exponent = {siBuffer, NULL, 0}; - case kt_rsa: rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ @@ -4156,8 +4374,9 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * check to make sure the hash is signed by right guy */ rv = ssl3_ComputeExportRSAKeyHash(modulus, exponent, - &ss->ssl3->hs.client_random, - &ss->ssl3->hs.server_random, &hashes); + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); @@ -4198,13 +4417,15 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto no_memory; } ss->sec.peerKey = peerKey; - SECITEM_FreeItem(&modulus, PR_FALSE); - SECITEM_FreeItem(&exponent, PR_FALSE); - SECITEM_FreeItem(&signature, PR_FALSE); - ss->ssl3->hs.ws = wait_cert_request; + ss->ssl3.hs.ws = wait_cert_request; return SECSuccess; + } + + case kt_dh: { + SECItem dh_p = {siBuffer, NULL, 0}; + SECItem dh_g = {siBuffer, NULL, 0}; + SECItem dh_Ys = {siBuffer, NULL, 0}; - case kt_dh: rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ @@ -4239,8 +4460,9 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * check to make sure the hash is signed by right guy */ rv = ssl3_ComputeDHKeyHash(dh_p, dh_g, dh_Ys, - &ss->ssl3->hs.client_random, - &ss->ssl3->hs.server_random, &hashes); + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); @@ -4282,120 +4504,14 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto no_memory; } ss->sec.peerKey = peerKey; - SECITEM_FreeItem(&dh_p, PR_FALSE); - SECITEM_FreeItem(&dh_g, PR_FALSE); - SECITEM_FreeItem(&dh_Ys, PR_FALSE); - ss->ssl3->hs.ws = wait_cert_request; + ss->ssl3.hs.ws = wait_cert_request; return SECSuccess; + } #ifdef NSS_ENABLE_ECC case kt_ecdh: - /* XXX This works only for named curves, revisit this when - * we support generic curves. - */ - ec_params.len = 2; - ec_params.data = (unsigned char*)PORT_Alloc(ec_params.len); - rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - - /* Fail if the curve is not a named curve */ - if ((ec_params.data[0] != ec_type_named) || - !supportedCurve(ec_params.data[1])) { - errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; - desc = handshake_failure; - goto alert_loser; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - /* Fail if the ec point uses compressed representation */ - if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { - errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; - desc = handshake_failure; - goto alert_loser; - } - - rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); - if (rv != SECSuccess) { - goto loser; /* malformed. */ - } - - if (length != 0) { - if (isTLS) - desc = decode_error; - goto alert_loser; /* malformed. */ - } - - PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, - ec_params.len)); - PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); - - /* failures after this point are not malformed handshakes. */ - /* TLS: send decrypt_error if signature failed. */ - desc = isTLS ? decrypt_error : handshake_failure; - - /* - * check to make sure the hash is signed by right guy - */ - rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point, - &ss->ssl3->hs.client_random, - &ss->ssl3->hs.server_random, &hashes); - - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, - isTLS, ss->pkcs11PinArg); - if (rv != SECSuccess) { - errCode = - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto alert_loser; - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) { - goto no_memory; - } - - ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); - if (peerKey == NULL) { - goto no_memory; - } - - peerKey->arena = arena; - peerKey->keyType = ecKey; - - /* set up EC parameters in peerKey */ - if (ecName2params(arena, ec_params.data[1], - &peerKey->u.ec.DEREncodedParams) != SECSuccess) { - /* we should never get here since we already - * checked that we are dealing with a supported curve - */ - errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; - goto alert_loser; - } - - /* copy publicValue in peerKey */ - if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point)) - { - PORT_FreeArena(arena, PR_FALSE); - goto no_memory; - } - peerKey->pkcs11Slot = NULL; - peerKey->pkcs11ID = CK_INVALID_HANDLE; - - ss->sec.peerKey = peerKey; - SECITEM_FreeItem(&ec_params, PR_FALSE); - SECITEM_FreeItem(&ec_point, PR_FALSE); - ss->ssl3->hs.ws = wait_cert_request; - - return SECSuccess; + rv = ssl3_HandleECDHServerKeyExchange(ss, b, length); + return rv; #endif /* NSS_ENABLE_ECC */ default: @@ -4407,30 +4523,10 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) alert_loser: (void)SSL3_SendAlert(ss, alert_fatal, desc); loser: - if (modulus.data != NULL) SECITEM_FreeItem(&modulus, PR_FALSE); - if (exponent.data != NULL) SECITEM_FreeItem(&exponent, PR_FALSE); - if (signature.data != NULL) SECITEM_FreeItem(&signature, PR_FALSE); - if (dh_p.data != NULL) SECITEM_FreeItem(&dh_p, PR_FALSE); - if (dh_g.data != NULL) SECITEM_FreeItem(&dh_g, PR_FALSE); - if (dh_Ys.data != NULL) SECITEM_FreeItem(&dh_Ys, PR_FALSE); -#ifdef NSS_ENABLE_ECC - if (ec_params.data != NULL) SECITEM_FreeItem(&ec_params, PR_FALSE); - if (ec_point.data != NULL) SECITEM_FreeItem(&ec_point, PR_FALSE); -#endif /* NSS_ENABLE_ECC */ PORT_SetError( errCode ); return SECFailure; no_memory: /* no-memory error has already been set. */ - if (modulus.data != NULL) SECITEM_FreeItem(&modulus, PR_FALSE); - if (exponent.data != NULL) SECITEM_FreeItem(&exponent, PR_FALSE); - if (signature.data != NULL) SECITEM_FreeItem(&signature, PR_FALSE); - if (dh_p.data != NULL) SECITEM_FreeItem(&dh_p, PR_FALSE); - if (dh_g.data != NULL) SECITEM_FreeItem(&dh_g, PR_FALSE); - if (dh_Ys.data != NULL) SECITEM_FreeItem(&dh_Ys, PR_FALSE); -#ifdef NSS_ENABLE_ECC - if (ec_params.data != NULL) SECITEM_FreeItem(&ec_params, PR_FALSE); - if (ec_point.data != NULL) SECITEM_FreeItem(&ec_point, PR_FALSE); -#endif /* NSS_ENABLE_ECC */ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); return SECFailure; } @@ -4448,7 +4544,6 @@ typedef struct dnameNode { static SECStatus ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { - ssl3State * ssl3 = ss->ssl3; PRArenaPool * arena = NULL; dnameNode * node; PRInt32 remaining; @@ -4463,23 +4558,23 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_request handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - if (ssl3->hs.ws != wait_cert_request && - ssl3->hs.ws != wait_server_key) { + if (ss->ssl3.hs.ws != wait_cert_request && + ss->ssl3.hs.ws != wait_server_key) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST; goto alert_loser; } /* clean up anything left from previous handshake. */ - if (ssl3->clientCertChain != NULL) { - CERT_DestroyCertificateList(ssl3->clientCertChain); - ssl3->clientCertChain = NULL; + if (ss->ssl3.clientCertChain != NULL) { + CERT_DestroyCertificateList(ss->ssl3.clientCertChain); + ss->ssl3.clientCertChain = NULL; } - isTLS = (PRBool)(ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); if (rv != SECSuccess) goto loser; /* malformed, alert has been sent */ @@ -4528,7 +4623,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } ca_list.nnames = nnames; - ca_list.names = (SECItem*)PORT_ArenaAlloc(arena, nnames * sizeof(SECItem)); + ca_list.names = PORT_ArenaNewArray(arena, SECItem, nnames); if (nnames > 0 && ca_list.names == NULL) goto no_mem; @@ -4542,7 +4637,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto alert_loser; /* malformed */ desc = no_certificate; - ssl3->hs.ws = wait_hello_done; + ss->ssl3.hs.ws = wait_hello_done; if (ss->getClientAuthData == NULL) { rv = SECFailure; /* force it to send a no_certificate alert */ @@ -4550,8 +4645,8 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* XXX Should pass cert_types in this call!! */ rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg, ss->fd, &ca_list, - &ssl3->clientCertificate, - &ssl3->clientPrivateKey); + &ss->ssl3.clientCertificate, + &ss->ssl3.clientPrivateKey); } switch (rv) { case SECWouldBlock: /* getClientAuthData has put up a dialog box. */ @@ -4560,33 +4655,34 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) case SECSuccess: /* check what the callback function returned */ - if ((!ssl3->clientCertificate) || (!ssl3->clientPrivateKey)) { + if ((!ss->ssl3.clientCertificate) || (!ss->ssl3.clientPrivateKey)) { /* we are missing either the key or cert */ - if (ssl3->clientCertificate) { + if (ss->ssl3.clientCertificate) { /* got a cert, but no key - free it */ - CERT_DestroyCertificate(ssl3->clientCertificate); - ssl3->clientCertificate = NULL; + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; } - if (ssl3->clientPrivateKey) { + if (ss->ssl3.clientPrivateKey) { /* got a key, but no cert - free it */ - SECKEY_DestroyPrivateKey(ssl3->clientPrivateKey); - ssl3->clientPrivateKey = NULL; + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); + ss->ssl3.clientPrivateKey = NULL; } goto send_no_certificate; } - /* Setting ssl3->clientCertChain non-NULL will cause + /* Setting ssl3.clientCertChain non-NULL will cause * ssl3_HandleServerHelloDone to call SendCertificate. */ - ssl3->clientCertChain = CERT_CertChainFromCert(ssl3->clientCertificate, - certUsageSSLClient, PR_FALSE); - if (ssl3->clientCertChain == NULL) { - if (ssl3->clientCertificate != NULL) { - CERT_DestroyCertificate(ssl3->clientCertificate); - ssl3->clientCertificate = NULL; + ss->ssl3.clientCertChain = CERT_CertChainFromCert( + ss->ssl3.clientCertificate, + certUsageSSLClient, PR_FALSE); + if (ss->ssl3.clientCertChain == NULL) { + if (ss->ssl3.clientCertificate != NULL) { + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; } - if (ssl3->clientPrivateKey != NULL) { - SECKEY_DestroyPrivateKey(ssl3->clientPrivateKey); - ssl3->clientPrivateKey = NULL; + if (ss->ssl3.clientPrivateKey != NULL) { + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); + ss->ssl3.clientPrivateKey = NULL; } goto send_no_certificate; } @@ -4596,7 +4692,7 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) default: send_no_certificate: if (isTLS) { - ssl3->sendEmptyCert = PR_TRUE; + ss->ssl3.sendEmptyCert = PR_TRUE; } else { (void)SSL3_SendAlert(ss, alert_warning, no_certificate); } @@ -4620,8 +4716,6 @@ loser: done: if (arena != NULL) PORT_FreeArena(arena, PR_FALSE); - if (cert_types.data != NULL) - SECITEM_FreeItem(&cert_types, PR_FALSE); return rv; } @@ -4665,16 +4759,16 @@ ssl3_RestartHandshakeAfterCertReq(sslSocket * ss, */ if (ss->handshake != 0) { ss->handshake = ssl_GatherRecord1stHandshake; - ss->ssl3->clientCertificate = cert; - ss->ssl3->clientCertChain = certChain; + ss->ssl3.clientCertificate = cert; + ss->ssl3.clientCertChain = certChain; if (key == NULL) { (void)SSL3_SendAlert(ss, alert_warning, no_certificate); - ss->ssl3->clientPrivateKey = NULL; + ss->ssl3.clientPrivateKey = NULL; } else { - ss->ssl3->clientPrivateKey = SECKEY_CopyPrivateKey(key); + ss->ssl3.clientPrivateKey = SECKEY_CopyPrivateKey(key); } ssl_GetRecvBufLock(ss); - if (ss->ssl3->hs.msgState.buf != NULL) { + if (ss->ssl3.hs.msgState.buf != NULL) { rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf); } ssl_ReleaseRecvBufLock(ss); @@ -4693,13 +4787,13 @@ static SECStatus ssl3_HandleServerHelloDone(sslSocket *ss) { SECStatus rv; - SSL3WaitState ws = ss->ssl3->hs.ws; + SSL3WaitState ws = ss->ssl3.hs.ws; PRBool send_verify = PR_FALSE; SSL_TRC(3, ("%d: SSL3[%d]: handle server_hello_done handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); if (ws != wait_hello_done && ws != wait_server_cert && @@ -4712,16 +4806,16 @@ ssl3_HandleServerHelloDone(sslSocket *ss) ssl_GetXmitBufLock(ss); /*******************************/ - if (ss->ssl3->sendEmptyCert) { - ss->ssl3->sendEmptyCert = PR_FALSE; + if (ss->ssl3.sendEmptyCert) { + ss->ssl3.sendEmptyCert = PR_FALSE; rv = ssl3_SendEmptyCertificate(ss); /* Don't send verify */ if (rv != SECSuccess) { goto loser; /* error code is set. */ } } else - if (ss->ssl3->clientCertChain != NULL && - ss->ssl3->clientPrivateKey != NULL) { + if (ss->ssl3.clientCertChain != NULL && + ss->ssl3.clientPrivateKey != NULL) { send_verify = PR_TRUE; rv = ssl3_SendCertificate(ss); if (rv != SECSuccess) { @@ -4751,7 +4845,7 @@ ssl3_HandleServerHelloDone(sslSocket *ss) ssl_ReleaseXmitBufLock(ss); /*******************************/ - ss->ssl3->hs.ws = wait_change_cipher; + ss->ssl3.hs.ws = wait_change_cipher; return SECSuccess; loser: @@ -4770,8 +4864,8 @@ ssl3_SendHelloRequest(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send hello_request handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); rv = ssl3_AppendHandshakeHeader(ss, hello_request, 0); if (rv != SECSuccess) { @@ -4781,7 +4875,7 @@ ssl3_SendHelloRequest(sslSocket *ss) if (rv != SECSuccess) { return rv; /* error code set by ssl3_FlushHandshake */ } - ss->ssl3->hs.ws = wait_client_hello; + ss->ssl3.hs.ws = wait_client_hello; return SECSuccess; } @@ -4809,11 +4903,10 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server) sid->cached = never_cached; sid->version = ss->version; - sid->u.ssl3.resumable = PR_TRUE; + sid->u.ssl3.keys.resumable = PR_TRUE; sid->u.ssl3.policy = SSL_ALLOWED; sid->u.ssl3.clientWriteKey = NULL; sid->u.ssl3.serverWriteKey = NULL; - sid->u.ssl3.tek = NULL; if (is_server) { SECStatus rv; @@ -4843,8 +4936,8 @@ ssl3_SendServerHelloSequence(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: begin send server_hello sequence", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); rv = ssl3_SendServerHello(ss); if (rv != SECSuccess) { @@ -4857,22 +4950,22 @@ ssl3_SendServerHelloSequence(sslSocket *ss) /* We have to do this after the call to ssl3_SendServerHello, * because kea_def is set up by ssl3_SendServerHello(). */ - kea_def = ss->ssl3->hs.kea_def; - ss->ssl3->hs.usedStepDownKey = PR_FALSE; + kea_def = ss->ssl3.hs.kea_def; + ss->ssl3.hs.usedStepDownKey = PR_FALSE; if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) { /* see if we can legally use the key in the cert. */ int keyLen; /* bytes */ keyLen = PK11_GetPrivateModulusLen( - ss->serverCerts[kea_def->exchKeyType].serverKey); + ss->serverCerts[kea_def->exchKeyType].SERVERKEY); if (keyLen > 0 && keyLen * BPB <= kea_def->key_size_limit ) { /* XXX AND cert is not signing only!! */ /* just fall through and use it. */ } else if (ss->stepDownKeyPair != NULL) { - ss->ssl3->hs.usedStepDownKey = PR_TRUE; + ss->ssl3.hs.usedStepDownKey = PR_TRUE; rv = ssl3_SendServerKeyExchange(ss); if (rv != SECSuccess) { return rv; /* err code was set. */ @@ -4893,7 +4986,7 @@ ssl3_SendServerHelloSequence(sslSocket *ss) #endif /* NSS_ENABLE_ECC */ } - if (ss->requestCertificate) { + if (ss->opt.requestCertificate) { rv = ssl3_SendCertificateRequest(ss); if (rv != SECSuccess) { return rv; /* err code is set. */ @@ -4904,7 +4997,7 @@ ssl3_SendServerHelloSequence(sslSocket *ss) return rv; /* err code is set. */ } - ss->ssl3->hs.ws = (ss->requestCertificate) ? wait_client_cert + ss->ssl3.hs.ws = (ss->opt.requestCertificate) ? wait_client_cert : wait_client_key; return SECSuccess; } @@ -4917,7 +5010,6 @@ static SECStatus ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { sslSessionID * sid = NULL; - ssl3State * ssl3; PRInt32 tmp; unsigned int i; int j; @@ -4934,8 +5026,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); /* Get peer name of client */ rv = ssl_GetPeerInfo(ss); @@ -4947,10 +5039,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (rv != SECSuccess) { return rv; /* ssl3_InitState has set the error code. */ } - ssl3 = ss->ssl3; - if ((ssl3->hs.ws != wait_client_hello) && - (ssl3->hs.ws != idle_handshake)) { + if ((ss->ssl3.hs.ws != wait_client_hello) && + (ss->ssl3.hs.ws != idle_handshake)) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO; goto alert_loser; @@ -4969,7 +5060,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* grab the client random data. */ rv = ssl3_ConsumeHandshake( - ss, &ssl3->hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); + ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed */ } @@ -4980,7 +5071,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } - if (sidBytes.len > 0 && !ss->noCache) { + if (sidBytes.len > 0 && !ss->opt.noCache) { SSL_TRC(7, ("%d: SSL3[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x", SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0], ss->sec.ci.peer.pr_s6_addr32[1], @@ -4994,7 +5085,6 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; } } - SECITEM_FreeItem(&sidBytes, PR_FALSE); /* grab the list of cipher suites. */ rv = ssl3_ConsumeHandshakeVariable(ss, &suites, 2, &b, &length); @@ -5022,10 +5112,10 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * and this is the first handshake on this connection (not a redo), * then drop this old cache entry and start a new session. */ - if ((sid->peerCert == NULL) && ss->requestCertificate && - ((ss->requireCertificate == SSL_REQUIRE_ALWAYS) || - (ss->requireCertificate == SSL_REQUIRE_NO_ERROR) || - ((ss->requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE) + if ((sid->peerCert == NULL) && ss->opt.requestCertificate && + ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) || + (ss->opt.requireCertificate == SSL_REQUIRE_NO_ERROR) || + ((ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE) && !ss->firstHsDone))) { ++ssl3stats.hch_sid_cache_not_ok; @@ -5053,15 +5143,15 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } if (!j) break; - if (!config_match(suite, ssl3->policy, PR_TRUE)) + if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) break; for (i = 0; i < suites.len; i += 2) { if ((suites.data[i] == MSB(suite->cipher_suite)) && (suites.data[i + 1] == LSB(suite->cipher_suite))) { - ssl3->hs.cipher_suite = suite->cipher_suite; - ssl3->hs.suite_def = - ssl_LookupCipherSuiteDef(ssl3->hs.cipher_suite); + ss->ssl3.hs.cipher_suite = suite->cipher_suite; + ss->ssl3.hs.suite_def = + ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); goto suite_found; } } @@ -5073,15 +5163,15 @@ 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, ssl3->policy, PR_TRUE)) + if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) continue; for (i = 0; i < suites.len; i += 2) { if ((suites.data[i] == MSB(suite->cipher_suite)) && (suites.data[i + 1] == LSB(suite->cipher_suite))) { - ssl3->hs.cipher_suite = suite->cipher_suite; - ssl3->hs.suite_def = - ssl_LookupCipherSuiteDef(ssl3->hs.cipher_suite); + ss->ssl3.hs.cipher_suite = suite->cipher_suite; + ss->ssl3.hs.suite_def = + ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); goto suite_found; } } @@ -5094,7 +5184,8 @@ suite_found: for (i = 0; i < comps.len; i++) { for (j = 0; j < compressionMethodsCount; j++) { if (comps.data[i] == compressions[j]) { - ssl3->hs.compression = (SSL3CompressionMethod)compressions[j]; + ss->ssl3.hs.compression = + (SSL3CompressionMethod)compressions[j]; goto compression_found; } } @@ -5104,9 +5195,7 @@ suite_found: goto alert_loser; compression_found: - PORT_Free(suites.data); suites.data = NULL; - PORT_Free(comps.data); comps.data = NULL; ss->sec.send = ssl3_SendApplicationData; @@ -5116,13 +5205,11 @@ compression_found: * as if the client had sent us no sid to begin with, and make a new one. */ if (sid != NULL) do { - PK11SymKey * wrapKey; /* wrapping key */ - SECItem wrappedKey; /* wrapped key */ ssl3CipherSpec *pwSpec; - CK_FLAGS keyFlags = 0; + SECItem wrappedMS; /* wrapped key */ if (sid->version != ss->version || - sid->u.ssl3.cipherSuite != ssl3->hs.cipher_suite) { + sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite) { break; /* not an error */ } @@ -5137,30 +5224,62 @@ compression_found: /* we need to resurrect the master secret.... */ ssl_GetSpecWriteLock(ss); haveSpecWriteLock = PR_TRUE; - pwSpec = ssl3->pwSpec; + pwSpec = ss->ssl3.pwSpec; + if (sid->u.ssl3.keys.msIsWrapped) { + PK11SymKey * wrapKey; /* wrapping key */ + CK_FLAGS keyFlags = 0; + if (ss->opt.bypassPKCS11) { + /* we cannot restart a non-bypass session in a + ** bypass socket. + */ + break; + } - wrapKey = getWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType, - sid->u.ssl3.masterWrapMech, ss->pkcs11PinArg); - if (!wrapKey) { - /* we have a SID cache entry, but no wrapping key for it??? */ - break; - } + wrapKey = getWrappingKey(ss, NULL, sid->u.ssl3.exchKeyType, + sid->u.ssl3.masterWrapMech, + ss->pkcs11PinArg); + if (!wrapKey) { + /* we have a SID cache entry, but no wrapping key for it??? */ + break; + } - if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - keyFlags = CKF_SIGN | CKF_VERIFY; - } + if (ss->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ + keyFlags = CKF_SIGN | CKF_VERIFY; + } - wrappedKey.data = sid->u.ssl3.keys.wrapped_master_secret; - wrappedKey.len = sid->u.ssl3.keys.wrapped_master_secret_len; + wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; + wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; - /* unwrap the master secret. */ - pwSpec->master_secret = - PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, - NULL, &wrappedKey, CKM_SSL3_MASTER_KEY_DERIVE, - CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); - PK11_FreeSymKey(wrapKey); - if (pwSpec->master_secret == NULL) { - break; /* not an error */ + /* unwrap the master secret. */ + pwSpec->master_secret = + PK11_UnwrapSymKeyWithFlags(wrapKey, sid->u.ssl3.masterWrapMech, + NULL, &wrappedMS, CKM_SSL3_MASTER_KEY_DERIVE, + CKA_DERIVE, sizeof(SSL3MasterSecret), keyFlags); + PK11_FreeSymKey(wrapKey); + if (pwSpec->master_secret == NULL) { + break; /* not an error */ + } + } else if (ss->opt.bypassPKCS11) { + wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; + wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; + memcpy(pwSpec->raw_master_secret, wrappedMS.data, wrappedMS.len); + pwSpec->msItem.data = pwSpec->raw_master_secret; + pwSpec->msItem.len = wrappedMS.len; + } else { + /* We CAN restart a bypass session in a non-bypass socket. */ + /* need to import the raw master secret to session object */ + PK11SlotInfo * slot; + wrappedMS.data = sid->u.ssl3.keys.wrapped_master_secret; + wrappedMS.len = sid->u.ssl3.keys.wrapped_master_secret_len; + slot = PK11_GetInternalSlot(); + pwSpec->master_secret = + PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, + PK11_OriginUnwrap, CKA_ENCRYPT, &wrappedMS, + NULL); + PK11_FreeSlot(slot); + if (pwSpec->master_secret == NULL) { + break; /* not an error */ + } } ss->sec.ci.sid = sid; if (sid->peerCert != NULL) { @@ -5173,7 +5292,7 @@ compression_found: * XXX make sure compression still matches */ ++ssl3stats.hch_sid_cache_hits; - ssl3->hs.isResuming = PR_TRUE; + ss->ssl3.hs.isResuming = PR_TRUE; ss->sec.authAlgorithm = sid->authAlgorithm; ss->sec.authKeyBits = sid->authKeyBits; @@ -5214,7 +5333,7 @@ compression_found: goto loser; } rv = ssl3_SendFinished(ss, 0); - ssl3->hs.ws = wait_change_cipher; + ss->ssl3.hs.ws = wait_change_cipher; if (rv != SECSuccess) { errCode = PORT_GetError(); goto loser; @@ -5248,7 +5367,7 @@ compression_found: } ss->sec.ci.sid = sid; - ssl3->hs.isResuming = PR_FALSE; + ss->ssl3.hs.isResuming = PR_FALSE; ssl_GetXmitBufLock(ss); rv = ssl3_SendServerHelloSequence(ss); ssl_ReleaseXmitBufLock(ss); @@ -5277,10 +5396,6 @@ loser: haveSpecWriteLock = PR_FALSE; } - if (sidBytes.data != NULL) SECITEM_FreeItem(&sidBytes, PR_FALSE); - if (suites.data != NULL) SECITEM_FreeItem(&suites, PR_FALSE); - if (comps.data != NULL) SECITEM_FreeItem(&comps, PR_FALSE); - if (haveXmitBufLock) { ssl_ReleaseXmitBufLock(ss); haveXmitBufLock = PR_FALSE; @@ -5313,7 +5428,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) SSL_TRC(3, ("%d: SSL3[%d]: handle v2 client_hello", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); ssl_GetSSL3HandshakeLock(ss); @@ -5323,7 +5438,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) return rv; /* ssl3_InitState has set the error code. */ } - if (ss->ssl3->hs.ws != wait_client_hello) { + if (ss->ssl3.hs.ws != wait_client_hello) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO; goto loser; /* alert_loser */ @@ -5363,12 +5478,12 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) PORT_Assert(SSL_MAX_CHALLENGE_BYTES == SSL3_RANDOM_LENGTH); - PORT_Memset(&ss->ssl3->hs.client_random, 0, SSL3_RANDOM_LENGTH); + PORT_Memset(&ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH); PORT_Memcpy( - &ss->ssl3->hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length], + &ss->ssl3.hs.client_random.rand[SSL3_RANDOM_LENGTH - rand_length], random, rand_length); - PRINT_BUF(60, (ss, "client random:", &ss->ssl3->hs.client_random.rand[0], + PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0], SSL3_RANDOM_LENGTH)); i = ssl3_config_match_init(ss); @@ -5383,16 +5498,16 @@ 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)) + if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) continue; for (i = 0; i < suite_length; i += 3) { if ((suites[i] == 0) && (suites[i+1] == MSB(suite->cipher_suite)) && (suites[i+2] == LSB(suite->cipher_suite))) { - ss->ssl3->hs.cipher_suite = suite->cipher_suite; - ss->ssl3->hs.suite_def = - ssl_LookupCipherSuiteDef(ss->ssl3->hs.cipher_suite); + ss->ssl3.hs.cipher_suite = suite->cipher_suite; + ss->ssl3.hs.suite_def = + ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite); goto suite_found; } } @@ -5402,7 +5517,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) suite_found: - ss->ssl3->hs.compression = compression_null; + ss->ssl3.hs.compression = compression_null; ss->sec.send = ssl3_SendApplicationData; /* we don't even search for a cache hit here. It's just a miss. */ @@ -5464,8 +5579,8 @@ ssl3_SendServerHello(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert( MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0)); if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) { @@ -5486,13 +5601,13 @@ ssl3_SendServerHello(sslSocket *ss) if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } - rv = ssl3_GetNewRandom(&ss->ssl3->hs.server_random); + rv = ssl3_GetNewRandom(&ss->ssl3.hs.server_random); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); return rv; } rv = ssl3_AppendHandshake( - ss, &ss->ssl3->hs.server_random, SSL3_RANDOM_LENGTH); + ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -5506,15 +5621,15 @@ ssl3_SendServerHello(sslSocket *ss) return rv; /* err set by AppendHandshake. */ } - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3->hs.cipher_suite, 2); + rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.cipher_suite, 2); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } - rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3->hs.compression, 1); + rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.compression, 1); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } - rv = ssl3_SetupPendingCipherSpec(ss, ss->ssl3); + rv = ssl3_SetupPendingCipherSpec(ss); if (rv != SECSuccess) { return rv; /* err set by ssl3_SetupPendingCipherSpec */ } @@ -5526,25 +5641,19 @@ ssl3_SendServerHello(sslSocket *ss) static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss) { -const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; +const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; SECStatus rv = SECFailure; int length; PRBool isTLS; SECItem signed_hash = {siBuffer, NULL, 0}; SSL3Hashes hashes; SECKEYPublicKey * sdPub; /* public key for step-down */ -#ifdef NSS_ENABLE_ECC - SECKEYPublicKey * ecdhePub; - SECItem ec_params = {siBuffer, NULL, 0}; - ECName curve; - SSL3KEAType certIndex; -#endif /* NSS_ENABLE_ECC */ SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); switch (kea_def->exchKeyType) { case kt_rsa: @@ -5557,16 +5666,16 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; } rv = ssl3_ComputeExportRSAKeyHash(sdPub->u.rsa.modulus, sdPub->u.rsa.publicExponent, - &ss->ssl3->hs.client_random, - &ss->ssl3->hs.server_random, - &hashes); + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); return rv; } - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); - rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].serverKey, + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].SERVERKEY, &signed_hash, isTLS); if (rv != SECSuccess) { goto loser; /* ssl3_SignHashes has set err. */ @@ -5607,90 +5716,10 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; return SECSuccess; #ifdef NSS_ENABLE_ECC - case kt_ecdh: - /* Generate ephemeral ECDH key pair and send the public key */ - rv = ssl3_CreateECDHEphemeralKeys(ss); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - ecdhePub = ss->ephemeralECDHKeyPair->pubKey; - PORT_Assert(ecdhePub != NULL); - if (!ecdhePub) { - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - - ec_params.len = 2; - ec_params.data = (unsigned char*)PORT_Alloc(ec_params.len); - curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams); - if (curve != ec_noName) { - ec_params.data[0] = ec_type_named; - ec_params.data[1] = curve; - } else { - PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); - goto loser; - } - - rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue, - &ss->ssl3->hs.client_random, - &ss->ssl3->hs.server_random, - &hashes); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - - isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); - - /* XXX SSLKEAType isn't really a good choice for - * indexing certificates but that's all we have - * for now. - */ - if (kea_def->kea == kea_ecdhe_rsa) - certIndex = kt_rsa; - else /* kea_def->kea == kea_ecdhe_ecdsa */ - certIndex = kt_ecdh; - - rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].serverKey, - &signed_hash, isTLS); - if (rv != SECSuccess) { - goto loser; /* ssl3_SignHashes has set err. */ - } - if (signed_hash.data == NULL) { - /* how can this happen and rv == SECSuccess ?? */ - PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); - goto loser; - } - - length = ec_params.len + - 1 + ecdhePub->u.ec.publicValue.len + - 2 + signed_hash.len; - - rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data, - ecdhePub->u.ec.publicValue.len, 1); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, - signed_hash.len, 2); - if (rv != SECSuccess) { - goto loser; /* err set by AppendHandshake. */ - } - - PORT_Free(ec_params.data); - PORT_Free(signed_hash.data); - return SECSuccess; + case kt_ecdh: { + rv = ssl3_SendECDHServerKeyExchange(ss); + return rv; + } #endif /* NSS_ENABLE_ECC */ case kt_dh: @@ -5700,10 +5729,6 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; break; } loser: -#ifdef NSS_ENABLE_ECC - if (ec_params.data != NULL) - PORT_Free(ec_params.data); -#endif /* NSS_ENABLE_ECC */ if (signed_hash.data != NULL) PORT_Free(signed_hash.data); return SECFailure; @@ -5727,11 +5752,11 @@ const uint8 * certTypes; SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - /* ssl3->ca_list is initialized to NULL, and never changed. */ - ca_list = ss->ssl3->ca_list; + /* ssl3.ca_list is initialized to NULL, and never changed. */ + ca_list = ss->ssl3.ca_list; if (!ca_list) { ca_list = ssl3_server_ca_list; } @@ -5785,8 +5810,8 @@ ssl3_SendServerHelloDone(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send server_hello_done handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); rv = ssl3_AppendHandshakeHeader(ss, server_hello_done, 0); if (rv != SECSuccess) { @@ -5815,10 +5840,10 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - if (ss->ssl3->hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) { + if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY; goto alert_loser; @@ -5829,7 +5854,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, goto loser; /* malformed. */ } - isTLS = (PRBool)(ss->ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); /* XXX verify that the key & kea match */ rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash, @@ -5840,20 +5865,18 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, goto alert_loser; } - PORT_Free(signed_hash.data); signed_hash.data = NULL; if (length != 0) { desc = isTLS ? decode_error : illegal_parameter; goto alert_loser; /* malformed */ } - ss->ssl3->hs.ws = wait_change_cipher; + ss->ssl3.hs.ws = wait_change_cipher; return SECSuccess; alert_loser: SSL3_SendAlert(ss, alert_fatal, desc); loser: - if (signed_hash.data != NULL) SECITEM_FreeItem(&signed_hash, PR_FALSE); PORT_SetError(errCode); return SECFailure; } @@ -5864,7 +5887,7 @@ loser: * If the serverKeySlot parameter is non-null, this function will use * that slot to do the job, otherwise it will find a slot. * - * Called from ssl3_GenerateSessionKeys() (above) + * Called from ssl3_DeriveConnectionKeysPKCS11() (above) * sendRSAClientKeyExchange() (above) * ssl3_HandleRSAClientKeyExchange() (below) * Caller must hold the SpecWriteLock, the SSL3HandshakeLock @@ -5880,7 +5903,7 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, CK_VERSION version; CK_MECHANISM_TYPE mechanism_array[3]; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); if (slot == NULL) { SSLCipherAlgorithm calg; @@ -5888,8 +5911,8 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, ** read locks. Also, all the callers who call with a non-null ** slot already hold the SpecWriteLock. */ - PORT_Assert( ssl_HaveSpecWriteLock(ss)); - PORT_Assert(ss->ssl3->prSpec == ss->ssl3->pwSpec); + PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); calg = spec->cipher_def->calg; PORT_Assert(alg2Mech[calg].calg == calg); @@ -5945,16 +5968,23 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, SECKEYPrivateKey *serverKey) { PK11SymKey * pms; + unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random; + unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random; + ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec; + unsigned int outLen = 0; + PRBool isTLS = PR_FALSE; SECStatus rv; SECItem enc_pms; + unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH]; + SECItem pmsItem = {siBuffer, rsaPmsBuf, sizeof rsaPmsBuf}; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); enc_pms.data = b; enc_pms.len = length; - if (ss->ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ + if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ PRInt32 kLen; kLen = ssl3_ConsumeHandshakeNumber(ss, 2, &enc_pms.data, &enc_pms.len); if (kLen < 0) { @@ -5964,114 +5994,83 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, if ((unsigned)kLen < enc_pms.len) { enc_pms.len = kLen; } - } - /* - * 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); - if (pms != NULL) { - PRINT_BUF(60, (ss, "decrypted premaster secret:", - PK11_GetKeyData(pms)->data, - PK11_GetKeyData(pms)->len)); + isTLS = PR_TRUE; } else { - /* unwrap failed. Generate a bogus pre-master secret and carry on. */ - PK11SlotInfo * slot = PK11_GetSlotFromPrivateKey(serverKey); - - ssl_GetSpecWriteLock(ss); - pms = ssl3_GenerateRSAPMS(ss, ss->ssl3->prSpec, slot); - ssl_ReleaseSpecWriteLock(ss); - - PK11_FreeSlot(slot); - } - - if (pms == NULL) { - /* last gasp. */ - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - return SECFailure; - } - - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); - if (rv != SECSuccess) { - SEND_ALERT - return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ - } - return SECSuccess; -} - -#ifdef NSS_ENABLE_ECC -/* -** Called from ssl3_HandleClientKeyExchange() -*/ -static SECStatus -ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, - PRUint32 length, - SECKEYPublicKey *srvrPubKey, - SECKEYPrivateKey *srvrPrivKey) -{ - PK11SymKey * pms; - SECStatus rv; - SECKEYPublicKey clntPubKey; - CK_MECHANISM_TYPE target; - PRBool isTLS; - CK_EC_KDF_TYPE kdf; - - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); - - clntPubKey.keyType = ecKey; - clntPubKey.u.ec.DEREncodedParams.len = - srvrPubKey->u.ec.DEREncodedParams.len; - clntPubKey.u.ec.DEREncodedParams.data = - srvrPubKey->u.ec.DEREncodedParams.data; - - rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, - 1, &b, &length); - if (rv != SECSuccess) { - SEND_ALERT - return SECFailure; /* XXX Who sets the error code?? */ + isTLS = (PRBool)(ss->ssl3.hs.kea_def->tls_keygen != 0); } - isTLS = (PRBool)(ss->ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0); - - if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; - else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + if (ss->opt.bypassPKCS11) { + /* TRIPLE BYPASS, get PMS directly from RSA decryption. + * Use PK11_PrivDecryptPKCS1 to decrypt the PMS to a buffer, + * then, check for version rollback attack, then + * do the equivalent of ssl3_DeriveMasterSecret, placing the MS in + * pwSpec->msItem. Finally call ssl3_InitPendingCipherSpec with + * ss and NULL, so that it will use the MS we've already derived here. + */ - /* If field size is not more than 24 octets, then use SHA-1 hash of result; - * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt). - */ - if (srvrPubKey->u.ec.size <= 24 * 8) { - kdf = CKD_SHA1_KDF; + rv = PK11_PrivDecryptPKCS1(serverKey, rsaPmsBuf, &outLen, + sizeof rsaPmsBuf, enc_pms.data, enc_pms.len); + if (rv != SECSuccess) { + /* avoid Bleichenbacker attack. generate faux pms. */ + rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf); + /* ignore failure */ + } else if (ss->opt.detectRollBack) { + SSL3ProtocolVersion client_version = + (rsaPmsBuf[0] << 8) | rsaPmsBuf[1]; + if (client_version != ss->clientHelloVersion) { + /* Version roll-back detected. ensure failure. */ + rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf); + } + } + /* have PMS, build MS without PKCS11 */ + rv = ssl3_MasterKeyDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS, + PR_TRUE); + if (rv != SECSuccess) { + pwSpec->msItem.data = pwSpec->raw_master_secret; + pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH; + PK11_GenerateRandom(pwSpec->msItem.data, pwSpec->msItem.len); + } + rv = ssl3_InitPendingCipherSpec(ss, NULL); } else { - kdf = CKD_NULL; - } + /* + * unwrap pms out of the incoming buffer + * Note: CKM_SSL3_MASTER_KEY_DERIVE 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_MASTER_KEY_DERIVE, CKA_DERIVE, 0); + if (pms != NULL) { + PRINT_BUF(60, (ss, "decrypted premaster secret:", + PK11_GetKeyData(pms)->data, + PK11_GetKeyData(pms)->len)); + } else { + /* unwrap failed. Generate a bogus PMS and carry on. */ + PK11SlotInfo * slot = PK11_GetSlotFromPrivateKey(serverKey); - /* Determine the PMS */ - pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, - CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, - kdf, NULL, NULL); + ssl_GetSpecWriteLock(ss); + pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot); + ssl_ReleaseSpecWriteLock(ss); + PK11_FreeSlot(slot); + } - PORT_Free(clntPubKey.u.ec.publicValue.data); + if (pms == NULL) { + /* last gasp. */ + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + return SECFailure; + } - if (pms == NULL) { - /* last gasp. */ - ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); - return SECFailure; + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); } - rv = ssl3_InitPendingCipherSpec(ss, pms); - PK11_FreeSymKey(pms); if (rv != SECSuccess) { SEND_ALERT - return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ + return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ } return SECSuccess; } -#endif /* NSS_ENABLE_ECC */ + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 ClientKeyExchange message from the remote client @@ -6090,16 +6089,16 @@ const ssl3KEADef * kea_def; SSL_TRC(3, ("%d: SSL3[%d]: handle client_key_exchange handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - if (ss->ssl3->hs.ws != wait_client_key) { + if (ss->ssl3.hs.ws != wait_client_key) { SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH); return SECFailure; } - kea_def = ss->ssl3->hs.kea_def; + kea_def = ss->ssl3.hs.kea_def; #ifdef NSS_ENABLE_ECC /* XXX Using SSLKEAType to index server certifiates @@ -6118,16 +6117,16 @@ const ssl3KEADef * kea_def; } else { #endif /* NSS_ENABLE_ECC */ - serverKey = (ss->ssl3->hs.usedStepDownKey + serverKey = (ss->ssl3.hs.usedStepDownKey #ifdef DEBUG && kea_def->is_limited /* XXX OR cert is signing only */ && kea_def->exchKeyType == kt_rsa && ss->stepDownKeyPair != NULL #endif ) ? ss->stepDownKeyPair->privKey - : ss->serverCerts[kea_def->exchKeyType].serverKey; + : ss->serverCerts[kea_def->exchKeyType].SERVERKEY; - if (ss->ssl3->hs.usedStepDownKey + if (ss->ssl3.hs.usedStepDownKey #ifdef DEBUG && kea_def->is_limited /* XXX OR cert is signing only */ && kea_def->exchKeyType == kt_rsa @@ -6138,7 +6137,7 @@ const ssl3KEADef * kea_def; ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; } else { sslServerCerts * sc = ss->serverCerts + kea_def->exchKeyType; - serverKey = sc->serverKey; + serverKey = sc->SERVERKEY; ss->sec.keaKeyBits = sc->serverKeyBits; } @@ -6159,7 +6158,7 @@ const ssl3KEADef * kea_def; rv = ssl3_HandleRSAClientKeyExchange(ss, b, length, serverKey); if (rv != SECSuccess) { SEND_ALERT - return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ + return SECFailure; /* error code set */ } break; @@ -6198,7 +6197,7 @@ const ssl3KEADef * kea_def; PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); return SECFailure; } - ss->ssl3->hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher; + ss->ssl3.hs.ws = ss->sec.peerCert ? wait_cert_verify : wait_change_cipher; return SECSuccess; } @@ -6298,8 +6297,8 @@ ssl3_SendCertificate(sslSocket *ss) SSL_TRC(3, ("%d: SSL3[%d]: send certificate handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (ss->sec.localCert) CERT_DestroyCertificate(ss->sec.localCert); @@ -6314,20 +6313,20 @@ ssl3_SendCertificate(sslSocket *ss) * for ECDHE-ECDSA or client-side authentication * using EC certificates. */ - if ((ss->ssl3->hs.kea_def->kea == kea_ecdhe_rsa) || - (ss->ssl3->hs.kea_def->kea == kea_dhe_rsa)) { + if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) || + (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) { certIndex = kt_rsa; } else { - certIndex = ss->ssl3->hs.kea_def->exchKeyType; + certIndex = ss->ssl3.hs.kea_def->exchKeyType; } sc = ss->serverCerts + certIndex; certChain = sc->serverCertChain; ss->sec.authKeyBits = sc->serverKeyBits; - ss->sec.authAlgorithm = ss->ssl3->hs.kea_def->signKeyType; + ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType; ss->sec.localCert = CERT_DupCertificate(sc->serverCert); } else { - certChain = ss->ssl3->clientCertChain; - ss->sec.localCert = CERT_DupCertificate(ss->ssl3->clientCertificate); + certChain = ss->ssl3.clientCertChain; + ss->sec.localCert = CERT_DupCertificate(ss->ssl3.clientCertificate); } #ifdef NISCC_TEST @@ -6382,17 +6381,17 @@ ssl3_SendCertificate(sslSocket *ss) * from the cert database after they've been validated. */ static void -ssl3_CleanupPeerCerts(ssl3State *ssl3) +ssl3_CleanupPeerCerts(sslSocket *ss) { - PRArenaPool * arena = ssl3->peerCertArena; - ssl3CertNode *certs = (ssl3CertNode *)ssl3->peerCertChain; + PRArenaPool * arena = ss->ssl3.peerCertArena; + ssl3CertNode *certs = (ssl3CertNode *)ss->ssl3.peerCertChain; for (; certs; certs = certs->next) { CERT_DestroyCertificate(certs->cert); } if (arena) PORT_FreeArena(arena, PR_FALSE); - ssl3->peerCertArena = NULL; - ssl3->peerCertChain = NULL; + ss->ssl3.peerCertArena = NULL; + ss->ssl3.peerCertChain = NULL; } /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete @@ -6405,7 +6404,6 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ssl3CertNode * c; ssl3CertNode * certs = NULL; PRArenaPool * arena = NULL; - ssl3State * ssl3 = ss->ssl3; CERTCertificate *cert; PRInt32 remaining = 0; PRInt32 size; @@ -6419,11 +6417,11 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); - if ((ssl3->hs.ws != wait_server_cert) && - (ssl3->hs.ws != wait_client_cert)) { + if ((ss->ssl3.hs.ws != wait_server_cert) && + (ss->ssl3.hs.ws != wait_client_cert)) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CERTIFICATE; goto alert_loser; @@ -6438,8 +6436,8 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->sec.peerCert = NULL; } - ssl3_CleanupPeerCerts(ssl3); - isTLS = (PRBool)(ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0); + ssl3_CleanupPeerCerts(ss); + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); /* It is reported that some TLS client sends a Certificate message ** with a zero-length message body. We'll treat that case like a @@ -6466,7 +6464,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto cert_block; } - ssl3->peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + ss->ssl3.peerCertArena = arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( arena == NULL ) { goto loser; /* don't send alerts on memory errors */ } @@ -6556,7 +6554,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* someone will handle this connection asynchronously*/ SSL_DBG(("%d: SSL3[%d]: go to async cert handler", SSL_GETPID(), ss->fd)); - ssl3->peerCertChain = certs; + ss->ssl3.peerCertChain = certs; certs = NULL; ssl_SetAlwaysBlock(ss); goto cert_block; @@ -6571,14 +6569,14 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) cert = ss->sec.peerCert; if (!isServer && ssl3_global_policy_some_restricted && - ssl3->policy == SSL_ALLOWED && + ss->ssl3.policy == SSL_ALLOWED && anyRestrictedEnabled(ss) && SECSuccess == CERT_VerifyCertNow(cert->dbhandle, cert, PR_FALSE, /* checkSig */ certUsageSSLServerWithStepUp, /*XXX*/ ss->authCertificateArg) ) { - ssl3->policy = SSL_RESTRICTED; - ssl3->hs.rehandshake = PR_TRUE; + ss->ssl3.policy = SSL_RESTRICTED; + ss->ssl3.hs.rehandshake = PR_TRUE; } ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); @@ -6589,8 +6587,8 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ** it will get fixed when we handle the server key exchange message. */ SECKEYPublicKey * pubKey = CERT_ExtractPublicKey(cert); - ss->sec.authAlgorithm = ssl3->hs.kea_def->signKeyType; - ss->sec.keaType = ssl3->hs.kea_def->exchKeyType; + ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType; + ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType; if (pubKey) { ss->sec.keaKeyBits = ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); @@ -6603,7 +6601,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * cert->signatureWrap.signature.len contains the * length of the encoded signature in bits. */ - if (ss->ssl3->hs.kea_def->kea == kea_ecdh_ecdsa) { + if (ss->ssl3.hs.kea_def->kea == kea_ecdh_ecdsa) { ss->sec.authKeyBits = cert->signatureWrap.signature.data[3]*8; if (cert->signatureWrap.signature.data[4] == 0x00) @@ -6612,7 +6610,7 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * XXX: if cert is not signed by ecdsa we should * destroy pubKey and goto bad_cert */ - } else if (ss->ssl3->hs.kea_def->kea == kea_ecdh_rsa) { + } else if (ss->ssl3.hs.kea_def->kea == kea_ecdh_rsa) { ss->sec.authKeyBits = cert->signatureWrap.signature.len; /* * XXX: if cert is not signed by rsa we should @@ -6626,21 +6624,21 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } } - ssl3->peerCertChain = certs; certs = NULL; arena = NULL; + ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL; cert_block: if (ss->sec.isServer) { - ssl3->hs.ws = wait_client_key; + ss->ssl3.hs.ws = wait_client_key; } else { - ssl3->hs.ws = wait_cert_request; /* disallow server_key_exchange */ - if (ssl3->hs.kea_def->is_limited || + ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */ + if (ss->ssl3.hs.kea_def->is_limited || /* XXX OR server cert is signing only. */ #ifdef NSS_ENABLE_ECC - ssl3->hs.kea_def->kea == kea_ecdhe_ecdsa || - ssl3->hs.kea_def->kea == kea_ecdhe_rsa || + ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || + ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa || #endif /* NSS_ENABLE_ECC */ - ssl3->hs.kea_def->exchKeyType == kt_dh) { - ssl3->hs.ws = wait_server_key; /* allow server_key_exchange */ + ss->ssl3.hs.kea_def->exchKeyType == kt_dh) { + ss->ssl3.hs.ws = wait_server_key; /* allow server_key_exchange */ } } @@ -6697,8 +6695,8 @@ alert_loser: (void)SSL3_SendAlert(ss, alert_fatal, desc); loser: - ssl3->peerCertChain = certs; certs = NULL; arena = NULL; - ssl3_CleanupPeerCerts(ssl3); + ss->ssl3.peerCertChain = certs; certs = NULL; arena = NULL; + ssl3_CleanupPeerCerts(ss); if (ss->sec.peerCert != NULL) { CERT_DestroyCertificate(ss->sec.peerCert); @@ -6724,14 +6722,13 @@ int ssl3_RestartHandshakeAfterServerCert(sslSocket *ss) { CERTCertificate * cert; - ssl3State * ssl3 = ss->ssl3; int rv = SECSuccess; if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) { SET_ERROR_CODE return SECFailure; } - if (!ss->ssl3) { + if (!ss->ssl3.initialized) { SET_ERROR_CODE return SECFailure; } @@ -6741,14 +6738,14 @@ ssl3_RestartHandshakeAfterServerCert(sslSocket *ss) /* Permit step up if user decided to accept the cert */ if (!ss->sec.isServer && ssl3_global_policy_some_restricted && - ssl3->policy == SSL_ALLOWED && + ss->ssl3.policy == SSL_ALLOWED && anyRestrictedEnabled(ss) && (SECSuccess == CERT_VerifyCertNow(cert->dbhandle, cert, PR_FALSE, /* checksig */ certUsageSSLServerWithStepUp, /*XXX*/ ss->authCertificateArg) )) { - ssl3->policy = SSL_RESTRICTED; - ssl3->hs.rehandshake = PR_TRUE; + ss->ssl3.policy = SSL_RESTRICTED; + ss->ssl3.hs.rehandshake = PR_TRUE; } if (ss->handshake != NULL) { @@ -6756,7 +6753,7 @@ ssl3_RestartHandshakeAfterServerCert(sslSocket *ss) ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); ssl_GetRecvBufLock(ss); - if (ssl3->hs.msgState.buf != NULL) { + if (ss->ssl3.hs.msgState.buf != NULL) { rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf); } ssl_ReleaseRecvBufLock(ss); @@ -6771,29 +6768,43 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec, const SSL3Finished * hashes, TLSFinished * tlsFinished) { - PK11Context *prf_context; const char * label; unsigned int len; SECStatus rv; - SECItem param = {siBuffer, NULL, 0}; label = isServer ? "server finished" : "client finished"; len = 15; - prf_context = - PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN, - spec->master_secret, ¶m); - if (!prf_context) - return SECFailure; + if (spec->master_secret && !spec->bypassCiphers) { + SECItem param = {siBuffer, NULL, 0}; + PK11Context *prf_context = + PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN, + spec->master_secret, ¶m); + if (!prf_context) + return SECFailure; - rv = PK11_DigestBegin(prf_context); - rv |= PK11_DigestOp(prf_context, (const unsigned char *) label, len); - rv |= PK11_DigestOp(prf_context, hashes->md5, sizeof *hashes); - rv |= PK11_DigestFinal(prf_context, tlsFinished->verify_data, - &len, sizeof *tlsFinished); - PORT_Assert(rv != SECSuccess || len == sizeof *tlsFinished); + rv = PK11_DigestBegin(prf_context); + rv |= PK11_DigestOp(prf_context, (const unsigned char *) label, len); + rv |= PK11_DigestOp(prf_context, hashes->md5, sizeof *hashes); + rv |= PK11_DigestFinal(prf_context, tlsFinished->verify_data, + &len, sizeof tlsFinished->verify_data); + PORT_Assert(rv != SECSuccess || len == sizeof *tlsFinished); - PK11_DestroyContext(prf_context, PR_TRUE); + PK11_DestroyContext(prf_context, PR_TRUE); + } else { + /* bypass PKCS11 */ + SECItem inData = { siBuffer, }; + SECItem outData = { siBuffer, }; + PRBool isFIPS = PR_FALSE; + + inData.data = (unsigned char *)hashes->md5; + inData.len = sizeof hashes[0]; + outData.data = tlsFinished->verify_data; + outData.len = sizeof tlsFinished->verify_data; + rv = TLS_PRF(&spec->msItem, label, &inData, &outData, isFIPS); + PORT_Assert(rv != SECSuccess || \ + outData.len == sizeof tlsFinished->verify_data); + } return rv; } @@ -6814,11 +6825,11 @@ ssl3_SendFinished(sslSocket *ss, PRInt32 flags) SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd)); - PORT_Assert( ssl_HaveXmitBufLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); ssl_GetSpecReadLock(ss); - cwSpec = ss->ssl3->cwSpec; + cwSpec = ss->ssl3.cwSpec; isTLS = (PRBool)(cwSpec->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ComputeHandshakeHashes(ss, cwSpec, &hashes, sender); if (isTLS && rv == SECSuccess) { @@ -6854,7 +6865,88 @@ fail: return rv; } +/* wrap the master secret, and put it into the SID. + * Caller holds the Spec read lock. + */ +static SECStatus +ssl3_CacheWrappedMasterSecret(sslSocket *ss, SSL3KEAType effectiveExchKeyType) +{ + sslSessionID * sid = ss->sec.ci.sid; + PK11SymKey * wrappingKey = NULL; + PK11SlotInfo * symKeySlot; + void * pwArg = ss->pkcs11PinArg; + SECStatus rv = SECFailure; + PRBool isServer = ss->sec.isServer; + CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; + symKeySlot = PK11_GetSlotFromKey(ss->ssl3.crSpec->master_secret); + if (!isServer) { + int wrapKeyIndex; + int incarnation; + + /* these next few functions are mere accessors and don't fail. */ + sid->u.ssl3.masterWrapIndex = wrapKeyIndex = + PK11_GetCurrentWrapIndex(symKeySlot); + PORT_Assert(wrapKeyIndex == 0); /* array has only one entry! */ + + sid->u.ssl3.masterWrapSeries = incarnation = + PK11_GetSlotSeries(symKeySlot); + sid->u.ssl3.masterSlotID = PK11_GetSlotID(symKeySlot); + sid->u.ssl3.masterModuleID = PK11_GetModuleID(symKeySlot); + sid->u.ssl3.masterValid = PR_TRUE; + /* Get the default wrapping key, for wrapping the master secret before + * placing it in the SID cache entry. */ + wrappingKey = PK11_GetWrapKey(symKeySlot, wrapKeyIndex, + CKM_INVALID_MECHANISM, incarnation, + pwArg); + if (wrappingKey) { + mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ + } else { + int keyLength; + /* if the wrappingKey doesn't exist, attempt to create it. + * Note: we intentionally ignore errors here. If we cannot + * generate a wrapping key, it is not fatal to this SSL connection, + * but we will not be able to restart this session. + */ + mechanism = PK11_GetBestWrapMechanism(symKeySlot); + keyLength = PK11_GetBestKeyLength(symKeySlot, mechanism); + /* Zero length means fixed key length algorithm, or error. + * It's ambiguous. + */ + wrappingKey = PK11_KeyGen(symKeySlot, mechanism, NULL, + keyLength, pwArg); + if (wrappingKey) { + PK11_SetWrapKey(symKeySlot, wrapKeyIndex, wrappingKey); + } + } + } else { + /* server socket using session cache. */ + mechanism = PK11_GetBestWrapMechanism(symKeySlot); + if (mechanism != CKM_INVALID_MECHANISM) { + wrappingKey = + getWrappingKey(ss, symKeySlot, effectiveExchKeyType, + mechanism, pwArg); + if (wrappingKey) { + mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ + } + } + } + + sid->u.ssl3.masterWrapMech = mechanism; + PK11_FreeSlot(symKeySlot); + if (wrappingKey) { + SECItem wmsItem; + + wmsItem.data = sid->u.ssl3.keys.wrapped_master_secret; + wmsItem.len = sizeof sid->u.ssl3.keys.wrapped_master_secret; + rv = PK11_WrapSymKey(mechanism, NULL, wrappingKey, + ss->ssl3.crSpec->master_secret, &wmsItem); + /* rv is examined below. */ + sid->u.ssl3.keys.wrapped_master_secret_len = wmsItem.len; + PK11_FreeSymKey(wrappingKey); + } + return rv; +} /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 Finished message from the peer. @@ -6864,31 +6956,26 @@ static SECStatus ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, const SSL3Hashes *hashes) { - ssl3State * ssl3 = ss->ssl3; sslSessionID * sid = ss->sec.ci.sid; - PK11SymKey * wrappingKey = NULL; - PK11SlotInfo * symKeySlot; - void * pwArg = ss->pkcs11PinArg; - SECStatus rv; + SECStatus rv = SECSuccess; PRBool isServer = ss->sec.isServer; PRBool isTLS; PRBool doStepUp; - CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; SSL3KEAType effectiveExchKeyType; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); SSL_TRC(3, ("%d: SSL3[%d]: handle finished handshake", SSL_GETPID(), ss->fd)); - if (ssl3->hs.ws != wait_finished) { + if (ss->ssl3.hs.ws != wait_finished) { SSL3_SendAlert(ss, alert_fatal, unexpected_message); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_FINISHED); return SECFailure; } - isTLS = (PRBool)(ssl3->crSpec->version > SSL_LIBRARY_VERSION_3_0); + isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0); if (isTLS) { TLSFinished tlsFinished; @@ -6897,7 +6984,7 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED); return SECFailure; } - rv = ssl3_ComputeTLSFinished(ssl3->crSpec, !isServer, + rv = ssl3_ComputeTLSFinished(ss->ssl3.crSpec, !isServer, hashes, &tlsFinished); if (rv != SECSuccess || 0 != PORT_Memcmp(&tlsFinished, b, length)) { @@ -6919,12 +7006,12 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, } } - doStepUp = (PRBool)(!isServer && ssl3->hs.rehandshake); + doStepUp = (PRBool)(!isServer && ss->ssl3.hs.rehandshake); ssl_GetXmitBufLock(ss); /*************************************/ - if ((isServer && !ssl3->hs.isResuming) || - (!isServer && ssl3->hs.isResuming)) { + if ((isServer && !ss->ssl3.hs.isResuming) || + (!isServer && ss->ssl3.hs.isResuming)) { PRInt32 flags = 0; rv = ssl3_SendChangeCipherSpecs(ss); @@ -6950,7 +7037,7 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, if (doStepUp) { ssl_FreeSID(sid); ss->sec.ci.sid = sid = NULL; - ssl3->hs.rehandshake = PR_FALSE; + ss->ssl3.hs.rehandshake = PR_FALSE; rv = ssl3_SendClientHello(ss); xmit_loser: ssl_ReleaseXmitBufLock(ss); @@ -6965,113 +7052,52 @@ xmit_loser: ss->gs.writeOffset = 0; ss->gs.readOffset = 0; - if (ssl3->hs.kea_def->kea == kea_ecdhe_rsa) { + if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) { effectiveExchKeyType = kt_rsa; } else { - effectiveExchKeyType = ssl3->hs.kea_def->exchKeyType; - } - - if (sid->cached == never_cached) { - - /* fill in the sid */ - sid->u.ssl3.cipherSuite = ssl3->hs.cipher_suite; - sid->u.ssl3.compression = ssl3->hs.compression; - sid->u.ssl3.policy = ssl3->policy; - sid->u.ssl3.exchKeyType = effectiveExchKeyType; - sid->version = ss->version; - sid->authAlgorithm = ss->sec.authAlgorithm; - sid->authKeyBits = ss->sec.authKeyBits; - sid->keaType = ss->sec.keaType; - sid->keaKeyBits = ss->sec.keaKeyBits; - sid->lastAccessTime = sid->creationTime = ssl_Time(); - sid->expirationTime = sid->creationTime + ssl3_sid_timeout; - sid->localCert = CERT_DupCertificate(ss->sec.localCert); - - ssl_GetSpecReadLock(ss); /*************************************/ - symKeySlot = PK11_GetSlotFromKey(ssl3->crSpec->master_secret); - if (!isServer) { - int wrapKeyIndex; - int incarnation; - - /* these next few functions are mere accessors and don't fail. */ - sid->u.ssl3.masterWrapIndex = wrapKeyIndex = - PK11_GetCurrentWrapIndex(symKeySlot); - PORT_Assert(wrapKeyIndex == 0); /* array has only one entry! */ - - sid->u.ssl3.masterWrapSeries = incarnation = - PK11_GetSlotSeries(symKeySlot); - sid->u.ssl3.masterSlotID = PK11_GetSlotID(symKeySlot); - sid->u.ssl3.masterModuleID = PK11_GetModuleID(symKeySlot); - sid->u.ssl3.masterValid = PR_TRUE; - - /* Get the default wrapping key, for wrapping the master secret before - * placing it in the SID cache entry. */ - wrappingKey = PK11_GetWrapKey(symKeySlot, wrapKeyIndex, - CKM_INVALID_MECHANISM, incarnation, - pwArg); - if (wrappingKey) { - mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ + effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType; + } + + if (sid->cached == never_cached && !ss->opt.noCache && ss->sec.cache) { + /* fill in the sid */ + sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite; + sid->u.ssl3.compression = ss->ssl3.hs.compression; + sid->u.ssl3.policy = ss->ssl3.policy; + sid->u.ssl3.exchKeyType = effectiveExchKeyType; + sid->version = ss->version; + sid->authAlgorithm = ss->sec.authAlgorithm; + sid->authKeyBits = ss->sec.authKeyBits; + sid->keaType = ss->sec.keaType; + sid->keaKeyBits = ss->sec.keaKeyBits; + sid->lastAccessTime = sid->creationTime = ssl_Time(); + sid->expirationTime = sid->creationTime + ssl3_sid_timeout; + sid->localCert = CERT_DupCertificate(ss->sec.localCert); + + ssl_GetSpecReadLock(ss); /*************************************/ + + /* Copy the master secret (wrapped or unwrapped) into the sid */ + if (ss->ssl3.crSpec->msItem.len && ss->ssl3.crSpec->msItem.data) { + sid->u.ssl3.keys.wrapped_master_secret_len = + ss->ssl3.crSpec->msItem.len; + memcpy(sid->u.ssl3.keys.wrapped_master_secret, + ss->ssl3.crSpec->msItem.data, ss->ssl3.crSpec->msItem.len); + sid->u.ssl3.masterValid = PR_TRUE; + sid->u.ssl3.keys.msIsWrapped = PR_FALSE; + rv = SECSuccess; } else { - int keyLength; - /* if the wrappingKey doesn't exist, attempt to create it. - * Note: we intentionally ignore errors here. If we cannot - * generate a wrapping key, it is not fatal to this SSL connection, - * but we will not be able to restart this session. - */ - mechanism = PK11_GetBestWrapMechanism(symKeySlot); - keyLength = PK11_GetBestKeyLength(symKeySlot, mechanism); - /* Zero length means fixed key length algorithm, or error. - * It's ambiguous. - */ - wrappingKey = PK11_KeyGen(symKeySlot, mechanism, NULL, - keyLength, pwArg); - if (wrappingKey) { - PK11_SetWrapKey(symKeySlot, wrapKeyIndex, wrappingKey); - } - } - } else if (!ss->noCache) { - /* server socket using session cache. */ - mechanism = PK11_GetBestWrapMechanism(symKeySlot); - if (mechanism != CKM_INVALID_MECHANISM) { - wrappingKey = - getWrappingKey(ss, symKeySlot, effectiveExchKeyType, - mechanism, pwArg); - if (wrappingKey) { - mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ - } + rv = ssl3_CacheWrappedMasterSecret(ss, effectiveExchKeyType); + sid->u.ssl3.keys.msIsWrapped = PR_TRUE; } - } - - sid->u.ssl3.masterWrapMech = mechanism; - PK11_FreeSlot(symKeySlot); - - rv = SECFailure; - if (wrappingKey) { - SECItem msItem; - - msItem.data = sid->u.ssl3.keys.wrapped_master_secret; - msItem.len = sizeof sid->u.ssl3.keys.wrapped_master_secret; - rv = PK11_WrapSymKey(mechanism, NULL, wrappingKey, - ssl3->crSpec->master_secret, &msItem); - /* rv is examined below. */ - sid->u.ssl3.keys.wrapped_master_secret_len = msItem.len; - PK11_FreeSymKey(wrappingKey); - } - ssl_ReleaseSpecReadLock(ss); /*************************************/ + ssl_ReleaseSpecReadLock(ss); /*************************************/ - /* If the wrap failed, we don't cache the sid. - * The connection continues normally however. - */ - if (!ss->noCache && rv == SECSuccess) { - if (ss->sec.cache) { + /* If the wrap failed, we don't cache the sid. + * The connection continues normally however. + */ + if (rv == SECSuccess) { (*ss->sec.cache)(sid); - } else { - PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); - return SECFailure; } } - } - ss->ssl3->hs.ws = idle_handshake; + ss->ssl3.hs.ws = idle_handshake; /* Do the handshake callback for sslv3 here. */ if (ss->handshakeCallback != NULL) { @@ -7089,12 +7115,12 @@ static SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { SECStatus rv = SECSuccess; - SSL3HandshakeType type = ss->ssl3->hs.msg_type; + SSL3HandshakeType type = ss->ssl3.hs.msg_type; SSL3Hashes hashes; /* computed hashes are put here. */ PRUint8 hdr[4]; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); /* * We have to compute the hashes before we update them with the * current message. @@ -7102,11 +7128,11 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ssl_GetSpecReadLock(ss); /************************************/ if((type == finished) || (type == certificate_verify)) { SSL3Sender sender = (SSL3Sender)0; - ssl3CipherSpec *rSpec = ss->ssl3->prSpec; + ssl3CipherSpec *rSpec = ss->ssl3.prSpec; if (type == finished) { sender = ss->sec.isServer ? sender_client : sender_server; - rSpec = ss->ssl3->crSpec; + rSpec = ss->ssl3.crSpec; } rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender); } @@ -7115,34 +7141,39 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return rv; /* error code was set by ssl3_ComputeHandshakeHashes*/ } SSL_TRC(30,("%d: SSL3[%d]: handle handshake message: %s", SSL_GETPID(), - ss->fd, ssl3_DecodeHandshakeType(ss->ssl3->hs.msg_type))); + ss->fd, ssl3_DecodeHandshakeType(ss->ssl3.hs.msg_type))); PRINT_BUF(60, (ss, "MD5 handshake hash:", - (unsigned char*)ss->ssl3->hs.md5, MD5_LENGTH)); + (unsigned char*)ss->ssl3.hs.md5_cx, MD5_LENGTH)); PRINT_BUF(95, (ss, "SHA handshake hash:", - (unsigned char*)ss->ssl3->hs.sha, SHA1_LENGTH)); + (unsigned char*)ss->ssl3.hs.sha_cx, SHA1_LENGTH)); - hdr[0] = (PRUint8)ss->ssl3->hs.msg_type; + hdr[0] = (PRUint8)ss->ssl3.hs.msg_type; hdr[1] = (PRUint8)(length >> 16); hdr[2] = (PRUint8)(length >> 8); hdr[3] = (PRUint8)(length ); /* Start new handshake hashes when we start a new handshake */ - if (ss->ssl3->hs.msg_type == client_hello) { + if (ss->ssl3.hs.msg_type == client_hello) { SSL_TRC(30,("%d: SSL3[%d]: reset handshake hashes", SSL_GETPID(), ss->fd )); - rv = PK11_DigestBegin(ss->ssl3->hs.md5); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - return rv; - } - rv = PK11_DigestBegin(ss->ssl3->hs.sha); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - return rv; + if (ss->opt.bypassPKCS11) { + MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); + SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); + } else { + rv = PK11_DigestBegin(ss->ssl3.hs.md5); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + return rv; + } + rv = PK11_DigestBegin(ss->ssl3.hs.sha); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + return rv; + } } } /* We should not include hello_request messages in the handshake hashes */ - if (ss->ssl3->hs.msg_type != hello_request) { + if (ss->ssl3.hs.msg_type != hello_request) { rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) hdr, 4); if (rv != SECSuccess) return rv; /* err code already set. */ rv = ssl3_UpdateHandshakeHashes(ss, b, length); @@ -7150,7 +7181,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } PORT_SetError(0); /* each message starts with no error. */ - switch (ss->ssl3->hs.msg_type) { + switch (ss->ssl3.hs.msg_type) { case hello_request: if (length != 0) { (void)ssl3_DecodeError(ss); @@ -7254,30 +7285,29 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) * Each message is made contiguous before being passed to the actual * message parser. */ - ssl3State *ssl3 = ss->ssl3; - sslBuffer *buf = &ssl3->hs.msgState; /* do not lose the original buffer pointer */ + sslBuffer *buf = &ss->ssl3.hs.msgState; /* do not lose the original buffer pointer */ SECStatus rv; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); if (buf->buf == NULL) { *buf = *origBuf; } while (buf->len > 0) { - if (ssl3->hs.header_bytes < 4) { + if (ss->ssl3.hs.header_bytes < 4) { uint8 t; t = *(buf->buf++); buf->len--; - if (ssl3->hs.header_bytes++ == 0) - ssl3->hs.msg_type = (SSL3HandshakeType)t; + if (ss->ssl3.hs.header_bytes++ == 0) + ss->ssl3.hs.msg_type = (SSL3HandshakeType)t; else - ssl3->hs.msg_len = (ssl3->hs.msg_len << 8) + t; - if (ssl3->hs.header_bytes < 4) + ss->ssl3.hs.msg_len = (ss->ssl3.hs.msg_len << 8) + t; + if (ss->ssl3.hs.header_bytes < 4) continue; #define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */ - if (ssl3->hs.msg_len > MAX_HANDSHAKE_MSG_LEN) { + if (ss->ssl3.hs.msg_len > MAX_HANDSHAKE_MSG_LEN) { (void)ssl3_DecodeError(ss); PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); return SECFailure; @@ -7287,7 +7317,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) /* If msg_len is zero, be sure we fall through, ** even if buf->len is zero. */ - if (ssl3->hs.msg_len > 0) + if (ss->ssl3.hs.msg_len > 0) continue; } @@ -7296,9 +7326,9 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) * data available for this message. If it can be done right out * of the original buffer, then use it from there. */ - if (ssl3->hs.msg_body.len == 0 && buf->len >= ssl3->hs.msg_len) { + if (ss->ssl3.hs.msg_body.len == 0 && buf->len >= ss->ssl3.hs.msg_len) { /* handle it from input buffer */ - rv = ssl3_HandleHandshakeMessage(ss, buf->buf, ssl3->hs.msg_len); + rv = ssl3_HandleHandshakeMessage(ss, buf->buf, ss->ssl3.hs.msg_len); if (rv == SECFailure) { /* This test wants to fall through on either * SECSuccess or SECWouldBlock. @@ -7306,10 +7336,10 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) */ return rv; } - buf->buf += ssl3->hs.msg_len; - buf->len -= ssl3->hs.msg_len; - ssl3->hs.msg_len = 0; - ssl3->hs.header_bytes = 0; + buf->buf += ss->ssl3.hs.msg_len; + buf->len -= ss->ssl3.hs.msg_len; + ss->ssl3.hs.msg_len = 0; + ss->ssl3.hs.header_bytes = 0; if (rv != SECSuccess) { /* return if SECWouldBlock. */ return rv; } @@ -7317,28 +7347,28 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) /* must be copied to msg_body and dealt with from there */ unsigned int bytes; - PORT_Assert(ssl3->hs.msg_body.len <= ssl3->hs.msg_len); - bytes = PR_MIN(buf->len, ssl3->hs.msg_len - ssl3->hs.msg_body.len); + PORT_Assert(ss->ssl3.hs.msg_body.len <= ss->ssl3.hs.msg_len); + bytes = PR_MIN(buf->len, ss->ssl3.hs.msg_len - ss->ssl3.hs.msg_body.len); /* Grow the buffer if needed */ - rv = sslBuffer_Grow(&ssl3->hs.msg_body, ssl3->hs.msg_len); + rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, ss->ssl3.hs.msg_len); if (rv != SECSuccess) { /* sslBuffer_Grow has set a memory error code. */ return SECFailure; } - PORT_Memcpy(ssl3->hs.msg_body.buf + ssl3->hs.msg_body.len, + PORT_Memcpy(ss->ssl3.hs.msg_body.buf + ss->ssl3.hs.msg_body.len, buf->buf, bytes); - ssl3->hs.msg_body.len += bytes; + ss->ssl3.hs.msg_body.len += bytes; buf->buf += bytes; buf->len -= bytes; - PORT_Assert(ssl3->hs.msg_body.len <= ssl3->hs.msg_len); + PORT_Assert(ss->ssl3.hs.msg_body.len <= ss->ssl3.hs.msg_len); /* if we have a whole message, do it */ - if (ssl3->hs.msg_body.len == ssl3->hs.msg_len) { + if (ss->ssl3.hs.msg_body.len == ss->ssl3.hs.msg_len) { rv = ssl3_HandleHandshakeMessage( - ss, ssl3->hs.msg_body.buf, ssl3->hs.msg_len); + ss, ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len); /* * XXX This appears to be wrong. This error handling * should clean up after a SECWouldBlock return, like the @@ -7348,9 +7378,9 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) /* ssl3_HandleHandshakeMessage MUST set error code. */ return rv; } - ssl3->hs.msg_body.len = 0; - ssl3->hs.msg_len = 0; - ssl3->hs.header_bytes = 0; + ss->ssl3.hs.msg_body.len = 0; + ss->ssl3.hs.msg_len = 0; + ss->ssl3.hs.header_bytes = 0; } else { PORT_Assert(buf->len == 0); break; @@ -7390,7 +7420,6 @@ SECStatus ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) { const ssl3BulkCipherDef *cipher_def; - ssl3State * ssl3 = ss->ssl3; ssl3CipherSpec * crSpec; SECStatus rv; unsigned int hashBytes = MAX_MAC_LENGTH + 1; @@ -7400,9 +7429,9 @@ const ssl3BulkCipherDef *cipher_def; SSL3ContentType rType; SSL3Opaque hash[MAX_MAC_LENGTH]; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); - if (ssl3 == NULL) { + if (!ss->ssl3.initialized) { ssl_GetSSL3HandshakeLock(ss); rv = ssl3_InitState(ss); ssl_ReleaseSSL3HandshakeLock(ss); @@ -7411,8 +7440,6 @@ const ssl3BulkCipherDef *cipher_def; } } - ssl3 = ss->ssl3; - /* check for Token Presence */ if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) { PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL); @@ -7446,7 +7473,7 @@ const ssl3BulkCipherDef *cipher_def; ssl_GetSpecReadLock(ss); /******************************************/ - crSpec = ssl3->crSpec; + crSpec = ss->ssl3.crSpec; cipher_def = crSpec->cipher_def; isTLS = (PRBool)(crSpec->version > SSL_LIBRARY_VERSION_3_0); @@ -7494,9 +7521,7 @@ const ssl3BulkCipherDef *cipher_def; /* compute the MAC */ rType = cText->type; - rv = ssl3_ComputeRecordMAC( - crSpec, (ss->sec.isServer) ? crSpec->client.write_mac_context - : crSpec->server.write_mac_context, + rv = ssl3_ComputeRecordMAC( crSpec, (PRBool)(!ss->sec.isServer), rType, cText->version, crSpec->read_seq_num, databuf->buf, databuf->len, hash, &hashBytes); if (rv != SECSuccess) { @@ -7603,6 +7628,10 @@ ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) spec->destroy = NULL; spec->mac_size = 0; spec->master_secret = NULL; + spec->bypassCiphers = PR_FALSE; + + spec->msItem.data = NULL; + spec->msItem.len = 0; spec->client.write_key = NULL; spec->client.write_mac_key = NULL; @@ -7618,7 +7647,7 @@ ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) spec->read_seq_num.high = 0; spec->read_seq_num.low = 0; - spec->version = ss->enableTLS + spec->version = ss->opt.enableTLS ? SSL_LIBRARY_VERSION_3_1_TLS : SSL_LIBRARY_VERSION_3_0; } @@ -7638,32 +7667,24 @@ ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) static SECStatus ssl3_InitState(sslSocket *ss) { - ssl3State * ssl3 = NULL; PK11Context *md5 = NULL; PK11Context *sha = NULL; SECStatus rv; + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss)); + if (ss->ssl3.initialized) + return SECSuccess; /* Function should be idempotent */ - /* reinitialization for renegotiated sessions XXX */ - if (ss->ssl3 != NULL) - return SECSuccess; - - ssl3 = PORT_ZNew(ssl3State); /* zero on purpose */ - if (ssl3 == NULL) - return SECFailure; /* PORT_ZAlloc has set memory error code. */ - - /* note that entire HandshakeState is zero, including the buffer */ - ssl3->policy = SSL_ALLOWED; + ss->ssl3.policy = SSL_ALLOWED; ssl_GetSpecWriteLock(ss); - ssl3->crSpec = ssl3->cwSpec = &ssl3->specs[0]; - ssl3->prSpec = ssl3->pwSpec = &ssl3->specs[1]; - ssl3->hs.rehandshake = PR_FALSE; - ssl3_InitCipherSpec(ss, ssl3->crSpec); - ssl3_InitCipherSpec(ss, ssl3->prSpec); + ss->ssl3.crSpec = ss->ssl3.cwSpec = &ss->ssl3.specs[0]; + ss->ssl3.prSpec = ss->ssl3.pwSpec = &ss->ssl3.specs[1]; + ss->ssl3.hs.rehandshake = PR_FALSE; + ssl3_InitCipherSpec(ss, ss->ssl3.crSpec); + ssl3_InitCipherSpec(ss, ss->ssl3.prSpec); - ssl3->hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; + ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; ssl_ReleaseSpecWriteLock(ss); /* @@ -7672,37 +7693,40 @@ ssl3_InitState(sslSocket *ss) * that the master secret will wind up in ... */ SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd)); - ssl3->hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); - if (md5 == NULL) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - goto loser; - } - rv = PK11_DigestBegin(ssl3->hs.md5); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); - goto loser; - } + if (ss->opt.bypassPKCS11) { + MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx); + SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx); + } else { + ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5); + if (md5 == NULL) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + goto loser; + } + rv = PK11_DigestBegin(ss->ssl3.hs.md5); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + goto loser; + } - sha = ssl3->hs.sha = PK11_CreateDigestContext(SEC_OID_SHA1); - if (sha == NULL) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; - } - rv = PK11_DigestBegin(ssl3->hs.sha); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); - goto loser; + sha = ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA1); + if (sha == NULL) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + goto loser; + } + rv = PK11_DigestBegin(ss->ssl3.hs.sha); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + goto loser; + } } - /* Don't hide this from the rest of the world any more. */ - ss->ssl3 = ssl3; + ss->ssl3.initialized = PR_TRUE; return SECSuccess; loser: if (md5 != NULL) PK11_DestroyContext(md5, PR_TRUE); if (sha != NULL) PK11_DestroyContext(sha, PR_TRUE); - if (ssl3 != NULL) PORT_Free(ssl3); return SECFailure; } @@ -7715,7 +7739,8 @@ ssl3_NewKeyPair( SECKEYPrivateKey * privKey, SECKEYPublicKey * pubKey) { ssl3KeyPair * pair; - if (!privKey || !pubKey) { + if (!privKey && !pubKey) { + /* one or the other may be NULL, but not both. */ PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return NULL; } @@ -7740,8 +7765,10 @@ ssl3_FreeKeyPair(ssl3KeyPair * keyPair) { PRInt32 newCount = PR_AtomicDecrement(&keyPair->refCount); if (!newCount) { - SECKEY_DestroyPrivateKey(keyPair->privKey); - SECKEY_DestroyPublicKey( keyPair->pubKey); + if (keyPair->privKey) + SECKEY_DestroyPrivateKey(keyPair->privKey); + if (keyPair->pubKey) + SECKEY_DestroyPublicKey( keyPair->pubKey); PORT_Free(keyPair); } } @@ -7764,7 +7791,7 @@ ssl3_CreateRSAStepDownKeys(sslSocket *ss) ss->stepDownKeyPair = NULL; #ifndef HACKED_EXPORT_SERVER /* Sigh, should have a get key strength call for private keys */ - if (PK11_GetPrivateModulusLen(ss->serverCerts[kt_rsa].serverKey) > + if (PK11_GetPrivateModulusLen(ss->serverCerts[kt_rsa].SERVERKEY) > EXPORT_RSA_KEY_LENGTH) { /* need to ask for the key size in bits */ privKey = SECKEY_CreateRSAPrivateKey(EXPORT_RSA_KEY_LENGTH * BPB, @@ -7779,40 +7806,6 @@ ssl3_CreateRSAStepDownKeys(sslSocket *ss) return rv; } -#ifdef NSS_ENABLE_ECC -/* - * Creates the ephemeral public and private ECDH keys used by - * server in ECDHE_RSA and ECDHE_ECDSA handshakes. - * XXX For now, the elliptic curve is hardcoded to NIST P-224. - * We need an API to specify the curve. This won't be a real - * issue until we further develop server-side support for ECC - * cipher suites. - */ -SECStatus -ssl3_CreateECDHEphemeralKeys(sslSocket *ss) -{ - SECStatus rv = SECSuccess; - SECKEYPrivateKey * privKey; - SECKEYPublicKey * pubKey; - SECKEYECParams ecParams = { siBuffer, NULL, 0 }; - - if (ss->ephemeralECDHKeyPair) - ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); - ss->ephemeralECDHKeyPair = NULL; - - if (ecName2params(NULL, ec_secp224r1, &ecParams) == SECFailure) - return SECFailure; - privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL); - if (!privKey || !pubKey || - !(ss->ephemeralECDHKeyPair = ssl3_NewKeyPair(privKey, pubKey))) { - ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); - rv = SECFailure; - } - - PORT_Free(ecParams.data); - return rv; -} -#endif /* NSS_ENABLE_ECC */ /* record the export policy for this cipher suite */ SECStatus @@ -7938,7 +7931,7 @@ ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, unsigned char *cs, int *size) PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return SECFailure; } - if (!ss->enableSSL3 && !ss->enableTLS) { + if (!ss->opt.enableSSL3 && !ss->opt.enableTLS) { *size = 0; return SECSuccess; } @@ -7977,11 +7970,12 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) sslSessionID * sid = ss->sec.ci.sid; SECStatus rv; - PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); if (!ss->firstHsDone || ((ss->version >= SSL_LIBRARY_VERSION_3_0) && - ss->ssl3 && (ss->ssl3->hs.ws != idle_handshake))) { + ss->ssl3.initialized && + (ss->ssl3.hs.ws != idle_handshake))) { PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); return SECFailure; } @@ -8003,41 +7997,43 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) /* Called from ssl_FreeSocket() in sslsock.c */ void -ssl3_DestroySSL3Info(ssl3State *ssl3) +ssl3_DestroySSL3Info(sslSocket *ss) { - if (ssl3 == NULL) - return; /* success the easy way. */ - if (ssl3->clientCertificate != NULL) - CERT_DestroyCertificate(ssl3->clientCertificate); + if (ss->ssl3.clientCertificate != NULL) + CERT_DestroyCertificate(ss->ssl3.clientCertificate); - if (ssl3->clientPrivateKey != NULL) - SECKEY_DestroyPrivateKey(ssl3->clientPrivateKey); + if (ss->ssl3.clientPrivateKey != NULL) + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); - if (ssl3->peerCertArena != NULL) - ssl3_CleanupPeerCerts(ssl3); + if (ss->ssl3.peerCertArena != NULL) + ssl3_CleanupPeerCerts(ss); - if (ssl3->clientCertChain != NULL) { - CERT_DestroyCertificateList(ssl3->clientCertChain); - ssl3->clientCertChain = NULL; + if (ss->ssl3.clientCertChain != NULL) { + CERT_DestroyCertificateList(ss->ssl3.clientCertChain); + ss->ssl3.clientCertChain = NULL; } /* clean up handshake */ - if (ssl3->hs.md5) { - PK11_DestroyContext(ssl3->hs.md5,PR_TRUE); + if (ss->opt.bypassPKCS11) { + SHA1_DestroyContext((SHA1Context *)ss->ssl3.hs.sha_cx, PR_FALSE); + MD5_DestroyContext((MD5Context *)ss->ssl3.hs.md5_cx, PR_FALSE); + } + if (ss->ssl3.hs.md5) { + PK11_DestroyContext(ss->ssl3.hs.md5,PR_TRUE); } - if (ssl3->hs.sha) { - PK11_DestroyContext(ssl3->hs.sha,PR_TRUE); + if (ss->ssl3.hs.sha) { + PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE); } /* free the SSL3Buffer (msg_body) */ - PORT_Free(ssl3->hs.msg_body.buf); + PORT_Free(ss->ssl3.hs.msg_body.buf); /* free up the CipherSpecs */ - ssl3_DestroyCipherSpec(&ssl3->specs[0]); - ssl3_DestroyCipherSpec(&ssl3->specs[1]); + ssl3_DestroyCipherSpec(&ss->ssl3.specs[0]); + ssl3_DestroyCipherSpec(&ss->ssl3.specs[1]); - PORT_Free(ssl3); + ss->ssl3.initialized = PR_FALSE; } /* End of ssl3con.c */ diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c new file mode 100644 index 000000000..9edbe9122 --- /dev/null +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -0,0 +1,675 @@ +/* + * SSL3 Protocol + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com> and + * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/* ECC code moved here from ssl3con.c */ +/* $Id$ */ + +#ifdef NSS_ENABLE_ECC + +#include "nssrenam.h" +#include "cert.h" +#include "ssl.h" +#include "cryptohi.h" /* for DSAU_ stuff */ +#include "keyhi.h" +#include "secder.h" +#include "secitem.h" + +#include "sslimpl.h" +#include "sslproto.h" +#include "sslerr.h" +#include "prtime.h" +#include "prinrval.h" +#include "prerror.h" +#include "pratom.h" +#include "prthread.h" + +#include "pk11func.h" +#include "secmod.h" +#include "nsslocks.h" +#include "ec.h" +#include "blapi.h" + +#include <stdio.h> + +/* + line 297: implicit function declaration: ssl3_InitPendingCipherSpec + line 305: implicit function declaration: ssl3_AppendHandshakeHeader + line 311: implicit function declaration: ssl3_AppendHandshakeVariable + line 356: implicit function declaration: ssl3_ConsumeHandshakeVariable +*/ + + +#ifndef PK11_SETATTRS +#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ + (x)->pValue=(v); (x)->ulValueLen = (l); +#endif + +/* Types and names of elliptic curves used in TLS */ +typedef enum { ec_type_explicitPrime = 1, + ec_type_explicitChar2Curve, + ec_type_named +} ECType; + +typedef enum { ec_noName = 0, + ec_sect163k1, ec_sect163r1, ec_sect163r2, + ec_sect193r1, ec_sect193r2, ec_sect233k1, + ec_sect233r1, ec_sect239k1, ec_sect283k1, + ec_sect283r1, ec_sect409k1, ec_sect409r1, + ec_sect571k1, ec_sect571r1, ec_secp160k1, + ec_secp160r1, ec_secp160r2, ec_secp192k1, + ec_secp192r1, ec_secp224k1, ec_secp224r1, + ec_secp256k1, ec_secp256r1, ec_secp384r1, + ec_secp521r1, + ec_pastLastName +} ECName; + +#define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName)) + +/* Table containing OID tags for elliptic curves named in the + * ECC-TLS IETF draft. + */ +static const SECOidTag ecName2OIDTag[] = { + 0, + SEC_OID_SECG_EC_SECT163K1, /* 1 */ + SEC_OID_SECG_EC_SECT163R1, /* 2 */ + SEC_OID_SECG_EC_SECT163R2, /* 3 */ + SEC_OID_SECG_EC_SECT193R1, /* 4 */ + SEC_OID_SECG_EC_SECT193R2, /* 5 */ + SEC_OID_SECG_EC_SECT233K1, /* 6 */ + SEC_OID_SECG_EC_SECT233R1, /* 7 */ + SEC_OID_SECG_EC_SECT239K1, /* 8 */ + SEC_OID_SECG_EC_SECT283K1, /* 9 */ + SEC_OID_SECG_EC_SECT283R1, /* 10 */ + SEC_OID_SECG_EC_SECT409K1, /* 11 */ + SEC_OID_SECG_EC_SECT409R1, /* 12 */ + SEC_OID_SECG_EC_SECT571K1, /* 13 */ + SEC_OID_SECG_EC_SECT571R1, /* 14 */ + SEC_OID_SECG_EC_SECP160K1, /* 15 */ + SEC_OID_SECG_EC_SECP160R1, /* 16 */ + SEC_OID_SECG_EC_SECP160R2, /* 17 */ + SEC_OID_SECG_EC_SECP192K1, /* 18 */ + SEC_OID_SECG_EC_SECP192R1, /* 19 */ + SEC_OID_SECG_EC_SECP224K1, /* 20 */ + SEC_OID_SECG_EC_SECP224R1, /* 21 */ + SEC_OID_SECG_EC_SECP256K1, /* 22 */ + SEC_OID_SECG_EC_SECP256R1, /* 23 */ + SEC_OID_SECG_EC_SECP384R1, /* 24 */ + SEC_OID_SECG_EC_SECP521R1, /* 25 */ +}; + +static SECStatus +ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params) +{ + SECOidData *oidData = NULL; + + if ((curve <= ec_noName) || (curve >= ec_pastLastName) || + ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + } + + SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)); + /* + * params->data needs to contain the ASN encoding of an object ID (OID) + * representing the named curve. The actual OID is in + * oidData->oid.data so we simply prepend 0x06 and OID length + */ + params->data[0] = SEC_ASN1_OBJECT_ID; + params->data[1] = oidData->oid.len; + memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); + + return SECSuccess; +} + +static ECName +params2ecName(SECKEYECParams * params) +{ + SECItem oid = { siBuffer, NULL, 0}; + SECOidData *oidData = NULL; + ECName i; + + /* + * params->data needs to contain the ASN encoding of an object ID (OID) + * representing a named curve. Here, we strip away everything + * before the actual OID and use the OID to look up a named curve. + */ + if (params->data[0] != SEC_ASN1_OBJECT_ID) return ec_noName; + oid.len = params->len - 2; + oid.data = params->data + 2; + if ((oidData = SECOID_FindOID(&oid)) == NULL) return ec_noName; + for (i = ec_noName + 1; i < ec_pastLastName; i++) { + if (ecName2OIDTag[i] == oidData->offset) + return i; + } + + return ec_noName; +} + +/* Caller must set hiLevel error code. */ +static SECStatus +ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, + SSL3Random *client_rand, SSL3Random *server_rand, + SSL3Hashes *hashes, PRBool bypassPKCS11) +{ + PRUint8 * hashBuf; + PRUint8 * pBuf; + SECStatus rv = SECSuccess; + unsigned int bufLen; + /* + * XXX For now, we only support named curves (the appropriate + * checks are made before this method is called) so ec_params + * takes up only two bytes. ECPoint needs to fit in 256 bytes + * (because the spec says the length must fit in one byte) + */ + PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 1 + 256]; + + bufLen = 2*SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len; + if (bufLen <= sizeof buf) { + hashBuf = buf; + } else { + hashBuf = PORT_Alloc(bufLen); + if (!hashBuf) { + return SECFailure; + } + } + + memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); + pBuf = hashBuf + SSL3_RANDOM_LENGTH; + memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); + pBuf += SSL3_RANDOM_LENGTH; + memcpy(pBuf, ec_params.data, ec_params.len); + pBuf += ec_params.len; + pBuf[0] = (PRUint8)(server_ecpoint.len); + pBuf += 1; + memcpy(pBuf, server_ecpoint.data, server_ecpoint.len); + pBuf += server_ecpoint.len; + PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); + + rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11); + + PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); + PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); + +done: + if (hashBuf != buf && hashBuf != NULL) + PORT_Free(hashBuf); + return rv; +} + + +/* Called from ssl3_SendClientKeyExchange(). */ +SECStatus +ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) +{ + PK11SymKey * pms = NULL; + SECStatus rv = SECFailure; + PRBool isTLS; + CK_MECHANISM_TYPE target; + SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ + SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ + CK_EC_KDF_TYPE kdf; + + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + + /* Generate ephemeral EC keypair */ + privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, + &pubKey, NULL); + if (!privKey || !pubKey) { + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); + rv = SECFailure; + goto loser; + } + PRINT_BUF(50, (ss, "ECDH public value:", + pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len)); + + if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; + else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + + /* If field size is not more than 24 octets, then use SHA-1 hash of result; + * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt). + */ + if ((pubKey->u.ec.publicValue.len - 1) / 2 <= 24) { + kdf = CKD_SHA1_KDF; + } else { + kdf = CKD_NULL; + } + + /* Determine the PMS */ + pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, + CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, + kdf, NULL, NULL); + + if (pms == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + SECKEY_DestroyPrivateKey(privKey); + privKey = NULL; + + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); pms = NULL; + + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, + pubKey->u.ec.publicValue.len + 1); + if (rv != SECSuccess) { + goto loser; /* err set by ssl3_AppendHandshake* */ + } + + rv = ssl3_AppendHandshakeVariable(ss, + pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len, 1); + SECKEY_DestroyPublicKey(pubKey); + pubKey = NULL; + + if (rv != SECSuccess) { + goto loser; /* err set by ssl3_AppendHandshake* */ + } + + rv = SECSuccess; + +loser: + if(pms) PK11_FreeSymKey(pms); + if(privKey) SECKEY_DestroyPrivateKey(privKey); + if(pubKey) SECKEY_DestroyPublicKey(pubKey); + return rv; +} + + +/* +** Called from ssl3_HandleClientKeyExchange() +*/ +SECStatus +ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, + PRUint32 length, + SECKEYPublicKey *srvrPubKey, + SECKEYPrivateKey *srvrPrivKey) +{ + PK11SymKey * pms; + SECStatus rv; + SECKEYPublicKey clntPubKey; + CK_MECHANISM_TYPE target; + PRBool isTLS; + CK_EC_KDF_TYPE kdf; + + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); + + clntPubKey.keyType = ecKey; + clntPubKey.u.ec.DEREncodedParams.len = + srvrPubKey->u.ec.DEREncodedParams.len; + clntPubKey.u.ec.DEREncodedParams.data = + srvrPubKey->u.ec.DEREncodedParams.data; + + rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, + 1, &b, &length); + if (rv != SECSuccess) { + SEND_ALERT + return SECFailure; /* XXX Who sets the error code?? */ + } + + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + + if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; + else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + + /* If field size is not more than 24 octets, then use SHA-1 hash of result; + * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt). + */ + if (srvrPubKey->u.ec.size <= 24 * 8) { + kdf = CKD_SHA1_KDF; + } else { + kdf = CKD_NULL; + } + + /* Determine the PMS */ + pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, + CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, + kdf, NULL, NULL); + + PORT_Free(clntPubKey.u.ec.publicValue.data); + + if (pms == NULL) { + /* last gasp. */ + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + return SECFailure; + } + + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); + if (rv != SECSuccess) { + SEND_ALERT + return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ + } + return SECSuccess; +} + + +/* + * Creates the ephemeral public and private ECDH keys used by + * server in ECDHE_RSA and ECDHE_ECDSA handshakes. + * XXX For now, the elliptic curve is hardcoded to NIST P-224. + * We need an API to specify the curve. This won't be a real + * issue until we further develop server-side support for ECC + * cipher suites. + */ +SECStatus +ssl3_CreateECDHEphemeralKeys(sslSocket *ss) +{ + SECStatus rv = SECSuccess; + SECKEYPrivateKey * privKey; + SECKEYPublicKey * pubKey; + SECKEYECParams ecParams = { siBuffer, NULL, 0 }; + + if (ss->ephemeralECDHKeyPair) + ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); + ss->ephemeralECDHKeyPair = NULL; + + if (ecName2params(NULL, ec_secp224r1, &ecParams) == SECFailure) + return SECFailure; + privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL); + if (!privKey || !pubKey || + !(ss->ephemeralECDHKeyPair = ssl3_NewKeyPair(privKey, pubKey))) { + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); + rv = SECFailure; + } + + PORT_Free(ecParams.data); + return rv; +} + +SECStatus +ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +{ + PRArenaPool * arena = NULL; + SECKEYPublicKey *peerKey = NULL; + PRBool isTLS; + SECStatus rv; + int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; + SSL3AlertDescription desc = illegal_parameter; + SSL3Hashes hashes; + SECItem signature = {siBuffer, NULL, 0}; + + SECItem ec_params = {siBuffer, NULL, 0}; + SECItem ec_point = {siBuffer, NULL, 0}; + unsigned char paramBuf[2]; + + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + + /* XXX This works only for named curves, revisit this when + * we support generic curves. + */ + ec_params.len = 2; + ec_params.data = paramBuf; + rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, + &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + + /* Fail if the curve is not a named curve */ + if ((ec_params.data[0] != ec_type_named) || + !supportedCurve(ec_params.data[1])) { + errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; + desc = handshake_failure; + goto alert_loser; + } + + rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + /* Fail if the ec point uses compressed representation */ + if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { + errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; + desc = handshake_failure; + goto alert_loser; + } + + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + + if (length != 0) { + if (isTLS) + desc = decode_error; + goto alert_loser; /* malformed. */ + } + + PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, + ec_params.len)); + PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); + + /* failures after this point are not malformed handshakes. */ + /* TLS: send decrypt_error if signature failed. */ + desc = isTLS ? decrypt_error : handshake_failure; + + /* + * check to make sure the hash is signed by right guy + */ + rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); + + if (rv != SECSuccess) { + errCode = + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto alert_loser; + } + rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, + isTLS, ss->pkcs11PinArg); + if (rv != SECSuccess) { + errCode = + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto alert_loser; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + goto no_memory; + } + + ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); + if (peerKey == NULL) { + goto no_memory; + } + + peerKey->arena = arena; + peerKey->keyType = ecKey; + + /* set up EC parameters in peerKey */ + if (ecName2params(arena, ec_params.data[1], + &peerKey->u.ec.DEREncodedParams) != SECSuccess) { + /* we should never get here since we already + * checked that we are dealing with a supported curve + */ + errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; + goto alert_loser; + } + + /* copy publicValue in peerKey */ + if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point)) + { + PORT_FreeArena(arena, PR_FALSE); + goto no_memory; + } + peerKey->pkcs11Slot = NULL; + peerKey->pkcs11ID = CK_INVALID_HANDLE; + + ss->sec.peerKey = peerKey; + ss->ssl3.hs.ws = wait_cert_request; + + return SECSuccess; + +alert_loser: + (void)SSL3_SendAlert(ss, alert_fatal, desc); +loser: + PORT_SetError( errCode ); + return SECFailure; + +no_memory: /* no-memory error has already been set. */ + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + return SECFailure; +} + +SECStatus +ssl3_SendECDHServerKeyExchange(sslSocket *ss) +{ +const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; + SECStatus rv = SECFailure; + int length; + PRBool isTLS; + SECItem signed_hash = {siBuffer, NULL, 0}; + SSL3Hashes hashes; + + SECKEYPublicKey * ecdhePub; + SECItem ec_params = {siBuffer, NULL, 0}; + ECName curve; + SSL3KEAType certIndex; + + + /* Generate ephemeral ECDH key pair and send the public key */ + rv = ssl3_CreateECDHEphemeralKeys(ss); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + ecdhePub = ss->ephemeralECDHKeyPair->pubKey; + PORT_Assert(ecdhePub != NULL); + if (!ecdhePub) { + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + return SECFailure; + } + + ec_params.len = 2; + ec_params.data = (unsigned char*)PORT_Alloc(ec_params.len); + curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams); + if (curve != ec_noName) { + ec_params.data[0] = ec_type_named; + ec_params.data[1] = curve; + } else { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + goto loser; + } + + rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue, + &ss->ssl3.hs.client_random, + &ss->ssl3.hs.server_random, + &hashes, ss->opt.bypassPKCS11); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto loser; + } + + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); + + /* XXX SSLKEAType isn't really a good choice for + * indexing certificates but that's all we have + * for now. + */ + if (kea_def->kea == kea_ecdhe_rsa) + certIndex = kt_rsa; + else /* kea_def->kea == kea_ecdhe_ecdsa */ + certIndex = kt_ecdh; + + rv = ssl3_SignHashes(&hashes, ss->serverCerts[certIndex].SERVERKEY, + &signed_hash, isTLS); + if (rv != SECSuccess) { + goto loser; /* ssl3_SignHashes has set err. */ + } + if (signed_hash.data == NULL) { + /* how can this happen and rv == SECSuccess ?? */ + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto loser; + } + + length = ec_params.len + + 1 + ecdhePub->u.ec.publicValue.len + + 2 + signed_hash.len; + + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data, + ecdhePub->u.ec.publicValue.len, 1); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, + signed_hash.len, 2); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + PORT_Free(ec_params.data); + PORT_Free(signed_hash.data); + return SECSuccess; + +loser: + if (ec_params.data != NULL) + PORT_Free(ec_params.data); + if (signed_hash.data != NULL) + PORT_Free(signed_hash.data); + return SECFailure; +} + + +#endif /* NSS_ENABLE_ECC */ + diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index 7fbf7663e..4465c4359 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -72,7 +72,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags) int err; int rv = 1; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); if (gs->state == GS_INIT) { gs->state = GS_HEADER; gs->remainder = 5; @@ -189,7 +189,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) SSL3Ciphertext cText; int rv; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); do { /* bring in the next sslv3 record. */ rv = ssl3_GatherData(ss, &ss->gs, flags); @@ -207,7 +207,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) if (rv < 0) { return ss->recvdCloseNotify ? 0 : rv; } - } while (ss->ssl3->hs.ws != idle_handshake && ss->gs.buf.len == 0); + } while (ss->ssl3.hs.ws != idle_handshake && ss->gs.buf.len == 0); ss->gs.readOffset = 0; ss->gs.writeOffset = ss->gs.buf.len; @@ -230,7 +230,7 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags) { int rv; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); do { rv = ssl3_GatherCompleteHandshake(ss, flags); } while (rv > 0 && ss->gs.buf.len == 0); diff --git a/security/nss/lib/ssl/sslauth.c b/security/nss/lib/ssl/sslauth.c index 24d250018..848f5aa63 100644 --- a/security/nss/lib/ssl/sslauth.c +++ b/security/nss/lib/ssl/sslauth.c @@ -53,7 +53,7 @@ SSL_PeerCertificate(PRFileDesc *fd) SSL_GETPID(), fd)); return 0; } - if (ss->useSecurity && ss->sec.peerCert) { + if (ss->opt.useSecurity && ss->sec.peerCert) { return CERT_DupCertificate(ss->sec.peerCert); } return 0; @@ -71,7 +71,7 @@ SSL_LocalCertificate(PRFileDesc *fd) SSL_GETPID(), fd)); return NULL; } - if (ss->useSecurity) { + if (ss->opt.useSecurity) { if (ss->sec.localCert) { return CERT_DupCertificate(ss->sec.localCert); } @@ -109,7 +109,7 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1, *op = SSL_SECURITY_STATUS_OFF; } - if (ss->useSecurity && ss->firstHsDone) { + if (ss->opt.useSecurity && ss->firstHsDone) { if (ss->version < SSL_LIBRARY_VERSION_3_0) { cipherName = ssl_cipherName[ss->sec.cipherType]; diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c index 278478fc6..06ec09813 100644 --- a/security/nss/lib/ssl/sslcon.c +++ b/security/nss/lib/ssl/sslcon.c @@ -186,11 +186,11 @@ ssl2_ConstructCipherSpecs(sslSocket *ss) int i; SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); count = 0; PORT_Assert(ss != 0); - allowed = !ss->enableSSL2 ? 0 : + allowed = !ss->opt.enableSSL2 ? 0 : (ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED); while (allowed) { if (allowed & 1) @@ -226,7 +226,7 @@ ssl2_ConstructCipherSpecs(sslSocket *ss) ss->sizeCipherSpecs = count * 3; /* fill in cipher specs for SSL2 cipher suites */ - allowed = !ss->enableSSL2 ? 0 : + allowed = !ss->opt.enableSSL2 ? 0 : (ss->allowedByPolicy & ss->chosenPreference & SSL_CB_IMPLEMENTED); for (i = 0; i < ssl2_NUM_SUITES_IMPLEMENTED * 3; i += 3) { const PRUint8 * hs = implementedCipherSuites + i; @@ -271,17 +271,17 @@ ssl2_CheckConfigSanity(sslSocket *ss) allowed = ss->allowedByPolicy & ss->chosenPreference; if (! allowed) - ss->enableSSL2 = PR_FALSE; /* not really enabled if no ciphers */ + ss->opt.enableSSL2 = PR_FALSE; /* not really enabled if no ciphers */ /* ssl3_config_match_init was called in ssl2_ConstructCipherSpecs(). */ /* Ask how many ssl3 CipherSuites were enabled. */ rv = ssl3_ConstructV2CipherSpecsHack(ss, NULL, &ssl3CipherCount); if (rv != SECSuccess || ssl3CipherCount <= 0) { - ss->enableSSL3 = PR_FALSE; /* not really enabled if no ciphers */ - ss->enableTLS = PR_FALSE; + ss->opt.enableSSL3 = PR_FALSE; /* not really enabled if no ciphers */ + ss->opt.enableTLS = PR_FALSE; } - if (!ss->enableSSL2 && !ss->enableSSL3 && !ss->enableTLS) { + if (!ss->opt.enableSSL2 && !ss->opt.enableSSL3 && !ss->opt.enableTLS) { SSL_DBG(("%d: SSL[%d]: Can't handshake! both v2 and v3 disabled.", SSL_GETPID(), ss->fd)); disabled: @@ -495,7 +495,7 @@ ssl2_GetSendBuffer(sslSocket *ss, unsigned int len) { SECStatus rv = SECSuccess; - PORT_Assert(ssl_HaveXmitBufLock(ss)); + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); if (len < 128) { len = 128; @@ -530,7 +530,7 @@ ssl2_SendErrorMessage(sslSocket *ss, int error) int rv; PRUint8 msg[SSL_HL_ERROR_HBYTES]; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); msg[0] = SSL_MT_ERROR; msg[1] = MSB(error); @@ -559,7 +559,7 @@ ssl2_SendClientFinishedMessage(sslSocket *ss) int sent; PRUint8 msg[1 + SSL_CONNECTIONID_BYTES]; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetXmitBufLock(ss); /***************************************/ @@ -595,7 +595,7 @@ ssl2_SendServerVerifyMessage(sslSocket *ss) int sent; SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetXmitBufLock(ss); /***************************************/ @@ -630,7 +630,7 @@ ssl2_SendServerFinishedMessage(sslSocket *ss) int sendLen, sent; SECStatus rv = SECSuccess; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetXmitBufLock(ss); /***************************************/ @@ -660,7 +660,7 @@ ssl2_SendServerFinishedMessage(sslSocket *ss) /* If send failed, it is now a bogus session-id */ (*ss->sec.uncache)(sid); rv = (SECStatus)sent; - } else if (!ss->noCache) { + } else if (!ss->opt.noCache) { /* Put the sid in session-id cache, (may already be there) */ (*ss->sec.cache)(sid); rv = SECSuccess; @@ -689,7 +689,7 @@ ssl2_SendSessionKeyMessage(sslSocket *ss, int cipher, int keySize, int sent; SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetXmitBufLock(ss); /***************************************/ @@ -735,7 +735,7 @@ ssl2_SendCertificateRequestMessage(sslSocket *ss) int sendLen; SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetXmitBufLock(ss); /***************************************/ @@ -775,7 +775,7 @@ ssl2_SendCertificateResponseMessage(sslSocket *ss, SECItem *cert, PRUint8 *msg; int rv, sendLen; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetXmitBufLock(ss); /***************************************/ @@ -887,7 +887,7 @@ ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) int amount; int count = 0; - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes in the clear", SSL_GETPID(), ss->fd, len)); @@ -962,7 +962,7 @@ ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) int nout; int buflen; - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using stream cipher", SSL_GETPID(), ss->fd, len)); @@ -1067,7 +1067,7 @@ ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) int nout; /* ciphertext size after header. */ int buflen; /* size of generated record. */ - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); SSL_TRC(10, ("%d: SSL[%d]: sending %d bytes using block cipher", SSL_GETPID(), ss->fd, len)); @@ -1251,7 +1251,7 @@ ssl_GatherRecord1stHandshake(sslSocket *ss) { int rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetRecvBufLock(ss); @@ -1369,7 +1369,7 @@ ssl2_ProduceKeys(sslSocket * ss, readKey->data = 0; writeKey->data = 0; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); rv = SECSuccess; cx = PK11_CreateDigestContext(SEC_OID_MD5); @@ -1441,7 +1441,7 @@ ssl2_CreateSessionCypher(sslSocket *ss, sslSessionID *sid, PRBool isClient) readKey.data = 0; writeKey.data = 0; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); if((ss->sec.ci.sid == 0)) goto sec_loser; /* don't crash if asserts are off */ @@ -1591,9 +1591,9 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits, PRUint8 mkbuf[SSL_MAX_MASTER_KEY_BYTES]; sslServerCerts * sc = ss->serverCerts + kt_rsa; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert((sc->serverKey != 0)); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert((sc->SERVERKEY != 0)); PORT_Assert((ss->sec.ci.sid != 0)); sid = ss->sec.ci.sid; @@ -1651,11 +1651,11 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits, ** 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, &el1, ekLen, ek, ekLen); if (rv != SECSuccess) goto hide_loser; - modulusLen = PK11_GetPrivateModulusLen(sc->serverKey); + 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 @@ -1679,7 +1679,7 @@ ssl2_ServerSetupSessionCypher(sslSocket *ss, int cipher, unsigned int keyBits, } /* Make sure we're not subject to a version rollback attack. */ - if (ss->enableSSL3 || ss->enableTLS) { + if (ss->opt.enableSSL3 || ss->opt.enableTLS) { PRUint8 threes[8] = { 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; @@ -1763,8 +1763,8 @@ ssl2_QualifyCypherSpecs(sslSocket *ss, int hc; PRUint8 qualifiedSpecs[ssl2_NUM_SUITES_IMPLEMENTED * 3]; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); if (!ss->cipherSpecs) { ssl2_ConstructCipherSpecs(ss); @@ -1824,8 +1824,8 @@ ssl2_ChooseSessionCypher(sslSocket *ss, int realKeySize; PRUint8 * ohs = hs; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); if (!ss->cipherSpecs) { ssl2_ConstructCipherSpecs(ss); @@ -2044,7 +2044,7 @@ ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen) PRUint8 keyData[SSL_MAX_MASTER_KEY_BYTES]; PRUint8 iv [8]; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); eblock = NULL; @@ -2131,7 +2131,7 @@ ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen) /* Set up the padding for version 2 rollback detection. */ /* XXX We should really use defines here */ - if (ss->enableSSL3 || ss->enableTLS) { + if (ss->opt.enableSSL3 || ss->opt.enableTLS) { PORT_Assert((modulusLen - rek.len) > 12); PORT_Memset(eblock + modulusLen - rek.len - 8 - 1, 0x03, 8); } @@ -2185,7 +2185,7 @@ ssl2_ClientRegSessionID(sslSocket *ss, PRUint8 *s) sid->peerCert = CERT_DupCertificate(ss->sec.peerCert); } - if (!ss->noCache) + if (!ss->opt.noCache) (*ss->sec.cache)(sid); } @@ -2195,7 +2195,7 @@ ssl2_TriggerNextMessage(sslSocket *ss) { SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); if ((ss->sec.ci.requiredElements & CIS_HAVE_CERTIFICATE) && !(ss->sec.ci.sentElements & CIS_HAVE_CERTIFICATE)) { @@ -2223,7 +2223,7 @@ ssl2_TryToFinish(sslSocket *ss) SECStatus rv; char e, ef; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); e = ss->sec.ci.elements; ef = e | CIS_HAVE_FINISHED; @@ -2261,7 +2261,7 @@ ssl2_SignResponse(sslSocket *ss, unsigned int len; SECStatus rv = SECFailure; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); challenge = ss->sec.ci.serverChallenge; len = ss->sec.ci.serverChallengeLen; @@ -2424,8 +2424,8 @@ ssl2_HandleClientCertificate(sslSocket * ss, SECItem certItem; SECItem rep; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); /* Extract the certificate */ certItem.data = cd; @@ -2512,7 +2512,7 @@ ssl2_HandleMessage(sslSocket *ss) int rv; int rv2; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetRecvBufLock(ss); @@ -2706,7 +2706,7 @@ ssl2_HandleVerifyMessage(sslSocket *ss) PRUint8 * data; SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ssl_GetRecvBufLock(ss); data = ss->gs.buf.buf + ss->gs.recordOffset; @@ -2758,9 +2758,9 @@ ssl2_HandleServerHelloMessage(sslSocket *ss) SECStatus rv; int needed, sidHit, certLen, csLen, cidLen, certType, err; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); - if (!ss->enableSSL2) { + if (!ss->opt.enableSSL2) { PORT_SetError(SSL_ERROR_SSL2_DISABLED); return SECFailure; } @@ -2989,7 +2989,7 @@ ssl2_BeginClientHandshake(sslSocket *ss) int sendLen, sidLen = 0; SECStatus rv; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); ss->sec.isServer = 0; ss->sec.sendSequence = 0; @@ -3035,7 +3035,7 @@ ssl2_BeginClientHandshake(sslSocket *ss) SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd)); /* Try to find server in our session-id cache */ - if (ss->noCache) { + if (ss->opt.noCache) { sid = NULL; } else { sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, @@ -3043,15 +3043,15 @@ ssl2_BeginClientHandshake(sslSocket *ss) } while (sid) { /* this isn't really a loop */ /* if we're not doing this SID's protocol any more, drop it. */ - if (((sid->version < SSL_LIBRARY_VERSION_3_0) && !ss->enableSSL2) || - ((sid->version == SSL_LIBRARY_VERSION_3_0) && !ss->enableSSL3) || - ((sid->version > SSL_LIBRARY_VERSION_3_0) && !ss->enableTLS)) { + if (((sid->version < SSL_LIBRARY_VERSION_3_0) && !ss->opt.enableSSL2) || + ((sid->version == SSL_LIBRARY_VERSION_3_0) && !ss->opt.enableSSL3) || + ((sid->version > SSL_LIBRARY_VERSION_3_0) && !ss->opt.enableTLS)) { ss->sec.uncache(sid); ssl_FreeSID(sid); sid = NULL; break; } - if (ss->enableSSL2 && sid->version < SSL_LIBRARY_VERSION_3_0) { + if (ss->opt.enableSSL2 && sid->version < SSL_LIBRARY_VERSION_3_0) { /* If the cipher in this sid is not enabled, drop it. */ for (i = 0; i < ss->sizeCipherSpecs; i += 3) { if (ss->cipherSpecs[i] == sid->u.ssl2.cipherType) @@ -3096,8 +3096,8 @@ ssl2_BeginClientHandshake(sslSocket *ss) PORT_Assert(sid != NULL); - if ((sid->version >= SSL_LIBRARY_VERSION_3_0 || !ss->v2CompatibleHello) && - (ss->enableSSL3 || ss->enableTLS)) { + if ((sid->version >= SSL_LIBRARY_VERSION_3_0 || !ss->opt.v2CompatibleHello) && + (ss->opt.enableSSL3 || ss->opt.enableTLS)) { ss->gs.state = GS_INIT; ss->handshake = ssl_GatherRecord1stHandshake; @@ -3138,9 +3138,9 @@ ssl2_BeginClientHandshake(sslSocket *ss) /* Construct client-hello message */ cp = msg = ss->sec.ci.sendBuf.buf; msg[0] = SSL_MT_CLIENT_HELLO; - if ( ss->enableTLS ) { + if ( ss->opt.enableTLS ) { ss->clientHelloVersion = SSL_LIBRARY_VERSION_3_1_TLS; - } else if ( ss->enableSSL3 ) { + } else if ( ss->opt.enableSSL3 ) { ss->clientHelloVersion = SSL_LIBRARY_VERSION_3_0; } else { ss->clientHelloVersion = SSL_LIBRARY_VERSION_2; @@ -3441,7 +3441,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) #endif PRUint8 csImpl[sizeof implementedCipherSuites]; - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); sc = ss->serverCerts + kt_rsa; serverCert = sc->serverCert; @@ -3470,7 +3470,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) */ if ((data[0] == SSL_MT_CLIENT_HELLO) && (data[1] >= MSB(SSL_LIBRARY_VERSION_3_0)) && - (ss->enableSSL3 || ss->enableTLS)) { + (ss->opt.enableSSL3 || ss->opt.enableTLS)) { rv = ssl3_HandleV2ClientHello(ss, data, ss->gs.recordLen); if (rv != SECFailure) { /* Success */ ss->handshake = NULL; @@ -3558,7 +3558,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) goto loser; } /* Since this handhsake is going to fail, don't cache it. */ - ss->noCache = 1; + ss->opt.noCache = 1; } /* Squirrel away the challenge for later */ @@ -3566,7 +3566,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) /* Examine message and see if session-id is good */ ss->sec.ci.elements = 0; - if (sdLen > 0 && !ss->noCache) { + if (sdLen > 0 && !ss->opt.noCache) { SSL_TRC(7, ("%d: SSL[%d]: server, lookup client session-id for 0x%08x%08x%08x%08x", SSL_GETPID(), ss->fd, ss->sec.ci.peer.pr_s6_addr32[0], ss->sec.ci.peer.pr_s6_addr32[1], @@ -3648,7 +3648,7 @@ ssl2_HandleClientHelloMessage(sslSocket *ss) /* Build up final list of required elements */ ss->sec.ci.requiredElements = CIS_HAVE_MASTER_KEY | CIS_HAVE_FINISHED; - if (ss->requestCertificate) { + if (ss->opt.requestCertificate) { ss->sec.ci.requiredElements |= CIS_HAVE_CERTIFICATE; } ss->sec.ci.sentElements = 0; @@ -3742,8 +3742,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) { - ss->enableSSL2 = PR_FALSE; + if (!rsaAuth->SERVERKEY || !rsaAuth->serverCert) { + ss->opt.enableSSL2 = PR_FALSE; } if (!ss->cipherSpecs) { diff --git a/security/nss/lib/ssl/ssldef.c b/security/nss/lib/ssl/ssldef.c index d42da2956..23ef9cafe 100644 --- a/security/nss/lib/ssl/ssldef.c +++ b/security/nss/lib/ssl/ssldef.c @@ -117,7 +117,7 @@ int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags) /* Although this is overkill, we disable Nagle delays completely for ** SSL sockets. */ - if (ss->useSecurity && !ss->delayDisabled) { + if (ss->opt.useSecurity && !ss->delayDisabled) { ssl_EnableNagleDelay(ss, PR_FALSE); /* ignore error */ ss->delayDisabled = 1; } diff --git a/security/nss/lib/ssl/sslgathr.c b/security/nss/lib/ssl/sslgathr.c index 75c465099..8308ad194 100644 --- a/security/nss/lib/ssl/sslgathr.c +++ b/security/nss/lib/ssl/sslgathr.c @@ -90,7 +90,7 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags) unsigned char * pBuf; int nb, err, rv; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); if (gs->state == GS_INIT) { /* Initialize gathering engine */ @@ -141,9 +141,9 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags) /* Probably finished this piece */ switch (gs->state) { case GS_HEADER: - if ((ss->enableSSL3 || ss->enableTLS) && !ss->firstHsDone) { + if ((ss->opt.enableSSL3 || ss->opt.enableTLS) && !ss->firstHsDone) { - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); /* If this looks like an SSL3 handshake record, ** and we're expecting an SSL2 Hello message from our peer, @@ -185,7 +185,7 @@ ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags) return SECFailure; } } - } /* ((ss->enableSSL3 || ss->enableTLS) && !ss->firstHsDone) */ + } /* ((ss->opt.enableSSL3 || ss->opt.enableTLS) && !ss->firstHsDone) */ /* we've got the first 3 bytes. The header may be two or three. */ if (gs->hdr[0] & 0x80) { @@ -411,7 +411,7 @@ ssl2_StartGatherBytes(sslSocket *ss, sslGather *gs, unsigned int count) { int rv; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); gs->state = GS_DATA; gs->remainder = count; gs->count = count; @@ -455,8 +455,8 @@ ssl2_HandleV3HandshakeRecord(sslSocket *ss) SECStatus rv; SSL3ProtocolVersion version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2]; - PORT_Assert( ssl_HaveRecvBufLock(ss) ); - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); /* We've read in 3 bytes, there are 2 more to go in an ssl3 header. */ ss->gs.remainder = 2; diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index ae6cb8a72..099f23e08 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -93,6 +93,10 @@ typedef SSLSignType SSL3SignType; #define hmac_md5 ssl_hmac_md5 #define hmac_sha ssl_hmac_sha +#define SET_ERROR_CODE /* reminder */ +#define SEND_ALERT /* reminder */ +#define TEST_FOR_FAILURE /* reminder */ +#define DEAL_WITH_FAILURE /* reminder */ #if defined(DEBUG) || defined(TRACE) #ifdef __cplusplus @@ -162,12 +166,17 @@ typedef enum { SSLAppOpRead = 0, #define SSL_MAX_MAC_BYTES 16 +#define SSL3_RSA_PMS_LENGTH 48 +#define SSL3_MASTER_SECRET_LENGTH 48 + /* number of wrap mechanisms potentially used to wrap master secrets. */ #define SSL_NUM_WRAP_MECHS 13 /* This makes the cert cache entry exactly 4k. */ #define SSL_MAX_CACHED_CERT_LEN 4060 +#define NUM_MIXERS 9 + #ifndef BPB #define BPB 8 /* Bits Per Byte */ #endif @@ -281,6 +290,8 @@ typedef struct sslOptionsStr { unsigned int v2CompatibleHello : 1; /* 13 */ unsigned int detectRollBack : 1; /* 14 */ unsigned int noStepDown : 1; /* 15 */ + unsigned int bypassPKCS11 : 1; /* 16 */ + unsigned int noLocks : 1; /* 17 */ } sslOptions; typedef enum { sslHandshakingUndetermined = 0, @@ -292,10 +303,11 @@ typedef struct sslServerCertsStr { /* Configuration state for server sockets */ CERTCertificate * serverCert; CERTCertificateList * serverCertChain; - SECKEYPrivateKey * serverKey; + ssl3KeyPair * serverKeyPair; unsigned int serverKeyBits; } sslServerCerts; +#define SERVERKEY serverKeyPair->privKey #define SSL_LOCK_RANK_SPEC 255 #define SSL_LOCK_RANK_GLOBAL NSS_RWLOCK_RANK_NONE @@ -432,21 +444,31 @@ typedef struct { uint32 low; } SSL3SequenceNumber; -typedef struct { - SSL3Opaque write_iv[MAX_IV_LENGTH]; - PK11SymKey *write_key; - PK11SymKey *write_mac_key; - PK11Context *write_mac_context; -} ssl3KeyMaterial; +#define MAX_MAC_CONTEXT_BYTES 400 +#define MAX_MAC_CONTEXT_LLONGS (MAX_MAC_CONTEXT_BYTES / 8) + +#define MAX_CIPHER_CONTEXT_BYTES 2080 +#define MAX_CIPHER_CONTEXT_LLONGS (MAX_CIPHER_CONTEXT_BYTES / 8) typedef struct { - SSL3Opaque wrapped_client_write_key[12]; /* wrapped with Ks */ - SSL3Opaque wrapped_server_write_key[12]; /* wrapped with Ks */ SSL3Opaque client_write_iv [24]; SSL3Opaque server_write_iv [24]; SSL3Opaque wrapped_master_secret [48]; PRUint16 wrapped_master_secret_len; -} ssl3SidKeys; + PRUint8 msIsWrapped; + PRUint8 resumable; +} ssl3SidKeys; /* 100 bytes */ + +typedef struct { + PK11SymKey *write_key; + PK11SymKey *write_mac_key; + PK11Context *write_mac_context; + SECItem write_key_item; + SECItem write_iv_item; + SECItem write_mac_key_item; + SSL3Opaque write_iv[MAX_IV_LENGTH]; + PRUint64 cipher_context[MAX_CIPHER_CONTEXT_LLONGS]; +} ssl3KeyMaterial; /* ** These are the "specs" in the "ssl3" struct. @@ -458,16 +480,20 @@ typedef struct { const ssl3MACDef * mac_def; int mac_size; SSLCipher encode; - void * encodeContext; SSLCipher decode; - void * decodeContext; SSLDestroy destroy; + void * encodeContext; + void * decodeContext; + PRBool bypassCiphers; /* did double bypass (at least) */ PK11SymKey * master_secret; - ssl3KeyMaterial client; - ssl3KeyMaterial server; SSL3SequenceNumber write_seq_num; SSL3SequenceNumber read_seq_num; SSL3ProtocolVersion version; + ssl3KeyMaterial client; + ssl3KeyMaterial server; + SECItem msItem; + unsigned char key_block[NUM_MIXERS * MD5_LENGTH]; + unsigned char raw_master_secret[56]; } ssl3CipherSpec; typedef enum { never_cached, @@ -519,7 +545,6 @@ struct sslSessionIDStr { ssl3CipherSuite cipherSuite; SSL3CompressionMethod compression; - PRBool resumable; int policy; ssl3SidKeys keys; CK_MECHANISM_TYPE masterWrapMech; @@ -533,7 +558,6 @@ struct sslSessionIDStr { */ PK11SymKey * clientWriteKey; PK11SymKey * serverWriteKey; - PK11SymKey * tek; /* The following values pertain to the slot that wrapped the ** master secret. (used only in client) @@ -631,6 +655,8 @@ typedef struct SSL3HandshakeStateStr { SSL3Random server_random; SSL3Random client_random; SSL3WaitState ws; + PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS]; + PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS]; PK11Context * md5; /* handshake running hashes */ PK11Context * sha; const ssl3KEADef * kea_def; @@ -673,9 +699,6 @@ struct ssl3StateStr { ssl3CipherSpec * prSpec; /* pending read spec. */ ssl3CipherSpec * cwSpec; /* current write spec. */ ssl3CipherSpec * pwSpec; /* pending write spec. */ - ssl3CipherSpec specs[2]; /* one is current, one is pending. */ - - SSL3HandshakeState hs; CERTCertificate * clientCertificate; /* used by client */ SECKEYPrivateKey * clientPrivateKey; /* used by client */ @@ -692,7 +715,9 @@ struct ssl3StateStr { /* chain while we are trying to validate it. */ CERTDistNames * ca_list; /* used by server. trusted CAs for this socket. */ - + PRBool initialized; + SSL3HandshakeState hs; + ssl3CipherSpec specs[2]; /* one is current, one is pending. */ }; typedef struct { @@ -739,7 +764,7 @@ typedef struct SSLWrappedSymWrappingKeyStr { */ /* -** This is "ci", as in "ss->sec->ci". +** This is "ci", as in "ss->sec.ci". ** ** Protection: All the variables in here are protected by ** firstHandshakeLock AND (in ssl3) ssl3HandshakeLock @@ -861,30 +886,17 @@ struct sslSocketStr { /* Pointer to operations vector for this socket */ const sslSocketOps * ops; + /* SSL socket options */ + sslOptions opt; + /* State flags */ - unsigned int useSocks : 1; - unsigned int useSecurity : 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 clientAuthRequested: 1; - unsigned int noCache : 1; - unsigned int fdx : 1; /* simultaneous R/W threads */ - unsigned int v2CompatibleHello : 1; /* Send v3+ client hello in v2 format */ - unsigned int detectRollBack : 1; /* Detect rollback to SSL v3 */ - unsigned int firstHsDone : 1; /* first handshake is complete. */ - - unsigned int recvdCloseNotify : 1; /* received SSL EOF. */ - unsigned int lastWriteBlocked : 1; - unsigned int TCPconnected : 1; - unsigned int handshakeBegun : 1; - unsigned int delayDisabled : 1; /* Nagle delay disabled */ - unsigned int noStepDown : 1; + unsigned long clientAuthRequested; + unsigned long delayDisabled; /* Nagle delay disabled */ + unsigned long firstHsDone; /* first handshake is complete. */ + unsigned long handshakeBegun; + unsigned long lastWriteBlocked; + unsigned long recvdCloseNotify; /* received SSL EOF. */ + unsigned long TCPconnected; /* version of the protocol to use */ SSL3ProtocolVersion version; @@ -895,28 +907,17 @@ struct sslSocketStr { /* protected by firstHandshakeLock AND (in ssl3) ssl3HandshakeLock. */ const char *url; /* ssl 2 & 3 */ - /* Gather object used for gathering data */ - sslGather gs; /*recvBufLock*/ - sslHandshakeFunc handshake; /*firstHandshakeLock*/ sslHandshakeFunc nextHandshake; /*firstHandshakeLock*/ sslHandshakeFunc securityHandshake; /*firstHandshakeLock*/ - sslBuffer saveBuf; /*xmitBufLock*/ - sslBuffer pendingBuf; /*xmitBufLock*/ - /* the following variable is only used with socks or other proxies. */ char * peerID; /* String uniquely identifies target server. */ - ssl3State * ssl3; unsigned char * cipherSpecs; unsigned int sizeCipherSpecs; const unsigned char * preferredCipher; - /* Configuration state for server sockets */ - /* server cert and key for each KEA type */ - sslServerCerts serverCerts[kt_kea_size]; - ssl3KeyPair * stepDownKeyPair; /* RSA step down keys */ /* Callbacks */ @@ -971,8 +972,21 @@ const unsigned char * preferredCipher; sslHandshakingType handshaking; + /* Gather object used for gathering data */ + sslGather gs; /*recvBufLock*/ + + sslBuffer saveBuf; /*xmitBufLock*/ + sslBuffer pendingBuf; /*xmitBufLock*/ + + /* Configuration state for server sockets */ + /* server cert and key for each KEA type */ + sslServerCerts serverCerts[kt_kea_size]; + ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED]; ssl3KeyPair * ephemeralECDHKeyPair; /* for ECDHE-* handshake */ + + /* SSL3 state info. Formerly was a pointer */ + ssl3State ssl3; }; @@ -1062,7 +1076,7 @@ extern int ssl2_StartGatherBytes(sslSocket *ss, sslGather *gs, extern SECStatus ssl_CreateSecurityInfo(sslSocket *ss); extern SECStatus ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os); -extern void ssl_ResetSecurityInfo(sslSecurityInfo *sec); +extern void ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset); extern void ssl_DestroySecurityInfo(sslSecurityInfo *sec); extern sslSocket * ssl_DupSocket(sslSocket *old); @@ -1099,33 +1113,57 @@ extern void ssl_SetAlwaysBlock(sslSocket *ss); extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled); #define SSL_LOCK_READER(ss) if (ss->recvLock) PZ_Lock(ss->recvLock) -#define SSL_UNLOCK_READER(ss) if (ss->recvLock) PZ_Unlock(ss->recvLock) +#define SSL_UNLOCK_READER(ss) if (ss->recvLock) PZ_Unlock(ss->recvLock) #define SSL_LOCK_WRITER(ss) if (ss->sendLock) PZ_Lock(ss->sendLock) -#define SSL_UNLOCK_WRITER(ss) if (ss->sendLock) PZ_Unlock(ss->sendLock) - -#define ssl_Get1stHandshakeLock(ss) PZ_EnterMonitor((ss)->firstHandshakeLock) -#define ssl_Release1stHandshakeLock(ss) PZ_ExitMonitor((ss)->firstHandshakeLock) -#define ssl_Have1stHandshakeLock(ss) PZ_InMonitor( (ss)->firstHandshakeLock) - -#define ssl_GetSSL3HandshakeLock(ss) PZ_EnterMonitor((ss)->ssl3HandshakeLock) -#define ssl_ReleaseSSL3HandshakeLock(ss) PZ_ExitMonitor((ss)->ssl3HandshakeLock) -#define ssl_HaveSSL3HandshakeLock(ss) PZ_InMonitor( (ss)->ssl3HandshakeLock) - -#define ssl_GetSpecReadLock(ss) NSSRWLock_LockRead( (ss)->specLock) -#define ssl_ReleaseSpecReadLock(ss) NSSRWLock_UnlockRead( (ss)->specLock) - -#define ssl_GetSpecWriteLock(ss) NSSRWLock_LockWrite( (ss)->specLock) -#define ssl_ReleaseSpecWriteLock(ss) NSSRWLock_UnlockWrite((ss)->specLock) -#define ssl_HaveSpecWriteLock(ss) NSSRWLock_HaveWriteLock((ss)->specLock) - -#define ssl_GetRecvBufLock(ss) PZ_EnterMonitor((ss)->recvBufLock) -#define ssl_ReleaseRecvBufLock(ss) PZ_ExitMonitor( (ss)->recvBufLock) -#define ssl_HaveRecvBufLock(ss) PZ_InMonitor( (ss)->recvBufLock) - -#define ssl_GetXmitBufLock(ss) PZ_EnterMonitor((ss)->xmitBufLock) -#define ssl_ReleaseXmitBufLock(ss) PZ_ExitMonitor( (ss)->xmitBufLock) -#define ssl_HaveXmitBufLock(ss) PZ_InMonitor( (ss)->xmitBufLock) - +#define SSL_UNLOCK_WRITER(ss) if (ss->sendLock) PZ_Unlock(ss->sendLock) + +#define ssl_Get1stHandshakeLock(ss) \ + { if (!ss->opt.noLocks) PZ_EnterMonitor((ss)->firstHandshakeLock); } +#define ssl_Release1stHandshakeLock(ss) \ + { if (!ss->opt.noLocks) PZ_ExitMonitor((ss)->firstHandshakeLock); } +#define ssl_Have1stHandshakeLock(ss) \ + (PZ_InMonitor((ss)->firstHandshakeLock)) + +#define ssl_GetSSL3HandshakeLock(ss) \ + { if (!ss->opt.noLocks) PZ_EnterMonitor((ss)->ssl3HandshakeLock); } +#define ssl_ReleaseSSL3HandshakeLock(ss) \ + { if (!ss->opt.noLocks) PZ_ExitMonitor((ss)->ssl3HandshakeLock); } +#define ssl_HaveSSL3HandshakeLock(ss) \ + (PZ_InMonitor((ss)->ssl3HandshakeLock)) + +#define ssl_GetSpecReadLock(ss) \ + { if (!ss->opt.noLocks) NSSRWLock_LockRead((ss)->specLock); } +#define ssl_ReleaseSpecReadLock(ss) \ + { if (!ss->opt.noLocks) NSSRWLock_UnlockRead((ss)->specLock); } + +#define ssl_GetSpecWriteLock(ss) \ + { if (!ss->opt.noLocks) NSSRWLock_LockWrite((ss)->specLock); } +#define ssl_ReleaseSpecWriteLock(ss) \ + { if (!ss->opt.noLocks) NSSRWLock_UnlockWrite((ss)->specLock); } +#define ssl_HaveSpecWriteLock(ss) \ + (NSSRWLock_HaveWriteLock((ss)->specLock)) + +#define ssl_GetRecvBufLock(ss) \ + { if (!ss->opt.noLocks) PZ_EnterMonitor((ss)->recvBufLock); } +#define ssl_ReleaseRecvBufLock(ss) \ + { if (!ss->opt.noLocks) PZ_ExitMonitor( (ss)->recvBufLock); } +#define ssl_HaveRecvBufLock(ss) \ + (PZ_InMonitor((ss)->recvBufLock)) + +#define ssl_GetXmitBufLock(ss) \ + { if (!ss->opt.noLocks) PZ_EnterMonitor((ss)->xmitBufLock); } +#define ssl_ReleaseXmitBufLock(ss) \ + { if (!ss->opt.noLocks) PZ_ExitMonitor( (ss)->xmitBufLock); } +#define ssl_HaveXmitBufLock(ss) \ + (PZ_InMonitor((ss)->xmitBufLock)) + + +extern SECStatus ssl3_KeyAndMacDeriveBypass(ssl3CipherSpec * pwSpec, + const unsigned char * cr, const unsigned char * sr, + PRBool isTLS, PRBool isExport); +extern SECStatus ssl3_MasterKeyDeriveBypass( ssl3CipherSpec * pwSpec, + const unsigned char * cr, const unsigned char * sr, + const SECItem * pms, PRBool isTLS, PRBool isRSA); /* These functions are called from secnav, even though they're "private". */ @@ -1208,13 +1246,46 @@ extern SECStatus ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache); -extern void ssl3_DestroySSL3Info(ssl3State *ssl3); +extern void ssl3_DestroySSL3Info(sslSocket *ss); extern SECStatus ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion); extern SECStatus ssl_GetPeerInfo(sslSocket *ss); +#ifdef NSS_ENABLE_ECC +/* ECDH functions */ +extern SECStatus ssl3_SendECDHClientKeyExchange(sslSocket * ss, + SECKEYPublicKey * svrPubKey); +extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss, + SSL3Opaque *b, PRUint32 length); +extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, + SSL3Opaque *b, PRUint32 length, + SECKEYPublicKey *srvrPubKey, + SECKEYPrivateKey *srvrPrivKey); +extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); +#endif + +extern SECStatus ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, + unsigned int bufLen, SSL3Hashes *hashes, + PRBool bypassPKCS11); +extern SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms); +extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src, + PRInt32 bytes); +extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, + SSL3HandshakeType t, PRUint32 length); +extern SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss, + const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); +extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, + SSL3Opaque **b, PRUint32 *length); +extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, + PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); +extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, + SECItem *buf, PRBool isTLS); +extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, + CERTCertificate *cert, SECItem *buf, PRBool isTLS, + void *pwArg); + /* Construct a new NSPR socket for the app to use */ extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd); extern void ssl_FreePRSocket(PRFileDesc *fd); diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index 796b6e062..d3a9735f0 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -60,17 +60,17 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) memset(&inf, 0, sizeof inf); inf.length = PR_MIN(sizeof inf, len); - if (ss->useSecurity && ss->firstHsDone) { + if (ss->opt.useSecurity && ss->firstHsDone) { sid = ss->sec.ci.sid; inf.protocolVersion = ss->version; inf.authKeyBits = ss->sec.authKeyBits; inf.keaKeyBits = ss->sec.keaKeyBits; if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */ inf.cipherSuite = ss->sec.cipherType | 0xff00; - } else if (ss->ssl3) { /* SSL3 and TLS */ + } else if (ss->ssl3.initialized) { /* SSL3 and TLS */ /* XXX These should come from crSpec */ - inf.cipherSuite = ss->ssl3->hs.cipher_suite; + inf.cipherSuite = ss->ssl3.hs.cipher_suite; } if (sid) { inf.creationTime = sid->creationTime; @@ -78,7 +78,8 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) inf.expirationTime = sid->expirationTime; if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */ inf.sessionIDLength = SSL2_SESSIONID_BYTES; - memcpy(inf.sessionID, sid->u.ssl2.sessionID, SSL2_SESSIONID_BYTES); + memcpy(inf.sessionID, sid->u.ssl2.sessionID, + SSL2_SESSIONID_BYTES); } else { unsigned int sidLen = sid->u.ssl3.sessionIDLength; sidLen = PR_MIN(sidLen, sizeof inf.sessionID); diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c index 1a02666e5..e2dbcf0a5 100644 --- a/security/nss/lib/ssl/sslnonce.c +++ b/security/nss/lib/ssl/sslnonce.c @@ -193,7 +193,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, PORT_Strcmp(sid->peerID, peerID) == 0)) && /* is cacheable */ (sid->version < SSL_LIBRARY_VERSION_3_0 || - sid->u.ssl3.resumable) && + sid->u.ssl3.keys.resumable) && /* server hostname matches. */ (sid->urlSvrName != NULL) && ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) || diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index 740d32afb..4c895d968 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -112,9 +112,9 @@ ssl_Do1stHandshake(sslSocket *ss) int loopCount = 0; do { - PORT_Assert( ssl_Have1stHandshakeLock(ss) ); - PORT_Assert( !ssl_HaveRecvBufLock(ss) ); - PORT_Assert( !ssl_HaveXmitBufLock(ss) ); + PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); + PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); + PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); if (ss->handshake == 0) { /* Previous handshake finished. Switch to next one */ @@ -153,8 +153,8 @@ ssl_Do1stHandshake(sslSocket *ss) */ } while (rv != SECFailure); /* was (rv >= 0); XXX_1 */ - PORT_Assert( !ssl_HaveRecvBufLock(ss) ); - PORT_Assert( !ssl_HaveXmitBufLock(ss) ); + PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); + PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); if (rv == SECWouldBlock) { PORT_SetError(PR_WOULD_BLOCK_ERROR); @@ -202,7 +202,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) } /* Don't waste my time */ - if (!ss->useSecurity) + if (!ss->opt.useSecurity) return SECSuccess; SSL_LOCK_READER(ss); @@ -231,7 +231,7 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) ** Blow away old security state and get a fresh setup. */ ssl_GetXmitBufLock(ss); - ssl_ResetSecurityInfo(&ss->sec); + ssl_ResetSecurityInfo(&ss->sec, PR_TRUE); status = ssl_CreateSecurityInfo(ss); ssl_ReleaseXmitBufLock(ss); @@ -264,7 +264,7 @@ SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) return SECFailure; } - if (!ss->useSecurity) + if (!ss->opt.useSecurity) return SECSuccess; ssl_Get1stHandshakeLock(ss); @@ -306,7 +306,7 @@ SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb, return SECFailure; } - if (!ss->useSecurity) { + if (!ss->opt.useSecurity) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } @@ -347,7 +347,7 @@ SSL_ForceHandshake(PRFileDesc *fd) } /* Don't waste my time */ - if (!ss->useSecurity) + if (!ss->opt.useSecurity) return SECSuccess; ssl_Get1stHandshakeLock(ss); @@ -388,6 +388,7 @@ SSL_ForceHandshake(PRFileDesc *fd) SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen) { + newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048); if (newLen > b->space) { unsigned char *newBuf; if (b->buf) { @@ -419,7 +420,7 @@ ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, const void *data, unsigned int newlen; SECStatus rv; - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); newlen = buf->len + len; if (newlen > buf->space) { rv = sslBuffer_Grow(buf, newlen); @@ -446,7 +447,7 @@ ssl_SendSavedWriteData(sslSocket *ss, sslBuffer *buf, sslSendFunc send) int rv = 0; int len = buf->len; - PORT_Assert( ssl_HaveXmitBufLock(ss) ); + PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); if (len != 0) { SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data", SSL_GETPID(), ss->fd, len)); @@ -664,19 +665,47 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, } /* load the private key */ - if (sc->serverKey != NULL) { - SECKEY_DestroyPrivateKey(sc->serverKey); - sc->serverKey = NULL; + if (sc->serverKeyPair != NULL) { + ssl3_FreeKeyPair(sc->serverKeyPair); + sc->serverKeyPair = NULL; } if (key) { - sc->serverKey = SECKEY_CopyPrivateKey(key); - if (sc->serverKey == NULL) + SECKEYPrivateKey * keyCopy = NULL; + CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM; + + if (key->pkcs11Slot) { + PK11SlotInfo * bestSlot; + bestSlot = PK11_ReferenceSlot(key->pkcs11Slot); + if (bestSlot) { + keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); + PK11_FreeSlot(bestSlot); + } + } + if (keyCopy == NULL) + keyMech = PK11_MapSignKeyType(key->keyType); + if (keyMech != CKM_INVALID_MECHANISM) { + PK11SlotInfo * bestSlot; + /* XXX Maybe should be bestSlotMultiple? */ + bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */); + if (bestSlot) { + keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); + PK11_FreeSlot(bestSlot); + } + } + if (keyCopy == NULL) + keyCopy = SECKEY_CopyPrivateKey(key); + if (keyCopy == NULL) goto loser; - SECKEY_CacheStaticFlags(sc->serverKey); + SECKEY_CacheStaticFlags(keyCopy); + sc->serverKeyPair = ssl3_NewKeyPair(keyCopy, NULL); + if (sc->serverKeyPair == NULL) { + SECKEY_DestroyPrivateKey(keyCopy); + goto loser; + } } if (kea == kt_rsa && cert && sc->serverKeyBits > 512) { - if (ss->noStepDown) { + if (ss->opt.noStepDown) { /* disable all export ciphersuites */ } else { rv = ssl3_CreateRSAStepDownKeys(ss); @@ -701,9 +730,9 @@ loser: CERT_DestroyCertificateList(sc->serverCertChain); sc->serverCertChain = NULL; } - if (sc->serverKey != NULL) { - SECKEY_DestroyPrivateKey(sc->serverKey); - sc->serverKey = NULL; + if (sc->serverKeyPair != NULL) { + ssl3_FreeKeyPair(sc->serverKeyPair); + sc->serverKeyPair = NULL; } return SECFailure; } @@ -788,7 +817,7 @@ loser: ** Caller holds any relevant locks. */ void -ssl_ResetSecurityInfo(sslSecurityInfo *sec) +ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset) { /* Destroy MAC */ if (sec->hash && sec->hashcx) { @@ -830,7 +859,10 @@ ssl_ResetSecurityInfo(sslSecurityInfo *sec) ssl_FreeSID(sec->ci.sid); } PORT_ZFree(sec->ci.sendBuf.buf, sec->ci.sendBuf.space); - memset(&sec->ci, 0, sizeof sec->ci); + if (doMemset) { + memset(&sec->ci, 0, sizeof sec->ci); + } + } /* @@ -841,7 +873,7 @@ ssl_ResetSecurityInfo(sslSecurityInfo *sec) void ssl_DestroySecurityInfo(sslSecurityInfo *sec) { - ssl_ResetSecurityInfo(sec); + ssl_ResetSecurityInfo(sec, PR_FALSE); PORT_ZFree(sec->writeBuf.buf, sec->writeBuf.space); sec->writeBuf.buf = 0; @@ -857,7 +889,7 @@ ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa) PRFileDesc *osfd = ss->fd->lower; int rv; - if ( ss->handshakeAsServer ) { + if ( ss->opt.handshakeAsServer ) { ss->securityHandshake = ssl2_BeginServerHandshake; ss->handshaking = sslHandshakingAsServer; } else { @@ -892,7 +924,7 @@ ssl_SecureClose(sslSocket *ss) ss->firstHsDone && !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && !ss->recvdCloseNotify && - (ss->ssl3 != NULL)) { + ss->ssl3.initialized) { /* We don't want the final alert to be Nagle delayed. */ if (!ss->delayDisabled) { @@ -924,7 +956,7 @@ ssl_SecureShutdown(sslSocket *ss, int nsprHow) (ss->version >= SSL_LIBRARY_VERSION_3_0) && ss->firstHsDone && !ss->recvdCloseNotify && - (ss->ssl3 != NULL)) { + ss->ssl3.initialized) { (void) SSL3_SendAlert(ss, alert_warning, close_notify); } @@ -956,7 +988,7 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) return PR_FAILURE; } - if (!ssl_SocketIsBlocking(ss) && !ss->fdx) { + if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) { ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { rv = ssl_SendSavedWriteData(ss, &ss->pendingBuf, ssl_DefSend); @@ -1132,7 +1164,7 @@ SSL_DataPending(PRFileDesc *fd) ss = ssl_FindSocket(fd); - if (ss && ss->useSecurity) { + if (ss && ss->opt.useSecurity) { ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); @@ -1180,7 +1212,7 @@ SSL_GetSessionID(PRFileDesc *fd) ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); - if (ss->useSecurity && ss->firstHsDone && ss->sec.ci.sid) { + if (ss->opt.useSecurity && ss->firstHsDone && ss->sec.ci.sid) { item = (SECItem *)PORT_Alloc(sizeof(SECItem)); if (item) { sslSessionID * sid = ss->sec.ci.sid; diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index a0c164963..469a1e4f1 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -146,17 +146,15 @@ struct sidCacheEntryStr { /* 2 */ ssl3CipherSuite cipherSuite; /* 2 */ PRUint16 compression; /* SSL3CompressionMethod */ -/*122 */ ssl3SidKeys keys; /* keys and ivs, wrapped as needed. */ -/* 1 */ PRUint8 unused; /* was hasFortezza; */ -/* 1 */ PRUint8 resumable; +/*100 */ ssl3SidKeys keys; /* keys and ivs, wrapped as needed. */ /* 4 */ PRUint32 masterWrapMech; /* 4 */ SSL3KEAType exchKeyType; /* 4 */ PRInt32 certIndex; -/*140 */} ssl3; -#if defined(LINUX) +/*116 */} ssl3; +#if defined(LINUX) /* XXX Why only on Linux ? */ struct { - PRUint8 filler[144]; + PRUint8 filler[144]; /* XXX why this number ? */ } forceSize; #endif } u; @@ -441,7 +439,6 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; to->u.ssl3.compression = (uint16)from->u.ssl3.compression; - to->u.ssl3.resumable = from->u.ssl3.resumable; to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; @@ -516,7 +513,6 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, to->u.ssl3.sessionIDLength = from->sessionIDLength; to->u.ssl3.cipherSuite = from->u.ssl3.cipherSuite; to->u.ssl3.compression = (SSL3CompressionMethod)from->u.ssl3.compression; - to->u.ssl3.resumable = from->u.ssl3.resumable; to->u.ssl3.keys = from->u.ssl3.keys; to->u.ssl3.masterWrapMech = from->u.ssl3.masterWrapMech; to->u.ssl3.exchKeyType = from->u.ssl3.exchKeyType; @@ -528,7 +524,7 @@ ConvertToSID(sidCacheEntry *from, certCacheEntry *pcce, */ to->u.ssl3.clientWriteKey = NULL; to->u.ssl3.serverWriteKey = NULL; - to->u.ssl3.tek = NULL; + to->urlSvrName = NULL; to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */ diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 2e8d73219..6a21457d0 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -161,6 +161,8 @@ static sslOptions ssl_defaults = { PR_TRUE, /* v2CompatibleHello */ PR_TRUE, /* detectRollBack */ PR_FALSE, /* noStepDown */ + PR_FALSE, /* bypassPKCS11 */ + PR_FALSE, /* noLocks */ }; sslSessionIDLookupFunc ssl_sid_lookup; @@ -170,13 +172,15 @@ sslSessionIDUncacheFunc ssl_sid_uncache; static PRBool ssl_inited = PR_FALSE; static PRDescIdentity ssl_layer_id; +PRBool locksEverDisabled; /* implicitly PR_FALSE */ int ssl_lock_readers = 1; /* default true. */ char ssl_debug; char ssl_trace; /* forward declarations. */ -static sslSocket *ssl_NewSocket(void); +static sslSocket *ssl_NewSocket(PRBool makeLocks); +static SECStatus ssl_MakeLocks(sslSocket *ss); static PRStatus ssl_PushIOLayer(sslSocket *ns, PRFileDesc *stack, PRDescIdentity id); @@ -227,22 +231,10 @@ ssl_DupSocket(sslSocket *os) sslSocket *ss; SECStatus rv; - ss = ssl_NewSocket(); + ss = ssl_NewSocket((PRBool)(!os->opt.noLocks)); if (ss) { - ss->useSocks = PR_FALSE; - ss->useSecurity = os->useSecurity; - ss->requestCertificate = os->requestCertificate; - ss->requireCertificate = os->requireCertificate; - ss->handshakeAsClient = os->handshakeAsClient; - ss->handshakeAsServer = os->handshakeAsServer; - ss->enableSSL2 = os->enableSSL2; - ss->enableSSL3 = os->enableSSL3; - ss->enableTLS = os->enableTLS; - ss->noCache = os->noCache; - ss->fdx = os->fdx; - ss->v2CompatibleHello = os->v2CompatibleHello; - ss->detectRollBack = os->detectRollBack; - ss->noStepDown = os->noStepDown; + ss->opt = os->opt; + ss->opt.useSocks = PR_FALSE; ss->peerID = !os->peerID ? NULL : PORT_Strdup(os->peerID); ss->url = !os->url ? NULL : PORT_Strdup(os->url); @@ -271,7 +263,7 @@ ssl_DupSocket(sslSocket *os) ss->sizeCipherSpecs = 0; ss->preferredCipher = NULL; } - if (ss->useSecurity) { + if (ss->opt.useSecurity) { /* This int should be SSLKEAType, but CC on Irix complains, * during the for loop. */ @@ -289,9 +281,9 @@ ssl_DupSocket(sslSocket *os) sc->serverCert = NULL; sc->serverCertChain = NULL; } - sc->serverKey = oc->serverKey ? - SECKEY_CopyPrivateKey(oc->serverKey) : NULL; - if (oc->serverKey && !sc->serverKey) + sc->serverKeyPair = oc->serverKeyPair ? + ssl3_GetKeyPairRef(oc->serverKeyPair) : NULL; + if (oc->serverKeyPair && !sc->serverKeyPair) goto loser; sc->serverKeyBits = oc->serverKeyBits; } @@ -328,7 +320,6 @@ loser: static void ssl_DestroyLocks(sslSocket *ss) { - /* Destroy locks. */ if (ss->firstHandshakeLock) { PZ_DestroyMonitor(ss->firstHandshakeLock); @@ -373,7 +364,7 @@ ssl_DestroySocketContents(sslSocket *ss) /* Free up socket */ ssl_DestroySecurityInfo(&ss->sec); - ssl3_DestroySSL3Info(ss->ssl3); + ssl3_DestroySSL3Info(ss); PORT_Free(ss->saveBuf.buf); PORT_Free(ss->pendingBuf.buf); @@ -396,8 +387,8 @@ ssl_DestroySocketContents(sslSocket *ss) CERT_DestroyCertificate(sc->serverCert); if (sc->serverCertChain != NULL) CERT_DestroyCertificateList(sc->serverCertChain); - if (sc->serverKey != NULL) - SECKEY_DestroyPrivateKey(sc->serverKey); + if (sc->serverKeyPair != NULL) + ssl3_FreeKeyPair(sc->serverKeyPair); } if (ss->stepDownKeyPair) { ssl3_FreeKeyPair(ss->stepDownKeyPair); @@ -476,7 +467,7 @@ ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled) static void ssl_ChooseOps(sslSocket *ss) { - ss->ops = ss->useSecurity ? &ssl_secure_ops : &ssl_default_ops; + ss->ops = ss->opt.useSecurity ? &ssl_secure_ops : &ssl_default_ops; } /* Called from SSL_Enable (immediately below) */ @@ -511,7 +502,7 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) switch (which) { case SSL_SOCKS: - ss->useSocks = PR_FALSE; + ss->opt.useSocks = PR_FALSE; rv = PrepareSocket(ss); if (on) { PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -520,38 +511,38 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) break; case SSL_SECURITY: - ss->useSecurity = on; + ss->opt.useSecurity = on; rv = PrepareSocket(ss); break; case SSL_REQUEST_CERTIFICATE: - ss->requestCertificate = on; + ss->opt.requestCertificate = on; break; case SSL_REQUIRE_CERTIFICATE: - ss->requireCertificate = on; + ss->opt.requireCertificate = on; break; case SSL_HANDSHAKE_AS_CLIENT: - if ( ss->handshakeAsServer && on ) { + if ( ss->opt.handshakeAsServer && on ) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->handshakeAsClient = on; + ss->opt.handshakeAsClient = on; break; case SSL_HANDSHAKE_AS_SERVER: - if ( ss->handshakeAsClient && on ) { + if ( ss->opt.handshakeAsClient && on ) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; break; } - ss->handshakeAsServer = on; + ss->opt.handshakeAsServer = on; break; case SSL_ENABLE_TLS: - ss->enableTLS = on; + ss->opt.enableTLS = on; ss->preferredCipher = NULL; if (ss->cipherSpecs) { PORT_Free(ss->cipherSpecs); @@ -561,7 +552,7 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) break; case SSL_ENABLE_SSL3: - ss->enableSSL3 = on; + ss->opt.enableSSL3 = on; ss->preferredCipher = NULL; if (ss->cipherSpecs) { PORT_Free(ss->cipherSpecs); @@ -571,9 +562,9 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) break; case SSL_ENABLE_SSL2: - ss->enableSSL2 = on; + ss->opt.enableSSL2 = on; if (on) { - ss->v2CompatibleHello = on; + ss->opt.v2CompatibleHello = on; } ss->preferredCipher = NULL; if (ss->cipherSpecs) { @@ -584,30 +575,45 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRBool on) break; case SSL_NO_CACHE: - ss->noCache = on; + ss->opt.noCache = on; break; case SSL_ENABLE_FDX: - ss->fdx = on; + ss->opt.fdx = on; break; case SSL_V2_COMPATIBLE_HELLO: - ss->v2CompatibleHello = on; + ss->opt.v2CompatibleHello = on; if (!on) { - ss->enableSSL2 = on; + ss->opt.enableSSL2 = on; } break; case SSL_ROLLBACK_DETECTION: - ss->detectRollBack = on; + ss->opt.detectRollBack = on; break; case SSL_NO_STEP_DOWN: - ss->noStepDown = on; + ss->opt.noStepDown = on; if (on) SSL_DisableExportCipherSuites(fd); break; + case SSL_BYPASS_PKCS11: + if (ss->handshakeBegun) { + PORT_SetError(PR_INVALID_STATE_ERROR); + rv = SECFailure; + } else { + ss->opt.bypassPKCS11 = on; + } + break; + + case SSL_NO_LOCKS: + ss->opt.noLocks = on; + if (on) + locksEverDisabled = PR_TRUE; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; @@ -641,19 +647,21 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 which, PRBool *pOn) switch (which) { case SSL_SOCKS: on = PR_FALSE; break; - case SSL_SECURITY: on = ss->useSecurity; break; - case SSL_REQUEST_CERTIFICATE: on = ss->requestCertificate; break; - case SSL_REQUIRE_CERTIFICATE: on = ss->requireCertificate; break; - case SSL_HANDSHAKE_AS_CLIENT: on = ss->handshakeAsClient; break; - case SSL_HANDSHAKE_AS_SERVER: on = ss->handshakeAsServer; break; - case SSL_ENABLE_TLS: on = ss->enableTLS; break; - case SSL_ENABLE_SSL3: on = ss->enableSSL3; break; - case SSL_ENABLE_SSL2: on = ss->enableSSL2; break; - 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; - case SSL_NO_STEP_DOWN: on = ss->noStepDown; break; + case SSL_SECURITY: on = ss->opt.useSecurity; break; + case SSL_REQUEST_CERTIFICATE: on = ss->opt.requestCertificate; break; + case SSL_REQUIRE_CERTIFICATE: on = ss->opt.requireCertificate; break; + case SSL_HANDSHAKE_AS_CLIENT: on = ss->opt.handshakeAsClient; break; + case SSL_HANDSHAKE_AS_SERVER: on = ss->opt.handshakeAsServer; break; + case SSL_ENABLE_TLS: on = ss->opt.enableTLS; break; + case SSL_ENABLE_SSL3: on = ss->opt.enableSSL3; break; + case SSL_ENABLE_SSL2: on = ss->opt.enableSSL2; break; + case SSL_NO_CACHE: on = ss->opt.noCache; break; + case SSL_ENABLE_FDX: on = ss->opt.fdx; break; + case SSL_V2_COMPATIBLE_HELLO: on = ss->opt.v2CompatibleHello; break; + case SSL_ROLLBACK_DETECTION: on = ss->opt.detectRollBack; break; + case SSL_NO_STEP_DOWN: on = ss->opt.noStepDown; break; + case SSL_BYPASS_PKCS11: on = ss->opt.bypassPKCS11; break; + case SSL_NO_LOCKS: on = ss->opt.noLocks; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -693,6 +701,8 @@ SSL_OptionGetDefault(PRInt32 which, PRBool *pOn) case SSL_V2_COMPATIBLE_HELLO: on = ssl_defaults.v2CompatibleHello; break; case SSL_ROLLBACK_DETECTION: on = ssl_defaults.detectRollBack; break; case SSL_NO_STEP_DOWN: on = ssl_defaults.noStepDown; break; + case SSL_BYPASS_PKCS11: on = ssl_defaults.bypassPKCS11; break; + case SSL_NO_LOCKS: on = ssl_defaults.noLocks; break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -790,6 +800,16 @@ SSL_OptionSetDefault(PRInt32 which, PRBool on) SSL_DisableDefaultExportCipherSuites(); break; + case SSL_BYPASS_PKCS11: + ssl_defaults.bypassPKCS11 = on; + break; + + case SSL_NO_LOCKS: + ssl_defaults.noLocks = on; + if (on) + locksEverDisabled = PR_TRUE; + break; + default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -906,7 +926,7 @@ SSL_CipherPrefSet(PRFileDesc *fd, PRInt32 which, PRBool enabled) SSL_DBG(("%d: SSL[%d]: bad socket in CipherPrefSet", SSL_GETPID(), fd)); return SECFailure; } - if (enabled && ss->noStepDown && SSL_IsExportCipherSuite(which)) { + if (enabled && ss->opt.noStepDown && SSL_IsExportCipherSuite(which)) { PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return SECFailure; } @@ -999,7 +1019,7 @@ SSL_ImportFD(PRFileDesc *model, PRFileDesc *fd) if (model == NULL) { /* Just create a default socket if we're given NULL for the model */ - ns = ssl_NewSocket(); + ns = ssl_NewSocket((PRBool)(!ssl_defaults.noLocks)); } else { sslSocket * ss = ssl_FindSocket(model); if (ss == NULL) { @@ -1084,8 +1104,8 @@ ssl_Accept(PRFileDesc *fd, PRNetAddr *sockaddr, PRIntervalTime timeout) /* Now start server connection handshake with client. ** Don't need locks here because nobody else has a reference to ns yet. */ - if ( ns->useSecurity ) { - if ( ns->handshakeAsClient ) { + if ( ns->opt.useSecurity ) { + if ( ns->opt.handshakeAsClient ) { ns->handshake = ssl2_BeginClientHandshake; ss->handshaking = sslHandshakingAsClient; } else { @@ -1241,7 +1261,7 @@ ssl_Recv(PRFileDesc *fd, void *buf, PRInt32 len, PRIntn flags, } SSL_LOCK_READER(ss); ss->rTimeout = timeout; - if (!ss->fdx) + if (!ss->opt.fdx) ss->wTimeout = timeout; rv = (*ss->ops->recv)(ss, (unsigned char*)buf, len, flags); SSL_UNLOCK_READER(ss); @@ -1262,7 +1282,7 @@ ssl_Send(PRFileDesc *fd, const void *buf, PRInt32 len, PRIntn flags, } SSL_LOCK_WRITER(ss); ss->wTimeout = timeout; - if (!ss->fdx) + if (!ss->opt.fdx) ss->rTimeout = timeout; rv = (*ss->ops->send)(ss, (const unsigned char*)buf, len, flags); SSL_UNLOCK_WRITER(ss); @@ -1282,7 +1302,7 @@ ssl_Read(PRFileDesc *fd, void *buf, PRInt32 len) } SSL_LOCK_READER(ss); ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; - if (!ss->fdx) + if (!ss->opt.fdx) ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; rv = (*ss->ops->read)(ss, (unsigned char*)buf, len); SSL_UNLOCK_READER(ss); @@ -1302,7 +1322,7 @@ ssl_Write(PRFileDesc *fd, const void *buf, PRInt32 len) } SSL_LOCK_WRITER(ss); ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; - if (!ss->fdx) + if (!ss->opt.fdx) ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; rv = (*ss->ops->write)(ss, (const unsigned char*)buf, len); SSL_UNLOCK_WRITER(ss); @@ -1398,7 +1418,7 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags) return 0; /* don't poll on this socket */ } - if (ss->useSecurity && + if (ss->opt.useSecurity && ss->handshaking != sslHandshakingUndetermined && !ss->firstHsDone && (how_flags & PR_POLL_RW)) { @@ -1840,38 +1860,83 @@ loser: return PR_FAILURE; } +/* if this fails, caller must destroy socket. */ +static SECStatus +ssl_MakeLocks(sslSocket *ss) +{ + ss->firstHandshakeLock = PZ_NewMonitor(nssILockSSL); + if (!ss->firstHandshakeLock) + goto loser; + ss->ssl3HandshakeLock = PZ_NewMonitor(nssILockSSL); + if (!ss->ssl3HandshakeLock) + goto loser; + ss->specLock = NSSRWLock_New(SSL_LOCK_RANK_SPEC, NULL); + if (!ss->specLock) + goto loser; + ss->recvBufLock = PZ_NewMonitor(nssILockSSL); + if (!ss->recvBufLock) + goto loser; + ss->xmitBufLock = PZ_NewMonitor(nssILockSSL); + if (!ss->xmitBufLock) + goto loser; + ss->writerThread = NULL; + if (ssl_lock_readers) { + ss->recvLock = PZ_NewLock(nssILockSSL); + if (!ss->recvLock) + goto loser; + ss->sendLock = PZ_NewLock(nssILockSSL); + if (!ss->sendLock) + goto loser; + } + return SECSuccess; +loser: + return SECFailure; +} + +#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)) && !defined(_WIN32_WCE) +#define NSS_HAVE_GETENV 1 +#endif + /* ** Create a newsocket structure for a file descriptor. */ static sslSocket * -ssl_NewSocket(void) +ssl_NewSocket(PRBool makeLocks) { sslSocket *ss; -#ifdef DEBUG -#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)) && !defined(_WIN32_WCE) +#if defined( NSS_HAVE_GETENV ) static int firsttime = 1; if (firsttime) { + char * ev; firsttime = 0; - { - char *ev = getenv("SSLDEBUG"); - if (ev && ev[0]) { - ssl_debug = atoi(ev); - SSL_TRACE(("SSL: debugging set to %d", ssl_debug)); - } - } +#ifdef DEBUG #ifdef TRACE - { - char *ev = getenv("SSLTRACE"); - if (ev && ev[0]) { - ssl_trace = atoi(ev); - SSL_TRACE(("SSL: tracing set to %d", ssl_trace)); - } + ev = getenv("SSLTRACE"); + if (ev && ev[0]) { + ssl_trace = atoi(ev); + SSL_TRACE(("SSL: tracing set to %d", ssl_trace)); } #endif /* TRACE */ - } -#endif /* XP_UNIX || XP_WIN32 */ + ev = getenv("SSLDEBUG"); + if (ev && ev[0]) { + ssl_debug = atoi(ev); + SSL_TRACE(("SSL: debugging set to %d", ssl_debug)); + } #endif /* DEBUG */ + ev = getenv("SSLBYPASS"); + if (ev && ev[0]) { + ssl_defaults.bypassPKCS11 = (ev[0] == '1'); + SSL_TRACE(("SSL: bypass default set to %d", \ + ssl_defaults.bypassPKCS11)); + } + ev = getenv("SSLNOLOCKS"); + if (ev && ev[0]) { + ssl_defaults.noLocks = (ev[0] == '1'); + SSL_TRACE(("SSL: noLocks default set to %d", ssl_defaults.noLocks)); + } + } +#endif /* NSS_HAVE_GETENV */ /* Make a new socket and get it ready */ ss = (sslSocket*) PORT_ZAlloc(sizeof(sslSocket)); @@ -1882,20 +1947,10 @@ ssl_NewSocket(void) int i; SECStatus status; - ss->useSecurity = ssl_defaults.useSecurity; - ss->useSocks = PR_FALSE; - ss->requestCertificate = ssl_defaults.requestCertificate; - ss->requireCertificate = ssl_defaults.requireCertificate; - ss->handshakeAsClient = ssl_defaults.handshakeAsClient; - ss->handshakeAsServer = ssl_defaults.handshakeAsServer; - ss->enableSSL2 = ssl_defaults.enableSSL2; - ss->enableSSL3 = ssl_defaults.enableSSL3; - ss->enableTLS = ssl_defaults.enableTLS ; - ss->fdx = ssl_defaults.fdx; - ss->v2CompatibleHello = ssl_defaults.v2CompatibleHello; - ss->detectRollBack = ssl_defaults.detectRollBack; - ss->noStepDown = ssl_defaults.noStepDown; - ss->noCache = ssl_defaults.noCache; + ss->opt = ssl_defaults; + ss->opt.useSocks = PR_FALSE; + ss->opt.noLocks = !makeLocks; + ss->peerID = NULL; ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; @@ -1909,7 +1964,7 @@ ssl_NewSocket(void) sslServerCerts * sc = ss->serverCerts + i; sc->serverCert = NULL; sc->serverCertChain = NULL; - sc->serverKey = NULL; + sc->serverKeyPair = NULL; sc->serverKeyBits = 0; } ss->stepDownKeyPair = NULL; @@ -1927,25 +1982,14 @@ ssl_NewSocket(void) ssl2_InitSocketPolicy(ss); ssl3_InitSocketPolicy(ss); - ss->firstHandshakeLock = PZ_NewMonitor(nssILockSSL); - if (!ss->firstHandshakeLock) goto loser; - ss->ssl3HandshakeLock = PZ_NewMonitor(nssILockSSL); - if (!ss->ssl3HandshakeLock) goto loser; - ss->specLock = NSSRWLock_New(SSL_LOCK_RANK_SPEC, NULL); - if (!ss->specLock) goto loser; - ss->recvBufLock = PZ_NewMonitor(nssILockSSL); - if (!ss->recvBufLock) goto loser; - ss->xmitBufLock = PZ_NewMonitor(nssILockSSL); - if (!ss->xmitBufLock) goto loser; - ss->writerThread = NULL; - if (ssl_lock_readers) { - ss->recvLock = PZ_NewLock(nssILockSSL); - if (!ss->recvLock) goto loser; - ss->sendLock = PZ_NewLock(nssILockSSL); - if (!ss->sendLock) goto loser; + if (makeLocks) { + status = ssl_MakeLocks(ss); + if (status != SECSuccess) + goto loser; } status = ssl_CreateSecurityInfo(ss); - if (status != SECSuccess) goto loser; + if (status != SECSuccess) + goto loser; status = ssl_InitGather(&ss->gs); if (status != SECSuccess) { loser: |