diff options
Diffstat (limited to 'security/nss/lib/ssl/ssl3con.c')
-rw-r--r-- | security/nss/lib/ssl/ssl3con.c | 1067 |
1 files changed, 765 insertions, 302 deletions
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 2b34b9519..bf37f19d3 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -74,7 +74,7 @@ static void ssl3_CleanupPeerCerts(sslSocket *ss); static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, PK11SlotInfo * serverKeySlot); -static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, const PK11SymKey *pms); +static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); static SECStatus ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss); static SECStatus ssl3_HandshakeFailure( sslSocket *ss); static SECStatus ssl3_InitState( sslSocket *ss); @@ -103,6 +103,10 @@ static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, */ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { /* cipher_suite policy enabled is_present*/ +#ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, #ifdef NSS_ENABLE_ECC @@ -112,7 +116,9 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, #ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, #endif /* NSS_ENABLE_ECC */ { TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, @@ -128,6 +134,10 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, #ifdef NSS_ENABLE_ECC @@ -140,10 +150,6 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, -#ifdef NSS_ENABLE_ECC - { TLS_ECDH_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, - { TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, -#endif /* NSS_ENABLE_ECC */ { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, @@ -153,6 +159,8 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, #ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, + { TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, #endif /* NSS_ENABLE_ECC */ @@ -236,6 +244,7 @@ static const ssl3KEADef kea_defs[] = {kea_ecdhe_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE}, {kea_ecdh_rsa, kt_ecdh, sign_rsa, PR_FALSE, 0, PR_FALSE}, {kea_ecdhe_rsa, kt_ecdh, sign_rsa, PR_FALSE, 0, PR_FALSE}, + {kea_ecdh_anon, kt_ecdh, sign_null, PR_FALSE, 0, PR_FALSE}, #endif /* NSS_ENABLE_ECC */ }; @@ -315,24 +324,37 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] = {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa_fips}, #ifdef NSS_ENABLE_ECC - /* Experimental TLS cipher suites using Elliptic Curves */ {TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_ecdsa}, {TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_ecdsa}, - {TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_ecdh_ecdsa}, {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa}, {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa}, {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_rsa}, {TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_rsa}, - {TLS_ECDH_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_ecdh_rsa}, {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_rsa}, {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_rsa}, {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_rsa}, - {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa}, +#if 0 + {TLS_ECDH_anon_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_anon}, +#endif #endif /* NSS_ENABLE_ECC */ }; @@ -395,6 +417,29 @@ const char * const ssl3_cipherName[] = { "missing" }; +#ifdef NSS_ENABLE_ECC +/* The ECCWrappedKeyInfo structure defines how various pieces of + * information are laid out within wrappedSymmetricWrappingkey + * for ECDH key exchange. Since wrappedSymmetricWrappingkey is + * a 512-byte buffer (see sslimpl.h), the variable length field + * in ECCWrappedKeyInfo can be at most (512 - 8) = 504 bytes. + * + * XXX For now, NSS only supports named elliptic curves of size 571 bits + * or smaller. The public value will fit within 145 bytes and EC params + * will fit within 12 bytes. We'll need to revisit this when NSS + * supports arbitrary curves. + */ +#define MAX_EC_WRAPPED_KEY_BUFLEN 504 + +typedef struct ECCWrappedKeyInfoStr { + PRUint16 size; /* EC public key size in bits */ + PRUint16 encodedParamLen; /* length (in bytes) of DER encoded EC params */ + PRUint16 pubValueLen; /* length (in bytes) of EC public value */ + PRUint16 wrappedKeyLen; /* length (in bytes) of the wrapped key */ + PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */ + /* EC public-key params, the EC public value and the wrapped key */ +} ECCWrappedKeyInfo; +#endif /* NSS_ENABLE_ECC */ #if defined(TRACE) @@ -450,6 +495,26 @@ SSL_GetStatistics(void) return &ssl3stats; } +typedef struct tooLongStr { +#if defined(IS_LITTLE_ENDIAN) + PRInt32 low; + PRInt32 high; +#else + PRInt32 high; + PRInt32 low; +#endif +} tooLong; + +static void SSL_AtomicIncrementLong(long * x) +{ + if ((sizeof *x) == sizeof(PRInt32)) { + PR_AtomicIncrement((PRInt32 *)x); + } else { + tooLong * tl = (tooLong *)x; + PR_AtomicIncrement(&tl->low) || PR_AtomicIncrement(&tl->high); + } +} + /* return pointer to ssl3CipherSuiteDef for suite, or NULL */ /* XXX This does a linear search. A binary search would be better. */ static const ssl3CipherSuiteDef * @@ -504,10 +569,15 @@ ssl3_config_match_init(sslSocket *ss) PRBool isServer; sslServerCerts *svrAuth; + PORT_Assert(ss); + if (!ss) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return 0; + } if (!ss->opt.enableSSL3 && !ss->opt.enableTLS) { return 0; } - isServer = (PRBool)( ss && ss->sec.isServer ); + isServer = (PRBool)(ss->sec.isServer != 0); for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) { suite = &ss->cipherSuites[i]; @@ -536,7 +606,15 @@ ssl3_config_match_init(sslSocket *ss) */ switch (cipher_def->key_exchange_alg) { case kea_ecdhe_rsa: +#if NSS_SERVER_DHE_IMPLEMENTED + /* XXX NSS does not yet implement the server side of _DHE_ + * cipher suites. Correcting the computation for svrAuth, + * as the case below does, causes NSS SSL servers to begin to + * negotiate cipher suites they do not implement. So, until + * server side _DHE_ is implemented, keep this disabled. + */ case kea_dhe_rsa: +#endif svrAuth = ss->serverCerts + kt_rsa; break; case kea_ecdh_ecdsa: @@ -715,7 +793,7 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, } buf->len = (unsigned)signatureLen; - buf->data = (unsigned char *)PORT_Alloc(signatureLen + 1); + buf->data = (unsigned char *)PORT_Alloc(signatureLen); if (!buf->data) goto done; /* error code was set. */ @@ -749,7 +827,7 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, SECItem derSig = {siBuffer, NULL, 0}; /* This also works for an ECDSA signature */ - rv = DSAU_EncodeDerSigWithLen(&derSig, buf, (unsigned) signatureLen); + rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); if (rv == SECSuccess) { PORT_Free(buf->data); /* discard unencoded signature. */ *buf = derSig; /* give caller encoded signature. */ @@ -818,7 +896,7 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, * using ASN (unlike DSA where ASN encoding is used * with TLS but not with SSL3) */ - len = SECKEY_PublicKeyStrength(key) * 2; + len = SECKEY_SignatureLen(key); if (len == 0) { SECKEY_DestroyPublicKey(key); PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); @@ -1693,32 +1771,164 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) { return isPresent; } +static SECStatus +ssl3_CompressMACEncryptRecord(sslSocket * ss, + SSL3ContentType type, + const SSL3Opaque * pIn, + PRUint32 contentLen) +{ + ssl3CipherSpec * cwSpec; + const ssl3BulkCipherDef * cipher_def; + sslBuffer * wrBuf = &ss->sec.writeBuf; + SECStatus rv; + PRUint32 macLen = 0; + PRUint32 fragLen; + PRUint32 p1Len, p2Len, oddLen = 0; + PRInt32 cipherBytes = 0; + + /* + * null compression is easy to do + PORT_Memcpy(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, pIn, contentLen); + */ + + ssl_GetSpecReadLock(ss); /********************************/ + + cwSpec = ss->ssl3.cwSpec; + cipher_def = cwSpec->cipher_def; + /* + * Add the MAC + */ + rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer), + type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen, + wrBuf->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); + + /* + * Pad the text (if we're doing a block cipher) + * then Encrypt it + */ + if (cipher_def->type == type_block) { + unsigned char * pBuf; + int padding_length; + int i; + + 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)); + fragLen += padding_length + 1; + PORT_Assert((fragLen % cipher_def->block_size) == 0); + + /* Pad according to TLS rules (also acceptable to SSL3). */ + pBuf = &wrBuf->buf[fragLen + SSL3_RECORD_HEADER_LENGTH - 1]; + 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; + } + 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(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + pIn + p1Len, oddLen); + } + if (p1Len > 0) { + rv = cwSpec->encode( cwSpec->encodeContext, + wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, /* output */ + &cipherBytes, /* actual outlen */ + p1Len, /* max outlen */ + pIn, 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, + wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + &cipherBytesPart2, /* output and actual outLen */ + p2Len, /* max outlen */ + wrBuf->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; + } + PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); + + ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); + + wrBuf->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; + wrBuf->buf[0] = type; + wrBuf->buf[1] = MSB(cwSpec->version); + wrBuf->buf[2] = LSB(cwSpec->version); + wrBuf->buf[3] = MSB(cipherBytes); + wrBuf->buf[4] = LSB(cipherBytes); + + ssl_ReleaseSpecReadLock(ss); /************************************/ + + return SECSuccess; + +spec_locked_loser: + ssl_ReleaseSpecReadLock(ss); + return SECFailure; +} + /* Process the plain text before sending it. * Returns the number of bytes of plaintext that were succesfully sent * plus the number of bytes of plaintext that were copied into the * output (write) buffer. * Returns SECFailure on a hard IO error, memory error, or crypto error. * Does NOT return SECWouldBlock. + * + * Notes on the use of the private ssl flags: + * (no private SSL flags) + * Attempt to make and send SSL records for all plaintext + * If non-blocking and a send gets WOULD_BLOCK, + * or if the pending (ciphertext) buffer is not empty, + * then buffer remaining bytes of ciphertext into pending buf, + * and continue to do that for all succssive records until all + * bytes are used. + * ssl_SEND_FLAG_FORCE_INTO_BUFFER + * As above, except this suppresses all write attempts, and forces + * all ciphertext into the pending ciphertext buffer. + * */ static PRInt32 ssl3_SendRecord( sslSocket * ss, SSL3ContentType type, - const SSL3Opaque * buf, - PRInt32 bytes, + const SSL3Opaque * pIn, /* input buffer */ + PRInt32 nIn, /* bytes of input */ PRInt32 flags) { - ssl3CipherSpec * cwSpec; - sslBuffer * write = &ss->sec.writeBuf; - const ssl3BulkCipherDef * cipher_def; + sslBuffer * wrBuf = &ss->sec.writeBuf; SECStatus rv; - PRUint32 bufSize = 0; - PRInt32 sent = 0; - PRBool isBlocking = ssl_SocketIsBlocking(ss); + PRInt32 totalSent = 0; - SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s bytes=%d", + SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), - bytes)); - PRINT_BUF(3, (ss, "Send record (plain text)", buf, bytes)); + nIn)); + PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn)); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); @@ -1740,149 +1950,30 @@ ssl3_SendRecord( sslSocket * ss, return SECFailure; } - while (bytes > 0) { - PRInt32 count; - PRUint32 contentLen; - PRUint32 fragLen; - PRUint32 macLen; - PRInt32 cipherBytes = 0; - PRUint32 p1Len, p2Len, oddLen = 0; + while (nIn > 0) { + PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH); - contentLen = PR_MIN(bytes, MAX_FRAGMENT_LENGTH); - if (write->space < contentLen + SSL3_BUFFER_FUDGE) { - rv = sslBuffer_Grow(write, contentLen + SSL3_BUFFER_FUDGE); + if (wrBuf->space < contentLen + SSL3_BUFFER_FUDGE) { + PRInt32 newSpace = PR_MAX(wrBuf->space * 2, contentLen); + newSpace = PR_MIN(newSpace, MAX_FRAGMENT_LENGTH); + newSpace += SSL3_BUFFER_FUDGE; + rv = sslBuffer_Grow(wrBuf, newSpace); if (rv != SECSuccess) { SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, contentLen + SSL3_BUFFER_FUDGE)); + SSL_GETPID(), ss->fd, newSpace)); return SECFailure; /* sslBuffer_Grow set a memory error code. */ } } - /* This variable records the actual size of the buffer allocated above. - * Some algorithms may expand the number of bytes needed to send data. - * If we only supply the output buffer with the same number - * of bytes as the input buffer, we will fail. - */ - bufSize = contentLen + SSL3_BUFFER_FUDGE; - - /* - * null compression is easy to do - PORT_Memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH, buf, contentLen); - */ - - ssl_GetSpecReadLock(ss); /********************************/ - - cwSpec = ss->ssl3.cwSpec; - cipher_def = cwSpec->cipher_def; - /* - * Add the MAC - */ - 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); - - /* - * Pad the text (if we're doing a block cipher) - * then Encrypt it - */ - if (cipher_def->type == type_block) { - unsigned char * pBuf; - int padding_length; - int i; - - 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)); - fragLen += padding_length + 1; - PORT_Assert((fragLen % cipher_def->block_size) == 0); - - /* Pad according to TLS rules (also acceptable to SSL3). */ - pBuf = &write->buf[fragLen + SSL3_RECORD_HEADER_LENGTH - 1]; - 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; - } - 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: - ssl_ReleaseSpecReadLock(ss); + rv = ssl3_CompressMACEncryptRecord( ss, type, pIn, contentLen); + if (rv != SECSuccess) return SECFailure; - } - PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); - /* - * XXX should we zero out our copy of the buffer after compressing - * and encryption ?? - */ - - ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); - - ssl_ReleaseSpecReadLock(ss); /************************************/ - - buf += contentLen; - bytes -= contentLen; - PORT_Assert( bytes >= 0 ); + pIn += contentLen; + nIn -= contentLen; + PORT_Assert( nIn >= 0 ); - /* PORT_Assert(fragLen == cipherBytes); */ - write->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; - write->buf[0] = type; - write->buf[1] = MSB(cwSpec->version); - write->buf[2] = LSB(cwSpec->version); - write->buf[3] = MSB(cipherBytes); - write->buf[4] = LSB(cipherBytes); - - PRINT_BUF(50, (ss, "send (encrypted) record data:", write->buf, write->len)); + PRINT_BUF(50, (ss, "send (encrypted) record data:", wrBuf->buf, wrBuf->len)); /* If there's still some previously saved ciphertext, * or the caller doesn't want us to send the data yet, @@ -1891,59 +1982,57 @@ spec_locked_loser: if ((ss->pendingBuf.len > 0) || (flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - rv = ssl_SaveWriteData(ss, &ss->pendingBuf, - write->buf, write->len); + rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ return SECFailure; } - write->len = 0; /* All cipher text is saved away. */ + wrBuf->len = 0; /* All cipher text is saved away. */ if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - + PRInt32 sent; ss->handshakeBegun = 1; - count = ssl_SendSavedWriteData(ss, &ss->pendingBuf, - &ssl_DefSend); - if (count < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) { + sent = ssl_SendSavedWriteData(ss); + if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); return SECFailure; } + if (ss->pendingBuf.len) { + flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER; + } } - } else if (write->len > 0) { + } else if (wrBuf->len > 0) { + PRInt32 sent; ss->handshakeBegun = 1; - count = ssl_DefSend(ss, write->buf, write->len, - flags & ~ssl_SEND_FLAG_MASK); - if (count < 0) { + sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len, + flags & ~ssl_SEND_FLAG_MASK); + if (sent < 0) { if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return (sent > 0) ? sent : SECFailure; + return SECFailure; } /* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */ - count = 0; + sent = 0; } - /* now take all the remaining unsent newly-generated ciphertext and - * append it to the buffer of previously unsent ciphertext. - */ - if ((unsigned)count < write->len) { - rv = ssl_SaveWriteData(ss, &ss->pendingBuf, - write->buf + (unsigned)count, - write->len - (unsigned)count); + wrBuf->len -= sent; + if (wrBuf->len) { + /* now take all the remaining unsent new ciphertext and + * append it to the buffer of previously unsent ciphertext. + */ + rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ return SECFailure; } } - write->len = 0; - } - sent += contentLen; - if ((flags & ssl_SEND_FLAG_NO_BUFFER) && - (isBlocking || (ss->pendingBuf.len > 0))) { - break; } + totalSent += contentLen; } - return sent; + return totalSent; } +#define SSL3_PENDING_HIGH_WATER 1024 + /* Attempt to send the content of "in" in an SSL application_data record. * Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess. */ @@ -1951,14 +2040,36 @@ int ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PRInt32 len, PRInt32 flags) { - PRInt32 sent = 0; + PRInt32 totalSent = 0; + PRInt32 discarded = 0; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); + if (len < 0 || !in) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + + if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER && + !ssl_SocketIsBlocking(ss)) { + PORT_Assert(!ssl_SocketIsBlocking(ss)); + PORT_SetError(PR_WOULD_BLOCK_ERROR); + return SECFailure; + } - while (len > 0) { - PRInt32 count; + if (ss->appDataBuffered && len) { + PORT_Assert (in[0] == (unsigned char)(ss->appDataBuffered)); + if (in[0] != (unsigned char)(ss->appDataBuffered)) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + in++; + len--; + discarded = 1; + } + while (len > totalSent) { + PRInt32 sent, toSend; - if (sent > 0) { + if (totalSent > 0) { /* * The thread yield is intended to give the reader thread a * chance to get some cycles while the writer thread is in @@ -1969,23 +2080,45 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */ ssl_GetXmitBufLock(ss); } - count = ssl3_SendRecord(ss, content_application_data, in, len, - flags | ssl_SEND_FLAG_NO_BUFFER); - if (count < 0) { - return (sent > 0) ? sent : count; - /* error code set by ssl3_SendRecord */ + toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); + sent = ssl3_SendRecord(ss, content_application_data, + in + totalSent, toSend, flags); + if (sent < 0) { + if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) { + PORT_Assert(ss->lastWriteBlocked); + break; + } + return SECFailure; /* error code set by ssl3_SendRecord */ + } + totalSent += sent; + if (ss->pendingBuf.len) { + /* must be a non-blocking socket */ + PORT_Assert(!ssl_SocketIsBlocking(ss)); + PORT_Assert(ss->lastWriteBlocked); + break; } - sent += count; - len -= count; - in += count; } - return sent; + if (ss->pendingBuf.len) { + /* Must be non-blocking. */ + PORT_Assert(!ssl_SocketIsBlocking(ss)); + if (totalSent > 0) { + ss->appDataBuffered = 0x100 | in[totalSent - 1]; + } + + totalSent = totalSent + discarded - 1; + if (totalSent <= 0) { + PORT_SetError(PR_WOULD_BLOCK_ERROR); + totalSent = SECFailure; + } + return totalSent; + } + ss->appDataBuffered = 0; + return totalSent + discarded; } /* Attempt to send the content of sendBuf buffer in an SSL handshake record. * This function returns SECSuccess or SECFailure, never SECWouldBlock. - * It used to always set sendBuf.len to 0, even when returning SECFailure. - * Now it does not. + * Always set sendBuf.len to 0, even when returning SECFailure. * * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(), * ssl3_AppendHandshake(), ssl3_SendClientHello(), @@ -1995,21 +2128,41 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, static SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) { - PRInt32 rv; + PRInt32 rv = SECSuccess; 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; + return rv; - rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf, - ss->sec.ci.sendBuf.len, flags); - if (rv < 0) { - return (SECStatus)rv; /* error code set by ssl3_SendRecord */ + /* only this flag is allowed */ + PORT_Assert(!(flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER)); + if ((flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER) != 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; + } else { + rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf, + ss->sec.ci.sendBuf.len, flags); } + if (rv < 0) { + int err = PORT_GetError(); + PORT_Assert(err != PR_WOULD_BLOCK_ERROR); + if (err == PR_WOULD_BLOCK_ERROR) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + } + } else if (rv < ss->sec.ci.sendBuf.len) { + /* short write should never happen */ + PORT_Assert(rv >= ss->sec.ci.sendBuf.len); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } else { + rv = SECSuccess; + } + + /* Whether we succeeded or failed, toss the old handshake data. */ ss->sec.ci.sendBuf.len = 0; - return SECSuccess; + return rv; } /* @@ -2218,7 +2371,19 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) case internal_error: error = SSL_ERROR_INTERNAL_ERROR_ALERT; break; case user_canceled: error = SSL_ERROR_USER_CANCELED_ALERT; break; case no_renegotiation: error = SSL_ERROR_NO_RENEGOTIATION_ALERT; break; - default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break; + + /* Alerts for TLS client hello extensions */ + case unsupported_extension: + error = SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT; break; + case certificate_unobtainable: + error = SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT; break; + case unrecognized_name: + error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; break; + case bad_certificate_status_response: + error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT; break; + case bad_certificate_hash_value: + error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT; break; + default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break; } if (level == alert_fatal) { ss->sec.uncache(ss->sec.ci.sid); @@ -2348,7 +2513,7 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) ss->ssl3.prSpec = ss->ssl3.crSpec; ss->ssl3.crSpec = prSpec; - ss->ssl3.hs.ws = wait_finished; + ss->ssl3.hs.ws = wait_finished; SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", SSL_GETPID(), ss->fd )); @@ -2369,7 +2534,7 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) ** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec. */ static SECStatus -ssl3_DeriveMasterSecret(sslSocket *ss, const PK11SymKey *pms) +ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) { ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec; const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def; @@ -2419,9 +2584,20 @@ ssl3_DeriveMasterSecret(sslSocket *ss, const PK11SymKey *pms) } if (pms != NULL) { - pwSpec->master_secret = PK11_DeriveWithFlags((PK11SymKey *)pms, - master_derive, ¶ms, key_derive, - CKA_DERIVE, 0, keyFlags); +#if defined(TRACE) + if (ssl_trace >= 100) { + SECStatus extractRV = PK11_ExtractKeyValue(pms); + if (extractRV == SECSuccess) { + SECItem * keyData = PK11_GetKeyData(pms); + if (keyData && keyData->data && keyData->len) { + ssl_PrintBuf(ss, "Pre-Master Secret", + keyData->data, keyData->len); + } + } + } +#endif + pwSpec->master_secret = PK11_DeriveWithFlags(pms, master_derive, + ¶ms, key_derive, CKA_DERIVE, 0, keyFlags); if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) { SSL3ProtocolVersion client_version; client_version = pms_version.major << 8 | pms_version.minor; @@ -2715,7 +2891,7 @@ ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes) return SECSuccess; } -static SECStatus +SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize) { SECStatus rv; @@ -2820,7 +2996,7 @@ ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, * Thus, the largest value that may be sent this way is 0x7fffffff. * On error, an alert has been sent, and a generic error code has been set. */ -static PRInt32 +PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length) { @@ -3192,6 +3368,7 @@ ssl3_SendClientHello(sslSocket *ss) int length; int num_suites; int actual_count = 0; + PRInt32 total_exten_len = 0; SSL_TRC(3, ("%d: SSL3[%d]: send client_hello handshake", SSL_GETPID(), ss->fd)); @@ -3269,7 +3446,7 @@ ssl3_SendClientHello(sslSocket *ss) } if (!sidOK) { - ++ssl3stats.sch_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_not_ok ); (*ss->sec.uncache)(sid); ssl_FreeSID(sid); sid = NULL; @@ -3277,7 +3454,7 @@ ssl3_SendClientHello(sslSocket *ss) } if (sid) { - ++ssl3stats.sch_sid_cache_hits; + SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits ); rv = ssl3_NegotiateVersion(ss, sid->version); if (rv != SECSuccess) @@ -3288,7 +3465,7 @@ ssl3_SendClientHello(sslSocket *ss) ss->ssl3.policy = sid->u.ssl3.policy; } else { - ++ssl3stats.sch_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_misses ); rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_3_1_TLS); if (rv != SECSuccess) @@ -3327,6 +3504,26 @@ ssl3_SendClientHello(sslSocket *ss) if (!num_suites) return SECFailure; /* ssl3_config_match_init has set error code. */ + if (ss->opt.enableTLS) { + PRUint32 maxBytes = 65535; /* 2^16 - 1 */ + PRInt32 extLen; + + extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, NULL); + if (extLen < 0) { + return SECFailure; + } + maxBytes -= extLen; + total_exten_len += extLen; + + if (total_exten_len > 0) + total_exten_len += 2; + } +#if defined(NSS_ENABLE_ECC) && !defined(NSS_ECC_MORE_THAN_SUITE_B) + else { /* SSL3 only */ + ssl3_DisableECCSuites(ss, NULL); /* disable all ECC suites */ + } +#endif + /* how many suites are permitted by policy and user preference? */ num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) @@ -3335,7 +3532,7 @@ ssl3_SendClientHello(sslSocket *ss) length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength) + 2 + num_suites*sizeof(ssl3CipherSuite) + - 1 + compressionMethodsCount; + 1 + compressionMethodsCount + total_exten_len; rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); if (rv != SECSuccess) { @@ -3409,6 +3606,24 @@ ssl3_SendClientHello(sslSocket *ss) } } + if (total_exten_len) { + PRUint32 maxBytes = total_exten_len - 2; + PRInt32 extLen; + + rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2); + if (rv != SECSuccess) { + return rv; /* err set by AppendHandshake. */ + } + + extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL); + if (extLen < 0) { + return SECFailure; + } + maxBytes -= extLen; + PORT_Assert(!maxBytes); + } + + rv = ssl3_FlushHandshake(ss, 0); if (rv != SECSuccess) { return rv; /* error code set by ssl3_FlushHandshake */ @@ -3470,6 +3685,7 @@ static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { CKM_CDMF_ECB, CKM_SKIPJACK_WRAP, CKM_SKIPJACK_CBC64, + CKM_AES_ECB, UNKNOWN_WRAP_MECHANISM }; @@ -3495,6 +3711,11 @@ ssl_UnwrapSymWrappingKey( { PK11SymKey * unwrappedWrappingKey = NULL; SECItem wrappedKey; +#ifdef NSS_ENABLE_ECC + PK11SymKey * Ks; + SECKEYPublicKey pubWrapKey; + ECCWrappedKeyInfo *ecWrapped; +#endif /* NSS_ENABLE_ECC */ /* found the wrapping key on disk. */ PORT_Assert(pWswk->symWrapMechanism == masterWrapMech); @@ -3515,6 +3736,60 @@ ssl_UnwrapSymWrappingKey( PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, masterWrapMech, CKA_UNWRAP, 0); break; + +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + /* + * For kt_ecdh, we first create an EC public key based on + * data stored with the wrappedSymmetricWrappingkey. Next, + * we do an ECDH computation involving this public key and + * the SSL server's (long-term) EC private key. The resulting + * shared secret is treated the same way as Fortezza's Ks, i.e., + * it is used to recover the symmetric wrapping key. + * + * The data in wrappedSymmetricWrappingkey is laid out as defined + * in the ECCWrappedKeyInfo structure. + */ + ecWrapped = (ECCWrappedKeyInfo *) pWswk->wrappedSymmetricWrappingkey; + + PORT_Assert(ecWrapped->encodedParamLen + ecWrapped->pubValueLen + + ecWrapped->wrappedKeyLen <= MAX_EC_WRAPPED_KEY_BUFLEN); + + if (ecWrapped->encodedParamLen + ecWrapped->pubValueLen + + ecWrapped->wrappedKeyLen > MAX_EC_WRAPPED_KEY_BUFLEN) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + pubWrapKey.keyType = ecKey; + pubWrapKey.u.ec.size = ecWrapped->size; + pubWrapKey.u.ec.DEREncodedParams.len = ecWrapped->encodedParamLen; + pubWrapKey.u.ec.DEREncodedParams.data = ecWrapped->var; + pubWrapKey.u.ec.publicValue.len = ecWrapped->pubValueLen; + pubWrapKey.u.ec.publicValue.data = ecWrapped->var + + ecWrapped->encodedParamLen; + + wrappedKey.len = ecWrapped->wrappedKeyLen; + wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen + + ecWrapped->pubValueLen; + + /* Derive Ks using ECDH */ + Ks = PK11_PubDeriveWithKDF(svrPrivKey, &pubWrapKey, PR_FALSE, NULL, + NULL, CKM_ECDH1_DERIVE, masterWrapMech, + CKA_DERIVE, 0, CKD_NULL, NULL, NULL); + if (Ks == NULL) { + goto loser; + } + + /* Use Ks to unwrap the wrapping key */ + unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL, + &wrappedKey, masterWrapMech, + CKA_UNWRAP, 0); + PK11_FreeSymKey(Ks); + + break; +#endif + default: /* Assert? */ SET_ERROR_CODE @@ -3580,7 +3855,6 @@ getWrappingKey( sslSocket * ss, CK_MECHANISM_TYPE masterWrapMech, void * pwArg) { - CERTCertificate * svrCert; SECKEYPrivateKey * svrPrivKey; SECKEYPublicKey * svrPubKey = NULL; PK11SymKey * unwrappedWrappingKey = NULL; @@ -3650,12 +3924,12 @@ getWrappingKey( sslSocket * ss, */ PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */ - svrCert = ss->serverCerts[exchKeyType].serverCert; - svrPubKey = CERT_ExtractPublicKey(svrCert); + if (ss->serverCerts[exchKeyType].serverKeyPair) { + svrPubKey = ss->serverCerts[exchKeyType].serverKeyPair->pubKey; + } if (svrPubKey == NULL) { - /* CERT_ExtractPublicKey doesn't set error code */ - PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - goto loser; + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; } wrappedKey.type = siBuffer; wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); @@ -3667,6 +3941,12 @@ getWrappingKey( sslSocket * ss, /* wrap symmetric wrapping key in server's public key. */ switch (exchKeyType) { +#ifdef NSS_ENABLE_ECC + PK11SymKey * Ks; + SECKEYPublicKey *pubWrapKey = NULL; + SECKEYPrivateKey *privWrapKey = NULL; + ECCWrappedKeyInfo *ecWrapped; +#endif /* NSS_ENABLE_ECC */ case kt_rsa: asymWrapMechanism = CKM_RSA_PKCS; @@ -3674,6 +3954,94 @@ getWrappingKey( sslSocket * ss, unwrappedWrappingKey, &wrappedKey); break; +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + /* + * We generate an ephemeral EC key pair. Perform an ECDH + * computation involving this ephemeral EC public key and + * the SSL server's (long-term) EC private key. The resulting + * shared secret is treated in the same way as Fortezza's Ks, + * i.e., it is used to wrap the wrapping key. To facilitate + * unwrapping in ssl_UnwrapWrappingKey, we also store all + * relevant info about the ephemeral EC public key in + * wswk.wrappedSymmetricWrappingkey and lay it out as + * described in the ECCWrappedKeyInfo structure. + */ + PORT_Assert(svrPubKey->keyType == ecKey); + if (svrPubKey->keyType != ecKey) { + /* something is wrong in sslsecur.c if this isn't an ecKey */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + goto ec_cleanup; + } + + privWrapKey = SECKEY_CreateECPrivateKey( + &svrPubKey->u.ec.DEREncodedParams, &pubWrapKey, NULL); + if ((privWrapKey == NULL) || (pubWrapKey == NULL)) { + rv = SECFailure; + goto ec_cleanup; + } + + /* Set the key size in bits */ + if (pubWrapKey->u.ec.size == 0) { + pubWrapKey->u.ec.size = SECKEY_PublicKeyStrengthInBits(svrPubKey); + } + + PORT_Assert(pubWrapKey->u.ec.DEREncodedParams.len + + pubWrapKey->u.ec.publicValue.len < MAX_EC_WRAPPED_KEY_BUFLEN); + if (pubWrapKey->u.ec.DEREncodedParams.len + + pubWrapKey->u.ec.publicValue.len >= MAX_EC_WRAPPED_KEY_BUFLEN) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + rv = SECFailure; + goto ec_cleanup; + } + + /* Derive Ks using ECDH */ + Ks = PK11_PubDeriveWithKDF(svrPrivKey, pubWrapKey, PR_FALSE, NULL, + NULL, CKM_ECDH1_DERIVE, masterWrapMech, + CKA_DERIVE, 0, CKD_NULL, NULL, NULL); + if (Ks == NULL) { + rv = SECFailure; + goto ec_cleanup; + } + + ecWrapped = (ECCWrappedKeyInfo *) (wswk.wrappedSymmetricWrappingkey); + ecWrapped->size = pubWrapKey->u.ec.size; + ecWrapped->encodedParamLen = pubWrapKey->u.ec.DEREncodedParams.len; + PORT_Memcpy(ecWrapped->var, pubWrapKey->u.ec.DEREncodedParams.data, + pubWrapKey->u.ec.DEREncodedParams.len); + + ecWrapped->pubValueLen = pubWrapKey->u.ec.publicValue.len; + PORT_Memcpy(ecWrapped->var + ecWrapped->encodedParamLen, + pubWrapKey->u.ec.publicValue.data, + pubWrapKey->u.ec.publicValue.len); + + wrappedKey.len = MAX_EC_WRAPPED_KEY_BUFLEN - + (ecWrapped->encodedParamLen + ecWrapped->pubValueLen); + wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen + + ecWrapped->pubValueLen; + + /* wrap symmetricWrapping key with the local Ks */ + rv = PK11_WrapSymKey(masterWrapMech, NULL, Ks, + unwrappedWrappingKey, &wrappedKey); + + if (rv != SECSuccess) { + goto ec_cleanup; + } + + /* Write down the length of wrapped key in the buffer + * wswk.wrappedSymmetricWrappingkey at the appropriate offset + */ + ecWrapped->wrappedKeyLen = wrappedKey.len; + +ec_cleanup: + if (privWrapKey) SECKEY_DestroyPrivateKey(privWrapKey); + if (pubWrapKey) SECKEY_DestroyPublicKey(pubWrapKey); + if (Ks) PK11_FreeSymKey(Ks); + asymWrapMechanism = masterWrapMech; + break; +#endif /* NSS_ENABLE_ECC */ + default: rv = SECFailure; break; @@ -3716,10 +4084,6 @@ install: loser: done: - if (svrPubKey) { - SECKEY_DestroyPublicKey(svrPubKey); - svrPubKey = NULL; - } PZ_Unlock(symWrapKeysLock); return unwrappedWrappingKey; } @@ -3749,6 +4113,19 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) goto loser; } +#if defined(TRACE) + if (ssl_trace >= 100) { + SECStatus extractRV = PK11_ExtractKeyValue(pms); + if (extractRV == SECSuccess) { + SECItem * keyData = PK11_GetKeyData(pms); + if (keyData && keyData->data && keyData->len) { + ssl_PrintBuf(ss, "Pre-Master Secret", + keyData->data, keyData->len); + } + } + } +#endif + /* Get the wrapped (encrypted) pre-master secret, enc_pms */ enc_pms.len = SECKEY_PublicKeyStrength(svrPubKey); enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len); @@ -3818,6 +4195,10 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) /* Copy DH parameters from server key */ + if (svrPubKey->keyType != dhKey) { + PORT_SetError(SEC_ERROR_BAD_KEY); + goto loser; + } dhParam.prime.data = svrPubKey->u.dh.prime.data; dhParam.prime.len = svrPubKey->u.dh.prime.len; dhParam.base.data = svrPubKey->u.dh.base.data; @@ -4260,7 +4641,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } /* Got a Match */ - ++ssl3stats.hsh_sid_cache_hits; + SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits ); ss->ssl3.hs.ws = wait_change_cipher; ss->ssl3.hs.isResuming = PR_TRUE; @@ -4279,9 +4660,9 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } while (0); if (sid_match) - ++ssl3stats.hsh_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_not_ok ); else - ++ssl3stats.hsh_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_misses ); /* throw the old one away */ sid->u.ssl3.keys.resumable = PR_FALSE; @@ -4576,6 +4957,14 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) CERT_DestroyCertificateList(ss->ssl3.clientCertChain); ss->ssl3.clientCertChain = NULL; } + if (ss->ssl3.clientCertificate != NULL) { + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; + } + if (ss->ssl3.clientPrivateKey != NULL) { + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); + ss->ssl3.clientPrivateKey = NULL; + } isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); @@ -5101,11 +5490,6 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } - /* It's OK for length to be non-zero here. - * Non-zero length means that some new protocol revision has extended - * the client hello message. - */ - desc = handshake_failure; if (sid != NULL) { @@ -5121,33 +5505,54 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ((ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE) && !ss->firstHsDone))) { - ++ssl3stats.hch_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_not_ok ); ss->sec.uncache(sid); ssl_FreeSID(sid); sid = NULL; } } +#ifdef NSS_ENABLE_ECC + /* Disable any ECC cipher suites for which we have no cert. */ + ssl3_FilterECCipherSuitesByServerCerts(ss); +#endif + +#ifdef PARANOID /* Look for a matching cipher suite. */ j = ssl3_config_match_init(ss); if (j <= 0) { /* no ciphers are working/supported by PK11 */ errCode = PORT_GetError(); /* error code is already set. */ goto alert_loser; } +#endif + /* If we already have a session for this client, be sure to pick the ** same cipher suite we picked before. ** This is not a loop, despite appearances. */ if (sid) do { ssl3CipherSuiteCfg *suite = ss->cipherSuites; + /* Find the entry for the cipher suite used in the cached session. */ for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) { if (suite->cipher_suite == sid->u.ssl3.cipherSuite) break; } - if (!j) + PORT_Assert(j > 0); + if (j <= 0) break; +#ifdef PARANOID + /* Double check that the cached cipher suite is still enabled, + * implemented, and allowed by policy. Might have been disabled. + * The product policy won't change during the process lifetime. + * Implemented ("isPresent") shouldn't change for servers. + */ if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) break; +#else + if (!suite->enabled) + break; +#endif + /* Double check that the cached cipher suite is in the client's list */ for (i = 0; i < suites.len; i += 2) { if ((suites.data[i] == MSB(suite->cipher_suite)) && (suites.data[i + 1] == LSB(suite->cipher_suite))) { @@ -5160,6 +5565,37 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } } while (0); + /* START A NEW SESSION */ + + /* Handle TLS hello extensions, for SSL3 & TLS, + * only if we're not restarting a previous session. + */ + if (length) { + /* Get length of hello extensions */ + PRInt32 extension_length; + extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); + if (extension_length < 0) { + goto loser; /* alert already sent */ + } + if (extension_length != length) { + ssl3_DecodeError(ss); /* send alert */ + goto loser; + } + rv = ssl3_HandleClientHelloExtensions(ss, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed */ + } + } + +#ifndef PARANOID + /* Look for a matching cipher suite. */ + j = ssl3_config_match_init(ss); + if (j <= 0) { /* no ciphers are working/supported by PK11 */ + errCode = PORT_GetError(); /* error code is already set. */ + goto alert_loser; + } +#endif + /* Select a cipher suite. ** NOTE: This suite selection algorithm should be the same as the one in ** ssl3_HandleV2ClientHello(). @@ -5294,7 +5730,7 @@ compression_found: * * XXX make sure compression still matches */ - ++ssl3stats.hch_sid_cache_hits; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_hits ); ss->ssl3.hs.isResuming = PR_TRUE; ss->sec.authAlgorithm = sid->authAlgorithm; @@ -5356,12 +5792,12 @@ compression_found: } if (sid) { /* we had a sid, but it's no longer valid, free it */ - ++ssl3stats.hch_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_not_ok ); ss->sec.uncache(sid); ssl_FreeSID(sid); sid = NULL; } - ++ssl3stats.hch_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses ); sid = ssl3_NewSessionID(ss, PR_TRUE); if (sid == NULL) { @@ -5488,7 +5924,10 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0], SSL3_RANDOM_LENGTH)); - +#ifdef NSS_ENABLE_ECC + /* Disable any ECC cipher suites for which we have no cert. */ + ssl3_FilterECCipherSuitesByServerCerts(ss); +#endif i = ssl3_config_match_init(ss); if (i <= 0) { errCode = PORT_GetError(); /* error code is already set. */ @@ -5524,7 +5963,7 @@ suite_found: ss->sec.send = ssl3_SendApplicationData; /* we don't even search for a cache hit here. It's just a miss. */ - ++ssl3stats.hch_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses ); sid = ssl3_NewSessionID(ss, PR_TRUE); if (sid == NULL) { errCode = PORT_GetError(); @@ -5577,7 +6016,9 @@ ssl3_SendServerHello(sslSocket *ss) { sslSessionID *sid; SECStatus rv; + PRUint32 maxBytes = 65535; PRUint32 length; + PRInt32 extensions_len = 0; SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), ss->fd)); @@ -5592,9 +6033,15 @@ ssl3_SendServerHello(sslSocket *ss) } sid = ss->sec.ci.sid; + + extensions_len = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, + &ss->serverExtensionSenders[0]); + if (extensions_len > 0) + extensions_len += 2; /* Add sizeof total extension length */ + length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + 1 + ((sid == NULL) ? 0: SSL3_SESSIONID_BYTES) + - sizeof(ssl3CipherSuite) + 1; + sizeof(ssl3CipherSuite) + 1 + extensions_len; rv = ssl3_AppendHandshakeHeader(ss, server_hello, length); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ @@ -5632,6 +6079,22 @@ ssl3_SendServerHello(sslSocket *ss) if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } + if (extensions_len) { + PRInt32 sent_len; + + extensions_len -= 2; + rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); + if (rv != SECSuccess) + return rv; /* err set by ssl3_SetupPendingCipherSpec */ + sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len, + &ss->serverExtensionSenders[0]); + PORT_Assert(sent_len == extensions_len); + if (sent_len != extensions_len) { + if (sent_len >= 0) + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + } rv = ssl3_SetupPendingCipherSpec(ss); if (rv != SECSuccess) { return rv; /* err set by ssl3_SetupPendingCipherSpec */ @@ -6085,6 +6548,7 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECKEYPrivateKey *serverKey = NULL; SECStatus rv; const ssl3KEADef * kea_def; + ssl3KeyPair *serverKeyPair = NULL; #ifdef NSS_ENABLE_ECC SECKEYPublicKey *serverPubKey = NULL; #endif /* NSS_ENABLE_ECC */ @@ -6103,6 +6567,20 @@ const ssl3KEADef * kea_def; kea_def = ss->ssl3.hs.kea_def; + if (ss->ssl3.hs.usedStepDownKey) { + PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */ + && kea_def->exchKeyType == kt_rsa + && ss->stepDownKeyPair != NULL); + if (!kea_def->is_limited || + kea_def->exchKeyType != kt_rsa || + ss->stepDownKeyPair == NULL) { + /* shouldn't happen, don't use step down if it does */ + goto skip; + } + serverKeyPair = ss->stepDownKeyPair; + ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; + } else +skip: #ifdef NSS_ENABLE_ECC /* XXX Using SSLKEAType to index server certifiates * does not work for (EC)DHE ciphers. Until we have @@ -6111,42 +6589,25 @@ const ssl3KEADef * kea_def; * one seprately. */ if ((kea_def->kea == kea_ecdhe_rsa) || - (kea_def->kea == kea_ecdhe_ecdsa)) { - if (ss->ephemeralECDHKeyPair != NULL) { - serverKey = ss->ephemeralECDHKeyPair->privKey; - ss->sec.keaKeyBits = - SECKEY_PublicKeyStrengthInBits(ss->ephemeralECDHKeyPair->pubKey); - } - } else { -#endif /* NSS_ENABLE_ECC */ - - 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; - - if (ss->ssl3.hs.usedStepDownKey -#ifdef DEBUG - && kea_def->is_limited /* XXX OR cert is signing only */ - && kea_def->exchKeyType == kt_rsa - && ss->stepDownKeyPair != NULL + (kea_def->kea == kea_ecdhe_ecdsa)) { + if (ss->ephemeralECDHKeyPair != NULL) { + serverKeyPair = ss->ephemeralECDHKeyPair; + if (serverKeyPair->pubKey) { + ss->sec.keaKeyBits = + SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); + } + } + } else #endif - ) { - serverKey = ss->stepDownKeyPair->privKey; - ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; - } else { + { sslServerCerts * sc = ss->serverCerts + kea_def->exchKeyType; - serverKey = sc->SERVERKEY; + serverKeyPair = sc->serverKeyPair; ss->sec.keaKeyBits = sc->serverKeyBits; } -#ifdef NSS_ENABLE_ECC + if (serverKeyPair) { + serverKey = serverKeyPair->privKey; } -#endif /* NSS_ENABLE_ECC */ if (serverKey == NULL) { SEND_ALERT @@ -6168,19 +6629,14 @@ const ssl3KEADef * kea_def; #ifdef NSS_ENABLE_ECC case kt_ecdh: - /* XXX We really ought to be able to store multiple + /* XXX We really ought to be able to store multiple * EC certs (a requirement if we wish to support both * ECDH-RSA and ECDH-ECDSA key exchanges concurrently). * When we make that change, we'll need an index other * than kt_ecdh to pick the right EC certificate. */ - if (((kea_def->kea == kea_ecdhe_ecdsa) || - (kea_def->kea == kea_ecdhe_rsa)) && - (ss->ephemeralECDHKeyPair != NULL)) { - serverPubKey = ss->ephemeralECDHKeyPair->pubKey; - } else { - serverPubKey = CERT_ExtractPublicKey( - ss->serverCerts[kt_ecdh].serverCert); + if (serverKeyPair) { + serverPubKey = serverKeyPair->pubKey; } if (serverPubKey == NULL) { /* XXX Is this the right error code? */ @@ -6358,23 +6814,25 @@ ssl3_SendCertificate(sslSocket *ss) if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } - for (i = 0; i < certChain->len; i++) { + if (certChain) { + for (i = 0; i < certChain->len; i++) { #ifdef NISCC_TEST - if (fakeCert.len > 0 && i == ndex) { - rv = ssl3_AppendHandshakeVariable(ss, fakeCert.data, fakeCert.len, - 3); - SECITEM_FreeItem(&fakeCert, PR_FALSE); - } else { - rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, - certChain->certs[i].len, 3); - } + if (fakeCert.len > 0 && i == ndex) { + rv = ssl3_AppendHandshakeVariable(ss, fakeCert.data, + fakeCert.len, 3); + SECITEM_FreeItem(&fakeCert, PR_FALSE); + } else { + rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, + certChain->certs[i].len, 3); + } #else - rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, - certChain->certs[i].len, 3); + rv = ssl3_AppendHandshakeVariable(ss, certChain->certs[i].data, + certChain->certs[i].len, 3); #endif - if (rv != SECSuccess) { - return rv; /* err set by AppendHandshake. */ - } + if (rv != SECSuccess) { + return rv; /* err set by AppendHandshake. */ + } + } } return SECSuccess; @@ -7066,6 +7524,9 @@ xmit_loser: sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite; sid->u.ssl3.compression = ss->ssl3.hs.compression; sid->u.ssl3.policy = ss->ssl3.policy; +#ifdef NSS_ENABLE_ECC + sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves; +#endif sid->u.ssl3.exchKeyType = effectiveExchKeyType; sid->version = ss->version; sid->authAlgorithm = ss->sec.authAlgorithm; @@ -7596,9 +8057,9 @@ process_it: case content_handshake: rv = ssl3_HandleHandshake(ss, databuf); break; - case content_application_data: - rv = SECSuccess; - break; + /* + case content_application_data is handled before this switch + */ default: SSL_DBG(("%d: SSL3[%d]: bogus content type=%d", SSL_GETPID(), ss->fd, cText->type)); @@ -7688,6 +8149,9 @@ ssl3_InitState(sslSocket *ss) ssl3_InitCipherSpec(ss, ss->ssl3.prSpec); ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; +#ifdef NSS_ENABLE_ECC + ss->ssl3.hs.negotiatedECCurves = SSL3_SUPPORTED_CURVES_MASK; +#endif ssl_ReleaseSpecWriteLock(ss); /* @@ -7742,8 +8206,7 @@ ssl3_NewKeyPair( SECKEYPrivateKey * privKey, SECKEYPublicKey * pubKey) { ssl3KeyPair * pair; - if (!privKey && !pubKey) { - /* one or the other may be NULL, but not both. */ + if (!privKey || !pubKey) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return NULL; } |