| Index: net/third_party/nss/ssl/ssl3con.c
|
| diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
|
| index 02b0ddaf9f1d3d049a5d7e0b24b3f339925f1d6c..e5e620fd34cfc87a1ba9a24ddf22b3c095fe5ed7 100644
|
| --- a/net/third_party/nss/ssl/ssl3con.c
|
| +++ b/net/third_party/nss/ssl/ssl3con.c
|
| @@ -25,6 +25,8 @@
|
| #include "prerror.h"
|
| #include "pratom.h"
|
| #include "prthread.h"
|
| +#include "nss.h"
|
| +#include "nssoptions.h"
|
|
|
| #include "pk11func.h"
|
| #include "secmod.h"
|
| @@ -91,8 +93,11 @@ static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
|
| static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
|
| const unsigned char *b,
|
| unsigned int l);
|
| +static SECStatus ssl3_ComputeHandshakeHashes(sslSocket *ss,
|
| + ssl3CipherSpec *spec,
|
| + SSL3Hashes *hashes,
|
| + PRUint32 sender);
|
| static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
|
| -static int ssl3_OIDToTLSHashAlgorithm(SECOidTag oid);
|
|
|
| static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
|
| int maxOutputLen, const unsigned char *input,
|
| @@ -122,17 +127,17 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
|
| #ifndef NSS_DISABLE_ECC
|
| { TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| + { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| /* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around
|
| * bug 946147.
|
| */
|
| - { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| - { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| + { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| @@ -140,14 +145,17 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
|
| #endif /* NSS_DISABLE_ECC */
|
|
|
| { TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| + { TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| { TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
|
| @@ -205,6 +213,23 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
|
| { TLS_RSA_WITH_NULL_MD5, SSL_ALLOWED, PR_FALSE, PR_FALSE},
|
| };
|
|
|
| +static const SSLSignatureAndHashAlg defaultSignatureAlgorithms[] = {
|
| + {ssl_hash_sha256, ssl_sign_rsa},
|
| + {ssl_hash_sha384, ssl_sign_rsa},
|
| + {ssl_hash_sha512, ssl_sign_rsa},
|
| + {ssl_hash_sha1, ssl_sign_rsa},
|
| +#ifndef NSS_DISABLE_ECC
|
| + {ssl_hash_sha256, ssl_sign_ecdsa},
|
| + {ssl_hash_sha384, ssl_sign_ecdsa},
|
| + {ssl_hash_sha512, ssl_sign_ecdsa},
|
| + {ssl_hash_sha1, ssl_sign_ecdsa},
|
| +#endif
|
| + {ssl_hash_sha256, ssl_sign_dsa},
|
| + {ssl_hash_sha1, ssl_sign_dsa}
|
| +};
|
| +PR_STATIC_ASSERT(PR_ARRAY_SIZE(defaultSignatureAlgorithms) <=
|
| + MAX_SIGNATURE_ALGORITHMS);
|
| +
|
| /* Verify that SSL_ImplementedCiphers and cipherSuites are in consistent order.
|
| */
|
| #ifdef DEBUG
|
| @@ -265,20 +290,6 @@ static const /*SSL3ClientCertificateType */ PRUint8 certificate_types [] = {
|
| ct_DSS_sign,
|
| };
|
|
|
| -/* This block is the contents of the supported_signature_algorithms field of
|
| - * our TLS 1.2 CertificateRequest message, in wire format. See
|
| - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
|
| - *
|
| - * This block contains only sha256 entries because we only support TLS 1.2
|
| - * CertificateVerify messages that use the handshake hash. */
|
| -static const PRUint8 supported_signature_algorithms[] = {
|
| - tls_hash_sha256, tls_sig_rsa,
|
| -#ifndef NSS_DISABLE_ECC
|
| - tls_hash_sha256, tls_sig_ecdsa,
|
| -#endif
|
| - tls_hash_sha256, tls_sig_dsa,
|
| -};
|
| -
|
| #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
|
|
|
|
|
| @@ -322,8 +333,8 @@ static const ssl3KEADef kea_defs[] =
|
| /* kea exchKeyType signKeyType is_limited limit tls_keygen ephemeral */
|
| {kea_null, kt_null, sign_null, PR_FALSE, 0, PR_FALSE, PR_FALSE},
|
| {kea_rsa, kt_rsa, sign_rsa, PR_FALSE, 0, PR_FALSE, PR_FALSE},
|
| - {kea_rsa_export, kt_rsa, sign_rsa, PR_TRUE, 512, PR_FALSE, PR_TRUE},
|
| - {kea_rsa_export_1024,kt_rsa, sign_rsa, PR_TRUE, 1024, PR_FALSE, PR_TRUE},
|
| + {kea_rsa_export, kt_rsa, sign_rsa, PR_TRUE, 512, PR_FALSE, PR_FALSE},
|
| + {kea_rsa_export_1024,kt_rsa, sign_rsa, PR_TRUE, 1024, PR_FALSE, PR_FALSE},
|
| {kea_dh_dss, kt_dh, sign_dsa, PR_FALSE, 0, PR_FALSE, PR_FALSE},
|
| {kea_dh_dss_export, kt_dh, sign_dsa, PR_TRUE, 512, PR_FALSE, PR_FALSE},
|
| {kea_dh_rsa, kt_dh, sign_rsa, PR_FALSE, 0, PR_FALSE, PR_FALSE},
|
| @@ -443,6 +454,10 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] =
|
| {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, cipher_chacha20, mac_aead, kea_ecdhe_rsa},
|
| {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, cipher_chacha20, mac_aead, kea_ecdhe_ecdsa},
|
|
|
| + {TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_aead, kea_dhe_dss},
|
| + {TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, hmac_sha256, kea_dhe_dss},
|
| + {TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, hmac_sha256, kea_dhe_dss},
|
| +
|
| #ifndef NSS_DISABLE_ECC
|
| {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},
|
| @@ -680,6 +695,8 @@ ssl3_CipherSuiteAllowedForVersionRange(
|
| case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
|
| case TLS_RSA_WITH_AES_128_CBC_SHA256:
|
| case TLS_RSA_WITH_AES_128_GCM_SHA256:
|
| + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
|
| + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
|
| case TLS_RSA_WITH_NULL_SHA256:
|
| return vrange->max == SSL_LIBRARY_VERSION_TLS_1_2;
|
|
|
| @@ -688,6 +705,7 @@ ssl3_CipherSuiteAllowedForVersionRange(
|
| case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
|
| case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
|
| case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
|
| + case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
|
| return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2;
|
|
|
| /* RFC 4492: ECC cipher suites need TLS extensions to negotiate curves and
|
| @@ -810,16 +828,11 @@ ssl3_config_match_init(sslSocket *ss)
|
| * that the server uses an RSA cert for (EC)DHE-RSA.
|
| */
|
| switch (cipher_def->key_exchange_alg) {
|
| + case kea_dhe_dss:
|
| + svrAuth = ss->serverCerts + ssl_kea_dh;
|
| + break;
|
| 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:
|
| @@ -831,6 +844,8 @@ ssl3_config_match_init(sslSocket *ss)
|
| * simultaneously. For now, both of them use
|
| * whatever is in the certificate slot for kt_ecdh
|
| */
|
| + case kea_dhe_dss_export:
|
| + case kea_dhe_rsa_export:
|
| default:
|
| svrAuth = ss->serverCerts + exchKeyType;
|
| break;
|
| @@ -867,11 +882,22 @@ ssl3_config_match_init(sslSocket *ss)
|
| * cipher suite. */
|
| static PRBool
|
| config_match(ssl3CipherSuiteCfg *suite, int policy, PRBool enabled,
|
| - const SSLVersionRange *vrange)
|
| + const SSLVersionRange *vrange, const sslSocket *ss)
|
| {
|
| + const ssl3CipherSuiteDef *cipher_def;
|
| +
|
| PORT_Assert(policy != SSL_NOT_ALLOWED && enabled != PR_FALSE);
|
| if (policy == SSL_NOT_ALLOWED || !enabled)
|
| - return PR_FALSE;
|
| + return PR_FALSE;
|
| +
|
| + cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
|
| + PORT_Assert(cipher_def != NULL);
|
| +
|
| + PORT_Assert(ss != NULL);
|
| + if (ss->sec.isServer && !ss->opt.enableServerDhe &&
|
| + kea_defs[cipher_def->key_exchange_alg].exchKeyType == ssl_kea_dh)
|
| + return PR_FALSE;
|
| +
|
| return (PRBool)(suite->enabled &&
|
| suite->isPresent &&
|
| suite->policy != SSL_NOT_ALLOWED &&
|
| @@ -892,7 +918,7 @@ count_cipher_suites(sslSocket *ss, int policy, PRBool enabled)
|
| return 0;
|
| }
|
| for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
|
| - if (config_match(&ss->cipherSuites[i], policy, enabled, &ss->vrange))
|
| + if (config_match(&ss->cipherSuites[i], policy, enabled, &ss->vrange, ss))
|
| count++;
|
| }
|
| if (count <= 0) {
|
| @@ -984,9 +1010,9 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf,
|
| break;
|
| case dsaKey:
|
| doDerEncode = isTLS;
|
| - /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
|
| * In that case, we use just the SHA1 part. */
|
| - if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hash->hashAlg == ssl_hash_none) {
|
| hashItem.data = hash->u.s.sha;
|
| hashItem.len = sizeof(hash->u.s.sha);
|
| } else {
|
| @@ -997,9 +1023,9 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf,
|
| #ifndef NSS_DISABLE_ECC
|
| case ecKey:
|
| doDerEncode = PR_TRUE;
|
| - /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
|
| * In that case, we use just the SHA1 part. */
|
| - if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hash->hashAlg == ssl_hash_none) {
|
| hashItem.data = hash->u.s.sha;
|
| hashItem.len = sizeof(hash->u.s.sha);
|
| } else {
|
| @@ -1014,7 +1040,7 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf,
|
| }
|
| PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
|
|
|
| - if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hash->hashAlg == ssl_hash_none) {
|
| signatureLen = PK11_SignatureLen(key);
|
| if (signatureLen <= 0) {
|
| PORT_SetError(SEC_ERROR_INVALID_KEY);
|
| @@ -1028,7 +1054,8 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf,
|
|
|
| rv = PK11_Sign(key, buf, &hashItem);
|
| } else {
|
| - rv = SGN_Digest(key, hash->hashAlg, buf, &hashItem);
|
| + SECOidTag hashOID = ssl3_TLSHashAlgorithmToOID(hash->hashAlg);
|
| + rv = SGN_Digest(key, hashOID, buf, &hashItem);
|
| }
|
| if (rv != SECSuccess) {
|
| ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
|
| @@ -1076,7 +1103,7 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
|
| return SECFailure;
|
| }
|
|
|
| - hashAlg = hash->hashAlg;
|
| + hashAlg = ssl3_TLSHashAlgorithmToOID(hash->hashAlg);
|
| switch (key->keyType) {
|
| case rsaKey:
|
| encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
|
| @@ -1085,9 +1112,9 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
|
| break;
|
| case dsaKey:
|
| encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
|
| - /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
|
| * In that case, we use just the SHA1 part. */
|
| - if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hash->hashAlg == ssl_hash_none) {
|
| hashItem.data = hash->u.s.sha;
|
| hashItem.len = sizeof(hash->u.s.sha);
|
| } else {
|
| @@ -1108,13 +1135,13 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
|
| #ifndef NSS_DISABLE_ECC
|
| case ecKey:
|
| encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
|
| - /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + /* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
|
| * In that case, we use just the SHA1 part.
|
| * ECDSA signatures always encode the integers r and s using ASN.1
|
| * (unlike DSA where ASN.1 encoding is used with TLS but not with
|
| * SSL3). So we can use VFY_VerifyDigestDirect for ECDSA.
|
| */
|
| - if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hash->hashAlg == ssl_hash_none) {
|
| hashAlg = SEC_OID_SHA1;
|
| hashItem.data = hash->u.s.sha;
|
| hashItem.len = sizeof(hash->u.s.sha);
|
| @@ -1142,8 +1169,8 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
|
| */
|
| rv = PK11_Verify(key, buf, &hashItem, pwArg);
|
| } else {
|
| - rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg,
|
| - pwArg);
|
| + rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg,
|
| + pwArg);
|
| }
|
| SECKEY_DestroyPublicKey(key);
|
| if (signature) {
|
| @@ -1159,75 +1186,71 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
|
| /* Caller must set hiLevel error code. */
|
| /* Called from ssl3_ComputeExportRSAKeyHash
|
| * ssl3_ComputeDHKeyHash
|
| - * which are called from ssl3_HandleServerKeyExchange.
|
| + * which are called from ssl3_HandleServerKeyExchange.
|
| *
|
| - * hashAlg: either the OID for a hash algorithm or SEC_OID_UNKNOWN to specify
|
| - * the pre-1.2, MD5/SHA1 combination hash.
|
| + * hashAlg: ssl_hash_none indicates the pre-1.2, MD5/SHA1 combination hash.
|
| */
|
| SECStatus
|
| -ssl3_ComputeCommonKeyHash(SECOidTag hashAlg,
|
| - PRUint8 * hashBuf, unsigned int bufLen,
|
| - SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| +ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
|
| + PRUint8 * hashBuf, unsigned int bufLen,
|
| + SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| {
|
| - SECStatus rv = SECSuccess;
|
| + SECStatus rv;
|
| + SECOidTag hashOID;
|
|
|
| #ifndef NO_PKCS11_BYPASS
|
| if (bypassPKCS11) {
|
| - if (hashAlg == SEC_OID_UNKNOWN) {
|
| - MD5_HashBuf (hashes->u.s.md5, hashBuf, bufLen);
|
| - SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen);
|
| - hashes->len = MD5_LENGTH + SHA1_LENGTH;
|
| - } else if (hashAlg == SEC_OID_SHA1) {
|
| - SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| - hashes->len = SHA1_LENGTH;
|
| - } else if (hashAlg == SEC_OID_SHA256) {
|
| - SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| - hashes->len = SHA256_LENGTH;
|
| - } else if (hashAlg == SEC_OID_SHA384) {
|
| - SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| - hashes->len = SHA384_LENGTH;
|
| - } else if (hashAlg == SEC_OID_SHA512) {
|
| - SHA512_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| - hashes->len = SHA512_LENGTH;
|
| - } else {
|
| - PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| - return SECFailure;
|
| - }
|
| - } else
|
| + if (hashAlg == ssl_hash_none) {
|
| + MD5_HashBuf (hashes->u.s.md5, hashBuf, bufLen);
|
| + SHA1_HashBuf(hashes->u.s.sha, hashBuf, bufLen);
|
| + hashes->len = MD5_LENGTH + SHA1_LENGTH;
|
| + } else if (hashAlg == ssl_hash_sha1) {
|
| + SHA1_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| + hashes->len = SHA1_LENGTH;
|
| + } else if (hashAlg == ssl_hash_sha256) {
|
| + SHA256_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| + hashes->len = SHA256_LENGTH;
|
| + } else if (hashAlg == ssl_hash_sha384) {
|
| + SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| + hashes->len = SHA384_LENGTH;
|
| + } else if (hashAlg == ssl_hash_sha512) {
|
| + SHA512_HashBuf(hashes->u.raw, hashBuf, bufLen);
|
| + hashes->len = SHA512_LENGTH;
|
| + } else {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| + return SECFailure;
|
| + }
|
| + } else
|
| #endif
|
| {
|
| - if (hashAlg == SEC_OID_UNKNOWN) {
|
| - rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| - rv = SECFailure;
|
| - goto done;
|
| - }
|
| -
|
| - rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| - rv = SECFailure;
|
| - }
|
| - hashes->len = MD5_LENGTH + SHA1_LENGTH;
|
| - } else {
|
| - hashes->len = HASH_ResultLenByOidTag(hashAlg);
|
| - if (hashes->len > sizeof(hashes->u.raw)) {
|
| - ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| - rv = SECFailure;
|
| - goto done;
|
| - }
|
| - rv = PK11_HashBuf(hashAlg, hashes->u.raw, hashBuf, bufLen);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
|
| - rv = SECFailure;
|
| - }
|
| - }
|
| + if (hashAlg == ssl_hash_none) {
|
| + rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| + return rv;
|
| + }
|
| + rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| + return rv;
|
| + }
|
| + hashes->len = MD5_LENGTH + SHA1_LENGTH;
|
| + } else {
|
| + hashOID = ssl3_TLSHashAlgorithmToOID(hashAlg);
|
| + hashes->len = HASH_ResultLenByOidTag(hashOID);
|
| + if (hashes->len == 0 || hashes->len > sizeof(hashes->u.raw)) {
|
| + ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| + return SECFailure;
|
| + }
|
| + rv = PK11_HashBuf(hashOID, hashes->u.raw, hashBuf, bufLen);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
|
| + return rv;
|
| + }
|
| + }
|
| }
|
| hashes->hashAlg = hashAlg;
|
| -
|
| -done:
|
| - return rv;
|
| + return SECSuccess;
|
| }
|
|
|
| /* Caller must set hiLevel error code.
|
| @@ -1235,10 +1258,10 @@ done:
|
| ** ssl3_HandleServerKeyExchange.
|
| */
|
| static SECStatus
|
| -ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg,
|
| - SECItem modulus, SECItem publicExponent,
|
| - SSL3Random *client_rand, SSL3Random *server_rand,
|
| - SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| +ssl3_ComputeExportRSAKeyHash(SSLHashType hashAlg,
|
| + SECItem modulus, SECItem publicExponent,
|
| + SSL3Random *client_rand, SSL3Random *server_rand,
|
| + SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| {
|
| PRUint8 * hashBuf;
|
| PRUint8 * pBuf;
|
| @@ -1276,7 +1299,7 @@ ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg,
|
| bypassPKCS11);
|
|
|
| PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen));
|
| - if (hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hashAlg == ssl_hash_none) {
|
| PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result",
|
| hashes->u.s.md5, MD5_LENGTH));
|
| PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result",
|
| @@ -1294,10 +1317,10 @@ ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg,
|
| /* Caller must set hiLevel error code. */
|
| /* Called from ssl3_HandleServerKeyExchange. */
|
| static SECStatus
|
| -ssl3_ComputeDHKeyHash(SECOidTag hashAlg,
|
| - SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
|
| - SSL3Random *client_rand, SSL3Random *server_rand,
|
| - SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| +ssl3_ComputeDHKeyHash(SSLHashType hashAlg,
|
| + SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
|
| + SSL3Random *client_rand, SSL3Random *server_rand,
|
| + SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| {
|
| PRUint8 * hashBuf;
|
| PRUint8 * pBuf;
|
| @@ -1340,7 +1363,7 @@ ssl3_ComputeDHKeyHash(SECOidTag hashAlg,
|
| bypassPKCS11);
|
|
|
| PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen));
|
| - if (hashAlg == SEC_OID_UNKNOWN) {
|
| + if (hashAlg == ssl_hash_none) {
|
| PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
|
| hashes->u.s.md5, MD5_LENGTH));
|
| PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
|
| @@ -2298,7 +2321,11 @@ fail:
|
| * 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.
|
| + * This code is common to the bypass and PKCS11 execution paths. For
|
| + * the bypass case, pms is NULL. If the old master secret is reused,
|
| + * pms is NULL and the master secret is already in either
|
| + * pwSpec->msItem.len (the bypass case) or pwSpec->master_secret.
|
| + *
|
| * For the bypass case, pms is NULL.
|
| */
|
| SECStatus
|
| @@ -2682,7 +2709,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
|
| PRUint32 fragLen;
|
| PRUint32 p1Len, p2Len, oddLen = 0;
|
| PRUint16 headerLen;
|
| - int ivLen = 0;
|
| + unsigned int ivLen = 0;
|
| int cipherBytes = 0;
|
| unsigned char pseudoHeader[13];
|
| unsigned int pseudoHeaderLen;
|
| @@ -3244,7 +3271,8 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
|
| {
|
| static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER |
|
| ssl_SEND_FLAG_CAP_RECORD_VERSION;
|
| - PRInt32 rv = SECSuccess;
|
| + PRInt32 count = -1;
|
| + SECStatus rv = SECSuccess;
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
|
| @@ -3258,18 +3286,19 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
|
| PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| rv = SECFailure;
|
| } else {
|
| - rv = ssl3_SendRecord(ss, 0, content_handshake, ss->sec.ci.sendBuf.buf,
|
| + count = ssl3_SendRecord(ss, 0, content_handshake, ss->sec.ci.sendBuf.buf,
|
| ss->sec.ci.sendBuf.len, flags);
|
| }
|
| - if (rv < 0) {
|
| + if (count < 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) {
|
| + rv = SECFailure;
|
| + } else if ((unsigned int)count < ss->sec.ci.sendBuf.len) {
|
| /* short write should never happen */
|
| - PORT_Assert(rv >= ss->sec.ci.sendBuf.len);
|
| + PORT_Assert((unsigned int)count >= ss->sec.ci.sendBuf.len);
|
| PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| rv = SECFailure;
|
| } else {
|
| @@ -3705,13 +3734,70 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
|
| return SECSuccess;
|
| }
|
|
|
| -/* 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.
|
| +/* This method completes the derivation of the MS from the PMS.
|
| +**
|
| +** 1. Derive the MS, if possible, else return an error.
|
| +**
|
| +** 2. Check the version if |pms_version| is non-zero and if wrong,
|
| +** return an error.
|
| +**
|
| +** 3. If |msp| is nonzero, return MS in |*msp|.
|
| +
|
| +** Called from:
|
| +** ssl3_ComputeMasterSecretInt
|
| +** tls_ComputeExtendedMasterSecretInt
|
| */
|
| static SECStatus
|
| -ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| +ssl3_ComputeMasterSecretFinish(sslSocket *ss,
|
| + CK_MECHANISM_TYPE master_derive,
|
| + CK_MECHANISM_TYPE key_derive,
|
| + CK_VERSION *pms_version,
|
| + SECItem *params, CK_FLAGS keyFlags,
|
| + PK11SymKey *pms, PK11SymKey **msp)
|
| +{
|
| + PK11SymKey *ms = NULL;
|
| +
|
| + ms = PK11_DeriveWithFlags(pms, master_derive,
|
| + params, key_derive,
|
| + CKA_DERIVE, 0, keyFlags);
|
| + if (!ms) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + if (pms_version && ss->opt.detectRollBack) {
|
| + SSL3ProtocolVersion client_version;
|
| + client_version = pms_version->major << 8 | pms_version->minor;
|
| +
|
| + if (IS_DTLS(ss)) {
|
| + client_version = dtls_DTLSVersionToTLSVersion(client_version);
|
| + }
|
| +
|
| + if (client_version != ss->clientHelloVersion) {
|
| + /* Destroy MS. Version roll-back detected. */
|
| + PK11_FreeSymKey(ms);
|
| + ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
|
| + return SECFailure;
|
| + }
|
| + }
|
| +
|
| + if (msp) {
|
| + *msp = ms;
|
| + } else {
|
| + PK11_FreeSymKey(ms);
|
| + }
|
| +
|
| + return SECSuccess;
|
| +}
|
| +
|
| +/* Compute the ordinary (pre draft-ietf-tls-session-hash) master
|
| + ** secret and return it in |*msp|.
|
| + **
|
| + ** Called from: ssl3_ComputeMasterSecret
|
| + */
|
| +static SECStatus
|
| +ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
|
| + PK11SymKey **msp)
|
| {
|
| ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
|
| const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def;
|
| @@ -3721,28 +3807,27 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
|
| PRBool isTLS12=
|
| (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
|
| - /*
|
| + /*
|
| * 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.
|
| + * data into a 48-byte value, and does not expect to return the version.
|
| */
|
| 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;
|
| SECItem params;
|
| CK_FLAGS keyFlags;
|
| CK_VERSION pms_version;
|
| - CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
|
| + CK_VERSION *pms_version_ptr = NULL;
|
| + /* master_params may be used as a CK_SSL3_MASTER_KEY_DERIVE_PARAMS */
|
| + CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params;
|
| + unsigned int master_params_len;
|
|
|
| - 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 (isTLS12) {
|
| - if(isDH) master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256;
|
| - else master_derive = CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256;
|
| - key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256;
|
| + if(isDH) master_derive = CKM_TLS12_MASTER_KEY_DERIVE_DH;
|
| + else master_derive = CKM_TLS12_MASTER_KEY_DERIVE;
|
| + key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
|
| keyFlags = CKF_SIGN | CKF_VERIFY;
|
| } else if (isTLS) {
|
| if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
|
| @@ -3756,87 +3841,142 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| keyFlags = 0;
|
| }
|
|
|
| - if (pms || !pwSpec->master_secret) {
|
| - if (isDH) {
|
| - master_params.pVersion = NULL;
|
| - } else {
|
| - master_params.pVersion = &pms_version;
|
| - }
|
| - master_params.RandomInfo.pClientRandom = cr;
|
| - master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
|
| - master_params.RandomInfo.pServerRandom = sr;
|
| - master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
|
| + if (!isDH) {
|
| + pms_version_ptr = &pms_version;
|
| + }
|
|
|
| - params.data = (unsigned char *) &master_params;
|
| - params.len = sizeof master_params;
|
| + master_params.pVersion = pms_version_ptr;
|
| + master_params.RandomInfo.pClientRandom = cr;
|
| + master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
|
| + master_params.RandomInfo.pServerRandom = sr;
|
| + master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
|
| + if (isTLS12) {
|
| + master_params.prfHashMechanism = CKM_SHA256;
|
| + master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
|
| + } else {
|
| + /* prfHashMechanism is not relevant with this PRF */
|
| + master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
|
| }
|
|
|
| - if (pms != NULL) {
|
| -#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;
|
| + params.data = (unsigned char *) &master_params;
|
| + params.len = master_params_len;
|
|
|
| - if (IS_DTLS(ss)) {
|
| - client_version = dtls_DTLSVersionToTLSVersion(client_version);
|
| - }
|
| + return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
|
| + pms_version_ptr, ¶ms,
|
| + keyFlags, pms, msp);
|
| +}
|
|
|
| - if (client_version != ss->clientHelloVersion) {
|
| - /* Destroy it. Version roll-back detected. */
|
| - PK11_FreeSymKey(pwSpec->master_secret);
|
| - pwSpec->master_secret = NULL;
|
| - }
|
| - }
|
| - if (pwSpec->master_secret == NULL) {
|
| - /* Generate a faux master secret in the same slot as the old one. */
|
| - PK11SlotInfo * slot = PK11_GetSlotFromKey((PK11SymKey *)pms);
|
| - PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
|
| +/* Compute the draft-ietf-tls-session-hash master
|
| +** secret and return it in |*msp|.
|
| +**
|
| +** Called from: ssl3_ComputeMasterSecret
|
| +*/
|
| +static SECStatus
|
| +tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
|
| + PK11SymKey **msp)
|
| +{
|
| + ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
|
| + CK_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_PARAMS extended_master_params;
|
| + SSL3Hashes hashes;
|
| + /*
|
| + * Determine whether to use the DH/ECDH or RSA derivation modes.
|
| + */
|
| + /*
|
| + * TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion
|
| + * mode. Bug 1198298 */
|
| + PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
|
| + (ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
|
| + CK_MECHANISM_TYPE master_derive;
|
| + CK_MECHANISM_TYPE key_derive;
|
| + SECItem params;
|
| + const CK_FLAGS keyFlags = CKF_SIGN | CKF_VERIFY;
|
| + CK_VERSION pms_version;
|
| + CK_VERSION *pms_version_ptr = NULL;
|
| + SECStatus rv;
|
|
|
| - PK11_FreeSlot(slot);
|
| - if (fpms != NULL) {
|
| - pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
|
| - master_derive, ¶ms, key_derive,
|
| - CKA_DERIVE, 0, keyFlags);
|
| - PK11_FreeSymKey(fpms);
|
| - }
|
| - }
|
| + rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0);
|
| + if (rv != SECSuccess) {
|
| + PORT_Assert(0); /* Should never fail */
|
| + ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
|
| + return SECFailure;
|
| }
|
| - if (pwSpec->master_secret == NULL) {
|
| - /* Generate a faux master secret from the internal slot. */
|
| - PK11SlotInfo * slot = PK11_GetInternalSlot();
|
| - PK11SymKey * fpms = ssl3_GenerateRSAPMS(ss, pwSpec, slot);
|
|
|
| - PK11_FreeSlot(slot);
|
| - if (fpms != NULL) {
|
| - pwSpec->master_secret = PK11_DeriveWithFlags(fpms,
|
| - master_derive, ¶ms, key_derive,
|
| - CKA_DERIVE, 0, keyFlags);
|
| - if (pwSpec->master_secret == NULL) {
|
| - pwSpec->master_secret = fpms; /* use the fpms as the master. */
|
| - fpms = NULL;
|
| - }
|
| - }
|
| - if (fpms) {
|
| - PK11_FreeSymKey(fpms);
|
| - }
|
| + if (isDH) {
|
| + master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH;
|
| + } else {
|
| + master_derive = CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE;
|
| + pms_version_ptr = &pms_version;
|
| }
|
| - if (pwSpec->master_secret == NULL) {
|
| - ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
|
| - return rv;
|
| +
|
| + if (pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + /* TLS 1.2 */
|
| + extended_master_params.prfHashMechanism = CKM_SHA256;
|
| + key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
|
| + } else {
|
| + /* TLS < 1.2 */
|
| + extended_master_params.prfHashMechanism = CKM_TLS_PRF;
|
| + key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
|
| + }
|
| +
|
| + extended_master_params.pVersion = pms_version_ptr;
|
| + extended_master_params.pSessionHash = hashes.u.raw;
|
| + extended_master_params.ulSessionHashLen = hashes.len;
|
| +
|
| + params.data = (unsigned char *) &extended_master_params;
|
| + params.len = sizeof extended_master_params;
|
| +
|
| + return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
|
| + pms_version_ptr, ¶ms,
|
| + keyFlags, pms, msp);
|
| +}
|
| +
|
| +
|
| +/* Wrapper method to compute the master secret and return it in |*msp|.
|
| +**
|
| +** Called from ssl3_ComputeMasterSecret
|
| +*/
|
| +static SECStatus
|
| +ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms,
|
| + PK11SymKey **msp)
|
| +{
|
| + PORT_Assert(pms != NULL);
|
| + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| + PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
|
| +
|
| + if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
|
| + return tls_ComputeExtendedMasterSecretInt(ss, pms, msp);
|
| + } else {
|
| + return ssl3_ComputeMasterSecretInt(ss, pms, msp);
|
| + }
|
| +}
|
| +
|
| +/* This method uses PKCS11 to derive the MS from the PMS, where PMS
|
| +** is a PKCS11 symkey. We call ssl3_ComputeMasterSecret to do the
|
| +** computations and then modify the pwSpec->state as a side effect.
|
| +**
|
| +** This is used in all cases except the "triple bypass" with RSA key
|
| +** exchange.
|
| +**
|
| +** Called from ssl3_InitPendingCipherSpec. prSpec is pwSpec.
|
| +*/
|
| +static SECStatus
|
| +ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| +{
|
| + SECStatus rv;
|
| + PK11SymKey* ms = NULL;
|
| + ssl3CipherSpec *pwSpec = 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 (pms) {
|
| + rv = ssl3_ComputeMasterSecret(ss, pms, &ms);
|
| + pwSpec->master_secret = ms;
|
| + if (rv != SECSuccess)
|
| + return rv;
|
| }
|
| +
|
| #ifndef NO_PKCS11_BYPASS
|
| if (ss->opt.bypassPKCS11) {
|
| SECItem * keydata;
|
| @@ -3847,7 +3987,7 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| 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.
|
| */
|
| @@ -3862,10 +4002,10 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
|
| }
|
| }
|
| #endif
|
| +
|
| return SECSuccess;
|
| }
|
|
|
| -
|
| /*
|
| * Derive encryption and MAC Keys (and IVs) from master secret
|
| * Sets a useful error code when returning SECFailure.
|
| @@ -3898,7 +4038,9 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss)
|
| PK11SymKey * symKey = NULL;
|
| void * pwArg = ss->pkcs11PinArg;
|
| int keySize;
|
| - CK_SSL3_KEY_MAT_PARAMS key_material_params;
|
| + CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a
|
| + * CK_SSL3_KEY_MAT_PARAMS */
|
| + unsigned int key_material_params_len;
|
| CK_SSL3_KEY_MAT_OUT returnedKeys;
|
| CK_MECHANISM_TYPE key_derive;
|
| CK_MECHANISM_TYPE bulk_mechanism;
|
| @@ -3952,17 +4094,21 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss)
|
| PORT_Assert( alg2Mech[calg].calg == calg);
|
| bulk_mechanism = alg2Mech[calg].cmech;
|
|
|
| - params.data = (unsigned char *)&key_material_params;
|
| - params.len = sizeof(key_material_params);
|
| -
|
| if (isTLS12) {
|
| - key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256;
|
| + key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
|
| + key_material_params.prfHashMechanism = CKM_SHA256;
|
| + key_material_params_len = sizeof(CK_TLS12_KEY_MAT_PARAMS);
|
| } else if (isTLS) {
|
| key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
|
| + key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
|
| } else {
|
| key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
|
| + key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
|
| }
|
|
|
| + params.data = (unsigned char *)&key_material_params;
|
| + params.len = key_material_params_len;
|
| +
|
| /* 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,
|
| @@ -4273,6 +4419,12 @@ ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize)
|
| PRUint8 b[4];
|
| PRUint8 * p = b;
|
|
|
| + PORT_Assert(lenSize <= 4 && lenSize > 0);
|
| + if (lenSize < 4 && num >= (1L << (lenSize * 8))) {
|
| + PORT_SetError(SSL_ERROR_TX_RECORD_TOO_LONG);
|
| + return SECFailure;
|
| + }
|
| +
|
| switch (lenSize) {
|
| case 4:
|
| *p++ = (num >> 24) & 0xff;
|
| @@ -4365,17 +4517,12 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length)
|
| * |sigAndHash| to the current handshake message. */
|
| SECStatus
|
| ssl3_AppendSignatureAndHashAlgorithm(
|
| - sslSocket *ss, const SSL3SignatureAndHashAlgorithm* sigAndHash)
|
| + sslSocket *ss, const SSLSignatureAndHashAlg* sigAndHash)
|
| {
|
| - unsigned char serialized[2];
|
| -
|
| - serialized[0] = ssl3_OIDToTLSHashAlgorithm(sigAndHash->hashAlg);
|
| - if (serialized[0] == 0) {
|
| - PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| - return SECFailure;
|
| - }
|
| + PRUint8 serialized[2];
|
|
|
| - serialized[1] = sigAndHash->sigAlg;
|
| + serialized[0] = (PRUint8)sigAndHash->hashAlg;
|
| + serialized[1] = (PRUint8)sigAndHash->sigAlg;
|
|
|
| return ssl3_AppendHandshake(ss, serialized, sizeof(serialized));
|
| }
|
| @@ -4470,6 +4617,7 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
|
| PORT_Assert(bytes <= 3);
|
| i->len = 0;
|
| i->data = NULL;
|
| + i->type = siBuffer;
|
| count = ssl3_ConsumeHandshakeNumber(ss, bytes, b, length);
|
| if (count < 0) { /* Can't test for SECSuccess here. */
|
| return SECFailure;
|
| @@ -4489,15 +4637,13 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
|
| /* tlsHashOIDMap contains the mapping between TLS hash identifiers and the
|
| * SECOidTag used internally by NSS. */
|
| static const struct {
|
| - int tlsHash;
|
| + SSLHashType tlsHash;
|
| SECOidTag oid;
|
| } tlsHashOIDMap[] = {
|
| - { tls_hash_md5, SEC_OID_MD5 },
|
| - { tls_hash_sha1, SEC_OID_SHA1 },
|
| - { tls_hash_sha224, SEC_OID_SHA224 },
|
| - { tls_hash_sha256, SEC_OID_SHA256 },
|
| - { tls_hash_sha384, SEC_OID_SHA384 },
|
| - { tls_hash_sha512, SEC_OID_SHA512 }
|
| + { ssl_hash_sha1, SEC_OID_SHA1 },
|
| + { ssl_hash_sha256, SEC_OID_SHA256 },
|
| + { ssl_hash_sha384, SEC_OID_SHA384 },
|
| + { ssl_hash_sha512, SEC_OID_SHA512 }
|
| };
|
|
|
| /* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value.
|
| @@ -4505,7 +4651,7 @@ static const struct {
|
| *
|
| * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| SECOidTag
|
| -ssl3_TLSHashAlgorithmToOID(int hashFunc)
|
| +ssl3_TLSHashAlgorithmToOID(SSLHashType hashFunc)
|
| {
|
| unsigned int i;
|
|
|
| @@ -4517,42 +4663,24 @@ ssl3_TLSHashAlgorithmToOID(int hashFunc)
|
| return SEC_OID_UNKNOWN;
|
| }
|
|
|
| -/* ssl3_OIDToTLSHashAlgorithm converts an OID to a TLS hash algorithm
|
| - * identifier. If the hash is not recognised, zero is returned.
|
| - *
|
| - * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| -static int
|
| -ssl3_OIDToTLSHashAlgorithm(SECOidTag oid)
|
| -{
|
| - unsigned int i;
|
| -
|
| - for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) {
|
| - if (oid == tlsHashOIDMap[i].oid) {
|
| - return tlsHashOIDMap[i].tlsHash;
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| /* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS 1.2 signature algorithm
|
| * identifier for a given KeyType. */
|
| static SECStatus
|
| -ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType,
|
| - TLSSignatureAlgorithm *out)
|
| +ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType, SSLSignType *out)
|
| {
|
| switch (keyType) {
|
| case rsaKey:
|
| - *out = tls_sig_rsa;
|
| - return SECSuccess;
|
| + *out = ssl_sign_rsa;
|
| + return SECSuccess;
|
| case dsaKey:
|
| - *out = tls_sig_dsa;
|
| - return SECSuccess;
|
| + *out = ssl_sign_dsa;
|
| + return SECSuccess;
|
| case ecKey:
|
| - *out = tls_sig_ecdsa;
|
| - return SECSuccess;
|
| + *out = ssl_sign_ecdsa;
|
| + return SECSuccess;
|
| default:
|
| - PORT_SetError(SEC_ERROR_INVALID_KEY);
|
| - return SECFailure;
|
| + PORT_SetError(SEC_ERROR_INVALID_KEY);
|
| + return SECFailure;
|
| }
|
| }
|
|
|
| @@ -4560,15 +4688,15 @@ ssl3_TLSSignatureAlgorithmForKeyType(KeyType keyType,
|
| * algorithm identifier for the given certificate. */
|
| static SECStatus
|
| ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert,
|
| - TLSSignatureAlgorithm *out)
|
| + SSLSignType *out)
|
| {
|
| SECKEYPublicKey *key;
|
| KeyType keyType;
|
|
|
| key = CERT_ExtractPublicKey(cert);
|
| if (key == NULL) {
|
| - ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| - return SECFailure;
|
| + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| + return SECFailure;
|
| }
|
|
|
| keyType = key->keyType;
|
| @@ -4578,24 +4706,75 @@ ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert,
|
|
|
| /* ssl3_CheckSignatureAndHashAlgorithmConsistency checks that the signature
|
| * algorithm identifier in |sigAndHash| is consistent with the public key in
|
| - * |cert|. If so, SECSuccess is returned. Otherwise, PORT_SetError is called
|
| - * and SECFailure is returned. */
|
| + * |cert|. It also checks the hash algorithm against the configured signature
|
| + * algorithms. If all the tests pass, SECSuccess is returned. Otherwise,
|
| + * PORT_SetError is called and SECFailure is returned. */
|
| SECStatus
|
| ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| - const SSL3SignatureAndHashAlgorithm *sigAndHash, CERTCertificate* cert)
|
| + sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash,
|
| + CERTCertificate* cert)
|
| {
|
| SECStatus rv;
|
| - TLSSignatureAlgorithm sigAlg;
|
| + SSLSignType sigAlg;
|
| + unsigned int i;
|
|
|
| rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg);
|
| if (rv != SECSuccess) {
|
| - return rv;
|
| + return rv;
|
| }
|
| if (sigAlg != sigAndHash->sigAlg) {
|
| - PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
|
| - return SECFailure;
|
| + PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
|
| + return SECFailure;
|
| }
|
| - return SECSuccess;
|
| +
|
| + for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
|
| + const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i];
|
| + if (sigAndHash->sigAlg == alg->sigAlg &&
|
| + sigAndHash->hashAlg == alg->hashAlg) {
|
| + return SECSuccess;
|
| + }
|
| + }
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
| + return SECFailure;
|
| +}
|
| +
|
| +PRBool
|
| +ssl3_IsSupportedSignatureAlgorithm(const SSLSignatureAndHashAlg *alg)
|
| +{
|
| + static const SSLHashType supportedHashes[] = {
|
| + ssl_hash_sha1,
|
| + ssl_hash_sha256,
|
| + ssl_hash_sha384,
|
| + ssl_hash_sha512
|
| + };
|
| +
|
| + static const SSLSignType supportedSigAlgs[] = {
|
| + ssl_sign_rsa,
|
| +#ifndef NSS_DISABLE_ECC
|
| + ssl_sign_ecdsa,
|
| +#endif
|
| + ssl_sign_dsa
|
| + };
|
| +
|
| + unsigned int i;
|
| + PRBool hashOK = PR_FALSE;
|
| + PRBool signOK = PR_FALSE;
|
| +
|
| + for (i = 0; i < PR_ARRAY_SIZE(supportedHashes); ++i) {
|
| + if (alg->hashAlg == supportedHashes[i]) {
|
| + hashOK = PR_TRUE;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + for (i = 0; i < PR_ARRAY_SIZE(supportedSigAlgs); ++i) {
|
| + if (alg->sigAlg == supportedSigAlgs[i]) {
|
| + signOK = PR_TRUE;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return hashOK && signOK;
|
| }
|
|
|
| /* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm
|
| @@ -4605,25 +4784,24 @@ ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| SECStatus
|
| ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss,
|
| - SSL3Opaque **b,
|
| - PRUint32 *length,
|
| - SSL3SignatureAndHashAlgorithm *out)
|
| + SSL3Opaque **b,
|
| + PRUint32 *length,
|
| + SSLSignatureAndHashAlg *out)
|
| {
|
| - unsigned char bytes[2];
|
| + PRUint8 bytes[2];
|
| SECStatus rv;
|
|
|
| rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length);
|
| if (rv != SECSuccess) {
|
| - return rv;
|
| + return rv;
|
| }
|
|
|
| - out->hashAlg = ssl3_TLSHashAlgorithmToOID(bytes[0]);
|
| - if (out->hashAlg == SEC_OID_UNKNOWN) {
|
| - PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| - return SECFailure;
|
| + out->hashAlg = (SSLHashType)bytes[0];
|
| + out->sigAlg = (SSLSignType)bytes[1];
|
| + if (!ssl3_IsSupportedSignatureAlgorithm(out)) {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
| + return SECFailure;
|
| }
|
| -
|
| - out->sigAlg = bytes[1];
|
| return SECSuccess;
|
| }
|
|
|
| @@ -4653,7 +4831,12 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
| SSL3Opaque sha_inner[MAX_MAC_LENGTH];
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| - hashes->hashAlg = SEC_OID_UNKNOWN;
|
| + if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + hashes->hashAlg = ssl_hash_none;
|
|
|
| #ifndef NO_PKCS11_BYPASS
|
| if (ss->opt.bypassPKCS11 &&
|
| @@ -4661,11 +4844,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
| /* compute them without PKCS11 */
|
| PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
|
|
|
| - if (!spec->msItem.data) {
|
| - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
|
| - return SECFailure;
|
| - }
|
| -
|
| ss->ssl3.hs.sha_clone(sha_cx, ss->ssl3.hs.sha_cx);
|
| ss->ssl3.hs.sha_obj->end(sha_cx, hashes->u.raw, &hashes->len,
|
| sizeof(hashes->u.raw));
|
| @@ -4674,7 +4852,7 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
|
|
| /* If we ever support ciphersuites where the PRF hash isn't SHA-256
|
| * then this will need to be updated. */
|
| - hashes->hashAlg = SEC_OID_SHA256;
|
| + hashes->hashAlg = ssl_hash_sha256;
|
| rv = SECSuccess;
|
| } else if (ss->opt.bypassPKCS11) {
|
| /* compute them without PKCS11 */
|
| @@ -4684,11 +4862,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
| #define md5cx ((MD5Context *)md5_cx)
|
| #define shacx ((SHA1Context *)sha_cx)
|
|
|
| - if (!spec->msItem.data) {
|
| - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
|
| - return SECFailure;
|
| - }
|
| -
|
| MD5_Clone (md5cx, (MD5Context *)ss->ssl3.hs.md5_cx);
|
| SHA1_Clone(shacx, (SHA1Context *)ss->ssl3.hs.sha_cx);
|
|
|
| @@ -4696,6 +4869,11 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
| /* compute hashes for SSL3. */
|
| unsigned char s[4];
|
|
|
| + if (!spec->msItem.data) {
|
| + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
|
| + return SECFailure;
|
| + }
|
| +
|
| s[0] = (unsigned char)(sender >> 24);
|
| s[1] = (unsigned char)(sender >> 16);
|
| s[2] = (unsigned char)(sender >> 8);
|
| @@ -4768,11 +4946,6 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
| unsigned char stackBuf[1024];
|
| unsigned char *stateBuf = NULL;
|
|
|
| - if (!spec->master_secret) {
|
| - PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
|
| - return SECFailure;
|
| - }
|
| -
|
| h = ss->ssl3.hs.sha;
|
| stateBuf = PK11_SaveContextAlloc(h, stackBuf,
|
| sizeof(stackBuf), &stateLen);
|
| @@ -4789,7 +4962,7 @@ ssl3_ComputeHandshakeHashes(sslSocket * ss,
|
| }
|
| /* If we ever support ciphersuites where the PRF hash isn't SHA-256
|
| * then this will need to be updated. */
|
| - hashes->hashAlg = SEC_OID_SHA256;
|
| + hashes->hashAlg = ssl_hash_sha256;
|
| rv = SECSuccess;
|
|
|
| tls12_loser:
|
| @@ -4812,11 +4985,6 @@ tls12_loser:
|
| 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) {
|
| @@ -4837,6 +5005,11 @@ tls12_loser:
|
| /* compute hashes for SSL3. */
|
| unsigned char s[4];
|
|
|
| + if (!spec->master_secret) {
|
| + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
|
| + return SECFailure;
|
| + }
|
| +
|
| s[0] = (unsigned char)(sender >> 24);
|
| s[1] = (unsigned char)(sender >> 16);
|
| s[2] = (unsigned char)(sender >> 8);
|
| @@ -4968,7 +5141,7 @@ ssl3_ComputeBackupHandshakeHashes(sslSocket * ss,
|
| rv = SECFailure;
|
| goto loser;
|
| }
|
| - hashes->hashAlg = SEC_OID_SHA1;
|
| + hashes->hashAlg = ssl_hash_sha1;
|
|
|
| loser:
|
| PK11_DestroyContext(ss->ssl3.hs.backupHash, PR_TRUE);
|
| @@ -5049,7 +5222,9 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
|
| if (rv != SECSuccess) {
|
| return rv; /* ssl3_InitState has set the error code. */
|
| }
|
| - ss->ssl3.hs.sendingSCSV = PR_FALSE; /* Must be reset every handshake */
|
| + /* These must be reset every handshake. */
|
| + ss->ssl3.hs.sendingSCSV = PR_FALSE;
|
| + ss->ssl3.hs.preliminaryInfo = 0;
|
| PORT_Assert(IS_DTLS(ss) || !resending);
|
|
|
| SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
|
| @@ -5425,7 +5600,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
|
| }
|
| for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
|
| ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
|
| - if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange)) {
|
| + if (config_match(suite, ss->ssl3.policy, PR_TRUE, &ss->vrange, ss)) {
|
| actual_count++;
|
| if (actual_count > num_suites) {
|
| if (sid->u.ssl3.lock) { NSSRWLock_UnlockRead(sid->u.ssl3.lock); }
|
| @@ -6083,14 +6258,6 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
|
| }
|
| }
|
|
|
| - 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,
|
| isTLS ? enc_pms.len + 2 : enc_pms.len);
|
| if (rv != SECSuccess) {
|
| @@ -6105,6 +6272,15 @@ sendRSAClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
|
| goto loser; /* err set by ssl3_AppendHandshake* */
|
| }
|
|
|
| + rv = ssl3_InitPendingCipherSpec(ss, pms);
|
| + PK11_FreeSymKey(pms);
|
| + pms = NULL;
|
| +
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
|
| + goto loser;
|
| + }
|
| +
|
| rv = SECSuccess;
|
|
|
| loser:
|
| @@ -6174,14 +6350,6 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
|
| 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.dh.publicValue.len + 2);
|
| if (rv != SECSuccess) {
|
| @@ -6197,8 +6365,16 @@ sendDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
|
| goto loser; /* err set by ssl3_AppendHandshake* */
|
| }
|
|
|
| - rv = SECSuccess;
|
| + rv = ssl3_InitPendingCipherSpec(ss, pms);
|
| + PK11_FreeSymKey(pms);
|
| + pms = NULL;
|
|
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
|
| + goto loser;
|
| + }
|
| +
|
| + rv = SECSuccess;
|
|
|
| loser:
|
|
|
| @@ -6240,9 +6416,9 @@ ssl3_SendClientKeyExchange(sslSocket *ss)
|
| 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) {
|
| - int keyLen = SECKEY_PublicKeyStrength(serverKey); /* bytes */
|
| + unsigned int keyLen = SECKEY_PublicKeyStrengthInBits(serverKey);
|
|
|
| - if (keyLen * BPB > ss->ssl3.hs.kea_def->key_size_limit) {
|
| + if (keyLen > ss->ssl3.hs.kea_def->key_size_limit) {
|
| if (isTLS)
|
| (void)SSL3_SendAlert(ss, alert_fatal, export_restriction);
|
| else
|
| @@ -6297,7 +6473,7 @@ ssl3_SendCertificateVerify(sslSocket *ss)
|
| SSL3Hashes hashes;
|
| KeyType keyType;
|
| unsigned int len;
|
| - SSL3SignatureAndHashAlgorithm sigAndHash;
|
| + SSLSignatureAndHashAlg sigAndHash;
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| @@ -6362,11 +6538,11 @@ ssl3_SendCertificateVerify(sslSocket *ss)
|
| }
|
| if (isTLS12) {
|
| rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType,
|
| - &sigAndHash.sigAlg);
|
| + &sigAndHash.sigAlg);
|
| if (rv != SECSuccess) {
|
| goto done;
|
| }
|
| - sigAndHash.hashAlg = hashes.hashAlg;
|
| + sigAndHash.hashAlg = hashes.hashAlg;
|
|
|
| rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
|
| if (rv != SECSuccess) {
|
| @@ -6474,6 +6650,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| errCode = SSL_ERROR_UNSUPPORTED_VERSION;
|
| goto alert_loser;
|
| }
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
|
| isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
|
|
|
| rv = ssl3_InitHandshakeHashes(ss);
|
| @@ -6509,7 +6686,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
|
| if (temp == suite->cipher_suite) {
|
| SSLVersionRange vrange = {ss->version, ss->version};
|
| - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) {
|
| + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
|
| /* config_match already checks whether the cipher suite is
|
| * acceptable for the version, but the check is repeated here
|
| * in order to give a more precise error code. */
|
| @@ -6533,6 +6710,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| }
|
| ss->ssl3.hs.cipher_suite = (ssl3CipherSuite)temp;
|
| ss->ssl3.hs.suite_def = ssl_LookupCipherSuiteDef((ssl3CipherSuite)temp);
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
|
| PORT_Assert(ss->ssl3.hs.suite_def);
|
| if (!ss->ssl3.hs.suite_def) {
|
| PORT_SetError(errCode = SEC_ERROR_LIBRARY_FAILURE);
|
| @@ -6619,6 +6797,32 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
|
|
| SECItem wrappedMS; /* wrapped master secret. */
|
|
|
| + /* [draft-ietf-tls-session-hash-06; Section 5.3]
|
| + *
|
| + * o If the original session did not use the "extended_master_secret"
|
| + * extension but the new ServerHello contains the extension, the
|
| + * client MUST abort the handshake.
|
| + */
|
| + if (!sid->u.ssl3.keys.extendedMasterSecretUsed &&
|
| + ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
|
| + errCode = SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET;
|
| + goto alert_loser;
|
| + }
|
| +
|
| + /*
|
| + * o If the original session used an extended master secret but the new
|
| + * ServerHello does not contain the "extended_master_secret"
|
| + * extension, the client SHOULD abort the handshake.
|
| + *
|
| + * TODO(ekr@rtfm.com): Add option to refuse to resume when EMS is not
|
| + * used at all (bug 1176526).
|
| + */
|
| + if (sid->u.ssl3.keys.extendedMasterSecretUsed &&
|
| + !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
|
| + errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
|
| + goto alert_loser;
|
| + }
|
| +
|
| ss->sec.authAlgorithm = sid->authAlgorithm;
|
| ss->sec.authKeyBits = sid->authKeyBits;
|
| ss->sec.keaType = sid->keaType;
|
| @@ -6721,7 +6925,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| ssl3_CopyPeerCertsFromSID(ss, sid);
|
| }
|
|
|
| - /* NULL value for PMS signifies re-use of the old MS */
|
| + /* NULL value for PMS because we are reusing the old MS */
|
| rv = ssl3_InitPendingCipherSpec(ss, NULL);
|
| if (rv != SECSuccess) {
|
| goto alert_loser; /* err code was set */
|
| @@ -6750,6 +6954,9 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| sid->u.ssl3.sessionIDLength = sidBytes.len;
|
| PORT_Memcpy(sid->u.ssl3.sessionID, sidBytes.data, sidBytes.len);
|
|
|
| + sid->u.ssl3.keys.extendedMasterSecretUsed =
|
| + ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn);
|
| +
|
| /* Copy Signed Certificate Timestamps, if any. */
|
| if (ss->xtnData.signedCertTimestamps.data) {
|
| rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.signedCertTimestamps,
|
| @@ -6761,13 +6968,14 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| ss->ssl3.hs.isResuming = PR_FALSE;
|
| if (ss->ssl3.hs.kea_def->signKeyType != sign_null) {
|
| /* All current cipher suites other than those with sign_null (i.e.,
|
| - * DH_anon_* suites) require a certificate, so use that signal. */
|
| + * (EC)DH_anon_* suites) require a certificate, so use that signal. */
|
| ss->ssl3.hs.ws = wait_server_cert;
|
| - } else if (ss->ssl3.hs.kea_def->ephemeral) {
|
| - /* Only ephemeral cipher suites use ServerKeyExchange. */
|
| - ss->ssl3.hs.ws = wait_server_key;
|
| } else {
|
| - ss->ssl3.hs.ws = wait_cert_request;
|
| + /* All the remaining cipher suites must be (EC)DH_anon_* and so
|
| + * must be ephemeral. Note, if we ever add PSK this might
|
| + * change. */
|
| + PORT_Assert(ss->ssl3.hs.kea_def->ephemeral);
|
| + ss->ssl3.hs.ws = wait_server_key;
|
| }
|
|
|
| winner:
|
| @@ -6807,29 +7015,6 @@ loser:
|
| return SECFailure;
|
| }
|
|
|
| -/* ssl3_BigIntGreaterThanOne returns true iff |mpint|, taken as an unsigned,
|
| - * big-endian integer is > 1 */
|
| -static PRBool
|
| -ssl3_BigIntGreaterThanOne(const SECItem* mpint) {
|
| - unsigned char firstNonZeroByte = 0;
|
| - unsigned int i;
|
| -
|
| - for (i = 0; i < mpint->len; i++) {
|
| - if (mpint->data[i]) {
|
| - firstNonZeroByte = mpint->data[i];
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (firstNonZeroByte == 0)
|
| - return PR_FALSE;
|
| - if (firstNonZeroByte > 1)
|
| - return PR_TRUE;
|
| -
|
| - /* firstNonZeroByte == 1, therefore mpint > 1 iff the first non-zero byte
|
| - * is followed by another byte. */
|
| - return (i < mpint->len - 1);
|
| -}
|
|
|
| /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
|
| * ssl3 ServerKeyExchange message.
|
| @@ -6846,9 +7031,9 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| SSL3AlertDescription desc = illegal_parameter;
|
| SSL3Hashes hashes;
|
| SECItem signature = {siBuffer, NULL, 0};
|
| - SSL3SignatureAndHashAlgorithm sigAndHash;
|
| + SSLSignatureAndHashAlg sigAndHash;
|
|
|
| - sigAndHash.hashAlg = SEC_OID_UNKNOWN;
|
| + sigAndHash.hashAlg = ssl_hash_none;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -6874,6 +7059,12 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| }
|
| + /* This exchange method is only used by export cipher suites.
|
| + * Those are broken and so this code will eventually be removed. */
|
| + if (SECKEY_BigIntegerBitLength(&modulus) < 512) {
|
| + desc = isTLS ? insufficient_security : illegal_parameter;
|
| + goto alert_loser;
|
| + }
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| @@ -6884,7 +7075,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed or unsupported. */
|
| }
|
| - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(ss,
|
| &sigAndHash, ss->sec.peerCert);
|
| if (rv != SECSuccess) {
|
| goto loser;
|
| @@ -6907,10 +7098,10 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| /*
|
| * check to make sure the hash is signed by right guy
|
| */
|
| - rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent,
|
| - &ss->ssl3.hs.client_random,
|
| - &ss->ssl3.hs.server_random,
|
| - &hashes, ss->opt.bypassPKCS11);
|
| + rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent,
|
| + &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);
|
| @@ -6936,7 +7127,6 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
|
|
| peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
|
| if (peerKey == NULL) {
|
| - PORT_FreeArena(arena, PR_FALSE);
|
| goto no_memory;
|
| }
|
|
|
| @@ -6947,7 +7137,6 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| if (SECITEM_CopyItem(arena, &peerKey->u.rsa.modulus, &modulus) ||
|
| SECITEM_CopyItem(arena, &peerKey->u.rsa.publicExponent, &exponent))
|
| {
|
| - PORT_FreeArena(arena, PR_FALSE);
|
| goto no_memory;
|
| }
|
| ss->sec.peerKey = peerKey;
|
| @@ -6959,13 +7148,22 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| SECItem dh_p = {siBuffer, NULL, 0};
|
| SECItem dh_g = {siBuffer, NULL, 0};
|
| SECItem dh_Ys = {siBuffer, NULL, 0};
|
| + unsigned dh_p_bits;
|
| + unsigned dh_g_bits;
|
| + unsigned dh_Ys_bits;
|
| + PRInt32 minDH;
|
|
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| }
|
| - if (dh_p.len < 1024/8 ||
|
| - (dh_p.len == 1024/8 && (dh_p.data[0] & 0x80) == 0)) {
|
| +
|
| + rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH);
|
| + if (rv != SECSuccess) {
|
| + minDH = SSL_DH_MIN_P_BITS;
|
| + }
|
| + dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p);
|
| + if (dh_p_bits < minDH) {
|
| errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
|
| goto alert_loser;
|
| }
|
| @@ -6973,13 +7171,16 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| }
|
| - if (dh_g.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_g))
|
| + /* Abort if dh_g is 0, 1, or obviously too big. */
|
| + dh_g_bits = SECKEY_BigIntegerBitLength(&dh_g);
|
| + if (dh_g_bits > dh_p_bits || dh_g_bits <= 1)
|
| goto alert_loser;
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &dh_Ys, 2, &b, &length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| }
|
| - if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys))
|
| + dh_Ys_bits = SECKEY_BigIntegerBitLength(&dh_Ys);
|
| + if (dh_Ys_bits > dh_p_bits || dh_Ys_bits <= 1)
|
| goto alert_loser;
|
| if (isTLS12) {
|
| rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
|
| @@ -6987,7 +7188,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed or unsupported. */
|
| }
|
| - rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(ss,
|
| &sigAndHash, ss->sec.peerCert);
|
| if (rv != SECSuccess) {
|
| goto loser;
|
| @@ -7014,10 +7215,10 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| /*
|
| * check to make sure the hash is signed by right guy
|
| */
|
| - rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys,
|
| - &ss->ssl3.hs.client_random,
|
| - &ss->ssl3.hs.server_random,
|
| - &hashes, ss->opt.bypassPKCS11);
|
| + rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg, dh_p, dh_g, dh_Ys,
|
| + &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);
|
| @@ -7041,7 +7242,7 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| goto no_memory;
|
| }
|
|
|
| - ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
|
| + peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
|
| if (peerKey == NULL) {
|
| goto no_memory;
|
| }
|
| @@ -7055,7 +7256,6 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| SECITEM_CopyItem(arena, &peerKey->u.dh.base, &dh_g) ||
|
| SECITEM_CopyItem(arena, &peerKey->u.dh.publicValue, &dh_Ys))
|
| {
|
| - PORT_FreeArena(arena, PR_FALSE);
|
| goto no_memory;
|
| }
|
| ss->sec.peerKey = peerKey;
|
| @@ -7078,10 +7278,16 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| alert_loser:
|
| (void)SSL3_SendAlert(ss, alert_fatal, desc);
|
| loser:
|
| + if (arena) {
|
| + PORT_FreeArena(arena, PR_FALSE);
|
| + }
|
| PORT_SetError( errCode );
|
| return SECFailure;
|
|
|
| no_memory: /* no-memory error has already been set. */
|
| + if (arena) {
|
| + PORT_FreeArena(arena, PR_FALSE);
|
| + }
|
| ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| return SECFailure;
|
| }
|
| @@ -7092,7 +7298,7 @@ no_memory: /* no-memory error has already been set. */
|
| */
|
| static SECStatus
|
| ssl3_ExtractClientKeyInfo(sslSocket *ss,
|
| - TLSSignatureAlgorithm *sigAlg,
|
| + SSLSignType *sigAlg,
|
| PRBool *preferSha1)
|
| {
|
| SECStatus rv = SECSuccess;
|
| @@ -7148,7 +7354,7 @@ ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss,
|
| const SECItem *algorithms)
|
| {
|
| SECStatus rv;
|
| - TLSSignatureAlgorithm sigAlg;
|
| + SSLSignType sigAlg;
|
| PRBool preferSha1;
|
| PRBool supportsSha1 = PR_FALSE;
|
| PRBool supportsSha256 = PR_FALSE;
|
| @@ -7173,9 +7379,9 @@ ssl3_DestroyBackupHandshakeHashIfNotNeeded(sslSocket *ss,
|
| /* Determine the server's hash support for that signature algorithm. */
|
| for (i = 0; i < algorithms->len; i += 2) {
|
| if (algorithms->data[i+1] == sigAlg) {
|
| - if (algorithms->data[i] == tls_hash_sha1) {
|
| + if (algorithms->data[i] == ssl_hash_sha1) {
|
| supportsSha1 = PR_TRUE;
|
| - } else if (algorithms->data[i] == tls_hash_sha256) {
|
| + } else if (algorithms->data[i] == ssl_hash_sha256) {
|
| supportsSha256 = PR_TRUE;
|
| }
|
| }
|
| @@ -7334,6 +7540,8 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| } else
|
| #endif
|
| if (ss->getClientAuthData != NULL) {
|
| + PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
|
| + ssl_preinfo_all);
|
| /* XXX Should pass cert_types and algorithms in this call!! */
|
| rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
|
| ss->fd, &ca_list,
|
| @@ -7565,6 +7773,8 @@ ssl3_CheckFalseStart(sslSocket *ss)
|
| SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher",
|
| SSL_GETPID(), ss->fd));
|
| } else {
|
| + PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
|
| + ssl_preinfo_all);
|
| rv = (ss->canFalseStartCallback)(ss->fd,
|
| ss->canFalseStartCallbackData,
|
| &ss->ssl3.hs.canFalseStart);
|
| @@ -7923,6 +8133,7 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
|
| sid->u.ssl3.policy = SSL_ALLOWED;
|
| sid->u.ssl3.clientWriteKey = NULL;
|
| sid->u.ssl3.serverWriteKey = NULL;
|
| + sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
|
|
|
| if (is_server) {
|
| SECStatus rv;
|
| @@ -7975,7 +8186,7 @@ ssl3_SendServerHelloSequence(sslSocket *ss)
|
|
|
| if (kea_def->is_limited && kea_def->exchKeyType == kt_rsa) {
|
| /* see if we can legally use the key in the cert. */
|
| - int keyLen; /* bytes */
|
| + unsigned int keyLen; /* bytes */
|
|
|
| keyLen = PK11_GetPrivateModulusLen(
|
| ss->serverCerts[kea_def->exchKeyType].SERVERKEY);
|
| @@ -8022,6 +8233,22 @@ ssl3_SendServerHelloSequence(sslSocket *ss)
|
| /* An empty TLS Renegotiation Info (RI) extension */
|
| static const PRUint8 emptyRIext[5] = {0xff, 0x01, 0x00, 0x01, 0x00};
|
|
|
| +static PRBool
|
| +ssl3_KEAAllowsSessionTicket(SSL3KeyExchangeAlgorithm kea)
|
| +{
|
| + switch (kea) {
|
| + case kea_dhe_dss:
|
| + case kea_dhe_dss_export:
|
| + case kea_dh_dss_export:
|
| + case kea_dh_dss:
|
| + /* TODO: Fix session tickets for DSS. The server code rejects the
|
| + * session ticket received from the client. Bug 1174677 */
|
| + return PR_FALSE;
|
| + default:
|
| + return PR_TRUE;
|
| + };
|
| +}
|
| +
|
| /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
|
| * ssl3 Client Hello message.
|
| * Caller must hold Handshake and RecvBuf locks.
|
| @@ -8044,6 +8271,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| SECItem comps = {siBuffer, NULL, 0};
|
| PRBool haveSpecWriteLock = PR_FALSE;
|
| PRBool haveXmitBufLock = PR_FALSE;
|
| + PRBool canOfferSessionTicket = PR_FALSE;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle client_hello handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -8051,6 +8279,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| PORT_Assert( ss->ssl3.initialized );
|
| + ss->ssl3.hs.preliminaryInfo = 0;
|
|
|
| if (!ss->sec.isServer ||
|
| (ss->ssl3.hs.ws != wait_client_hello &&
|
| @@ -8116,6 +8345,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| errCode = SSL_ERROR_UNSUPPORTED_VERSION;
|
| goto alert_loser;
|
| }
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
|
|
|
| rv = ssl3_InitHandshakeHashes(ss);
|
| if (rv != SECSuccess) {
|
| @@ -8283,8 +8513,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| * resuming.)
|
| */
|
| if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) && sid == NULL) {
|
| - ssl3_RegisterServerHelloExtensionSender(ss,
|
| - ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn);
|
| + canOfferSessionTicket = PR_TRUE;
|
| }
|
|
|
| if (sid != NULL) {
|
| @@ -8367,7 +8596,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| * 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, &vrange))
|
| + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss))
|
| break;
|
| #else
|
| if (!suite->enabled)
|
| @@ -8380,6 +8609,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| ss->ssl3.hs.cipher_suite = suite->cipher_suite;
|
| ss->ssl3.hs.suite_def =
|
| ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
|
|
|
| /* Use the cached compression method. */
|
| ss->ssl3.hs.compression = sid->u.ssl3.compression;
|
| @@ -8416,7 +8646,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
|
| ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
|
| SSLVersionRange vrange = {ss->version, ss->version};
|
| - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) {
|
| + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
|
| continue;
|
| }
|
| for (i = 0; i + 1 < suites.len; i += 2) {
|
| @@ -8425,6 +8655,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| ss->ssl3.hs.cipher_suite = suite->cipher_suite;
|
| ss->ssl3.hs.suite_def =
|
| ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
|
| goto suite_found;
|
| }
|
| }
|
| @@ -8433,6 +8664,15 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| goto alert_loser;
|
|
|
| suite_found:
|
| + if (canOfferSessionTicket)
|
| + canOfferSessionTicket = ssl3_KEAAllowsSessionTicket(
|
| + ss->ssl3.hs.suite_def->key_exchange_alg);
|
| +
|
| + if (canOfferSessionTicket) {
|
| + ssl3_RegisterServerHelloExtensionSender(ss,
|
| + ssl_session_ticket_xtn, ssl3_SendSessionTicketXtn);
|
| + }
|
| +
|
| /* Select a compression algorithm. */
|
| for (i = 0; i < comps.len; i++) {
|
| if (!compressionEnabled(ss, comps.data[i]))
|
| @@ -8458,6 +8698,8 @@ compression_found:
|
| /* If there are any failures while processing the old sid,
|
| * we don't consider them to be errors. Instead, We just behave
|
| * as if the client had sent us no sid to begin with, and make a new one.
|
| + * The exception here is attempts to resume extended_master_secret
|
| + * sessions without the extension, which causes an alert.
|
| */
|
| if (sid != NULL) do {
|
| ssl3CipherSpec *pwSpec;
|
| @@ -8469,6 +8711,30 @@ compression_found:
|
| break; /* not an error */
|
| }
|
|
|
| + /* [draft-ietf-tls-session-hash-06; Section 5.3]
|
| + * o If the original session did not use the "extended_master_secret"
|
| + * extension but the new ClientHello contains the extension, then the
|
| + * server MUST NOT perform the abbreviated handshake. Instead, it
|
| + * SHOULD continue with a full handshake (as described in
|
| + * Section 5.2) to negotiate a new session.
|
| + *
|
| + * o If the original session used the "extended_master_secret"
|
| + * extension but the new ClientHello does not contain the extension,
|
| + * the server MUST abort the abbreviated handshake.
|
| + */
|
| + if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
|
| + if (!sid->u.ssl3.keys.extendedMasterSecretUsed) {
|
| + break; /* not an error */
|
| + }
|
| + } else {
|
| + if (sid->u.ssl3.keys.extendedMasterSecretUsed) {
|
| + /* Note: we do not destroy the session */
|
| + desc = handshake_failure;
|
| + errCode = SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET;
|
| + goto alert_loser;
|
| + }
|
| + }
|
| +
|
| if (ss->sec.ci.sid) {
|
| if (ss->sec.uncache)
|
| ss->sec.uncache(ss->sec.ci.sid);
|
| @@ -8610,7 +8876,7 @@ compression_found:
|
| haveSpecWriteLock = PR_FALSE;
|
| }
|
|
|
| - /* NULL value for PMS signifies re-use of the old MS */
|
| + /* NULL value for PMS because we are re-using the old MS */
|
| rv = ssl3_InitPendingCipherSpec(ss, NULL);
|
| if (rv != SECSuccess) {
|
| errCode = PORT_GetError();
|
| @@ -8654,6 +8920,9 @@ compression_found:
|
| if (ssl3_ExtensionNegotiated(ss, ssl_server_name_xtn)) {
|
| int ret = 0;
|
| if (ss->sniSocketConfig) do { /* not a loop */
|
| + PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
|
| + ssl_preinfo_all);
|
| +
|
| ret = SSL_SNI_SEND_ALERT;
|
| /* If extension is negotiated, the len of names should > 0. */
|
| if (ss->xtnData.sniNameArrSize) {
|
| @@ -8701,7 +8970,7 @@ compression_found:
|
| ret = SSL_SNI_SEND_ALERT;
|
| break;
|
| }
|
| - } else if (ret < ss->xtnData.sniNameArrSize) {
|
| + } else if ((unsigned int)ret < ss->xtnData.sniNameArrSize) {
|
| /* Application has configured new socket info. Lets check it
|
| * and save the name. */
|
| SECStatus rv;
|
| @@ -8752,7 +9021,7 @@ compression_found:
|
| ssl3_SendServerNameXtn);
|
| } else {
|
| /* Callback returned index outside of the boundary. */
|
| - PORT_Assert(ret < ss->xtnData.sniNameArrSize);
|
| + PORT_Assert((unsigned int)ret < ss->xtnData.sniNameArrSize);
|
| errCode = SSL_ERROR_INTERNAL_ERROR_ALERT;
|
| desc = internal_error;
|
| ret = SSL_SNI_SEND_ALERT;
|
| @@ -8798,13 +9067,16 @@ compression_found:
|
| }
|
| ss->sec.ci.sid = sid;
|
|
|
| + sid->u.ssl3.keys.extendedMasterSecretUsed =
|
| + ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn);
|
| ss->ssl3.hs.isResuming = PR_FALSE;
|
| ssl_GetXmitBufLock(ss);
|
| rv = ssl3_SendServerHelloSequence(ss);
|
| ssl_ReleaseXmitBufLock(ss);
|
| if (rv != SECSuccess) {
|
| - errCode = PORT_GetError();
|
| - goto loser;
|
| + errCode = PORT_GetError();
|
| + desc = handshake_failure;
|
| + goto alert_loser;
|
| }
|
|
|
| if (haveXmitBufLock) {
|
| @@ -8896,6 +9168,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length)
|
| errCode = SSL_ERROR_UNSUPPORTED_VERSION;
|
| goto alert_loser;
|
| }
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_version;
|
|
|
| rv = ssl3_InitHandshakeHashes(ss);
|
| if (rv != SECSuccess) {
|
| @@ -8951,7 +9224,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length)
|
| for (j = 0; j < ssl_V3_SUITES_IMPLEMENTED; j++) {
|
| ssl3CipherSuiteCfg *suite = &ss->cipherSuites[j];
|
| SSLVersionRange vrange = {ss->version, ss->version};
|
| - if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange)) {
|
| + if (!config_match(suite, ss->ssl3.policy, PR_TRUE, &vrange, ss)) {
|
| continue;
|
| }
|
| for (i = 0; i+2 < suite_length; i += 3) {
|
| @@ -8960,6 +9233,7 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length)
|
| ss->ssl3.hs.cipher_suite = suite->cipher_suite;
|
| ss->ssl3.hs.suite_def =
|
| ssl_LookupCipherSuiteDef(ss->ssl3.hs.cipher_suite);
|
| + ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_cipher_suite;
|
| goto suite_found;
|
| }
|
| }
|
| @@ -9150,6 +9424,154 @@ ssl3_SendServerHello(sslSocket *ss)
|
| return SECSuccess;
|
| }
|
|
|
| +static SECStatus
|
| +ssl3_PickSignatureHashAlgorithm(sslSocket *ss,
|
| + SSLSignatureAndHashAlg* out);
|
| +
|
| +static SECStatus
|
| +ssl3_SendDHServerKeyExchange(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;
|
| + SSLSignatureAndHashAlg sigAndHash;
|
| + SECKEYDHParams dhParam;
|
| +
|
| + ssl3KeyPair *keyPair = NULL;
|
| + SECKEYPublicKey *pubKey = NULL; /* Ephemeral DH key */
|
| + SECKEYPrivateKey *privKey = NULL; /* Ephemeral DH key */
|
| + int certIndex = -1;
|
| +
|
| + if (kea_def->kea != kea_dhe_dss && kea_def->kea != kea_dhe_rsa) {
|
| + /* TODO: Support DH_anon. It might be sufficient to drop the signature.
|
| + See bug 1170510. */
|
| + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + dhParam.prime.data = ss->dheParams->prime.data;
|
| + dhParam.prime.len = ss->dheParams->prime.len;
|
| + dhParam.base.data = ss->dheParams->base.data;
|
| + dhParam.base.len = ss->dheParams->base.len;
|
| +
|
| + PRINT_BUF(60, (NULL, "Server DH p", dhParam.prime.data,
|
| + dhParam.prime.len));
|
| + PRINT_BUF(60, (NULL, "Server DH g", dhParam.base.data,
|
| + dhParam.base.len));
|
| +
|
| + /* Generate ephemeral DH keypair */
|
| + privKey = SECKEY_CreateDHPrivateKey(&dhParam, &pubKey, NULL);
|
| + if (!privKey || !pubKey) {
|
| + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
| + rv = SECFailure;
|
| + goto loser;
|
| + }
|
| +
|
| + keyPair = ssl3_NewKeyPair(privKey, pubKey);
|
| + if (!keyPair) {
|
| + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
| + goto loser;
|
| + }
|
| +
|
| + PRINT_BUF(50, (ss, "DH public value:",
|
| + pubKey->u.dh.publicValue.data,
|
| + pubKey->u.dh.publicValue.len));
|
| +
|
| + if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) {
|
| + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
|
| + goto loser;
|
| + }
|
| +
|
| + rv = ssl3_ComputeDHKeyHash(sigAndHash.hashAlg,
|
| + pubKey->u.dh.prime,
|
| + pubKey->u.dh.base,
|
| + pubKey->u.dh.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;
|
| + }
|
| +
|
| + /* It has been suggested to test kea_def->signKeyType instead, and to use
|
| + * ssl_auth_* instead. Investigate what to do. See bug 102794. */
|
| + if (kea_def->kea == kea_dhe_rsa)
|
| + certIndex = ssl_kea_rsa;
|
| + else
|
| + certIndex = ssl_kea_dh;
|
| +
|
| + isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
|
| + 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) {
|
| + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| + goto loser;
|
| + }
|
| + length = 2 + pubKey->u.dh.prime.len +
|
| + 2 + pubKey->u.dh.base.len +
|
| + 2 + pubKey->u.dh.publicValue.len +
|
| + 2 + signed_hash.len;
|
| +
|
| + if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + length += 2;
|
| + }
|
| +
|
| + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* err set by AppendHandshake. */
|
| + }
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.prime.data,
|
| + pubKey->u.dh.prime.len, 2);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* err set by AppendHandshake. */
|
| + }
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.base.data,
|
| + pubKey->u.dh.base.len, 2);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* err set by AppendHandshake. */
|
| + }
|
| +
|
| + rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.dh.publicValue.data,
|
| + pubKey->u.dh.publicValue.len, 2);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* err set by AppendHandshake. */
|
| + }
|
| +
|
| + if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
|
| + 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(signed_hash.data);
|
| + ss->dheKeyPair = keyPair;
|
| + return SECSuccess;
|
| +
|
| +loser:
|
| + if (signed_hash.data)
|
| + PORT_Free(signed_hash.data);
|
| + if (privKey)
|
| + SECKEY_DestroyPrivateKey(privKey);
|
| + if (pubKey)
|
| + SECKEY_DestroyPublicKey(pubKey);
|
| + return SECFailure;
|
| +}
|
| +
|
| /* ssl3_PickSignatureHashAlgorithm selects a hash algorithm to use when signing
|
| * elements of the handshake. (The negotiated cipher suite determines the
|
| * signature algorithm.) Prior to TLS 1.2, the MD5/SHA1 combination is always
|
| @@ -9157,18 +9579,11 @@ ssl3_SendServerHello(sslSocket *ss)
|
| * hash combinations. */
|
| static SECStatus
|
| ssl3_PickSignatureHashAlgorithm(sslSocket *ss,
|
| - SSL3SignatureAndHashAlgorithm* out)
|
| + SSLSignatureAndHashAlg* out)
|
| {
|
| - TLSSignatureAlgorithm sigAlg;
|
| + SSLSignType sigAlg;
|
| + PRUint32 policy;
|
| unsigned int i, j;
|
| - /* hashPreference expresses our preferences for hash algorithms, most
|
| - * preferable first. */
|
| - static const SECOidTag hashPreference[] = {
|
| - SEC_OID_SHA256,
|
| - SEC_OID_SHA384,
|
| - SEC_OID_SHA512,
|
| - SEC_OID_SHA1,
|
| - };
|
|
|
| switch (ss->ssl3.hs.kea_def->kea) {
|
| case kea_rsa:
|
| @@ -9181,48 +9596,63 @@ ssl3_PickSignatureHashAlgorithm(sslSocket *ss,
|
| case kea_rsa_fips:
|
| case kea_ecdh_rsa:
|
| case kea_ecdhe_rsa:
|
| - sigAlg = tls_sig_rsa;
|
| - break;
|
| + sigAlg = ssl_sign_rsa;
|
| + break;
|
| case kea_dh_dss:
|
| case kea_dh_dss_export:
|
| case kea_dhe_dss:
|
| case kea_dhe_dss_export:
|
| - sigAlg = tls_sig_dsa;
|
| - break;
|
| + sigAlg = ssl_sign_dsa;
|
| + break;
|
| case kea_ecdh_ecdsa:
|
| case kea_ecdhe_ecdsa:
|
| - sigAlg = tls_sig_ecdsa;
|
| - break;
|
| + sigAlg = ssl_sign_ecdsa;
|
| + break;
|
| default:
|
| - PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
| - return SECFailure;
|
| + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
| + return SECFailure;
|
| }
|
| out->sigAlg = sigAlg;
|
|
|
| if (ss->version <= SSL_LIBRARY_VERSION_TLS_1_1) {
|
| - /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and
|
| - * prior. */
|
| - out->hashAlg = SEC_OID_UNKNOWN;
|
| - return SECSuccess;
|
| + /* SEC_OID_UNKNOWN means the MD5/SHA1 combo hash used in TLS 1.1 and
|
| + * prior. */
|
| + out->hashAlg = ssl_hash_none;
|
| + return SECSuccess;
|
| }
|
|
|
| if (ss->ssl3.hs.numClientSigAndHash == 0) {
|
| - /* If the client didn't provide any signature_algorithms extension then
|
| - * we can assume that they support SHA-1:
|
| - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| - out->hashAlg = SEC_OID_SHA1;
|
| - return SECSuccess;
|
| + /* If the client didn't provide any signature_algorithms extension then
|
| + * we can assume that they support SHA-1:
|
| + * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| + out->hashAlg = ssl_hash_sha1;
|
| + return SECSuccess;
|
| }
|
|
|
| - for (i = 0; i < PR_ARRAY_SIZE(hashPreference); i++) {
|
| - for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) {
|
| - const SSL3SignatureAndHashAlgorithm* sh =
|
| - &ss->ssl3.hs.clientSigAndHash[j];
|
| - if (sh->sigAlg == sigAlg && sh->hashAlg == hashPreference[i]) {
|
| - out->hashAlg = sh->hashAlg;
|
| - return SECSuccess;
|
| - }
|
| + /* Here we look for the first server preference that the client has
|
| + * indicated support for in their signature_algorithms extension. */
|
| + for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
|
| + const SSLSignatureAndHashAlg *serverPref =
|
| + &ss->ssl3.signatureAlgorithms[i];
|
| + SECOidTag hashOID;
|
| + if (serverPref->sigAlg != sigAlg) {
|
| + continue;
|
| + }
|
| + hashOID = ssl3_TLSHashAlgorithmToOID(serverPref->hashAlg);
|
| + if ((NSS_GetAlgorithmPolicy(hashOID, &policy) != SECSuccess)
|
| + || !(policy & NSS_USE_ALG_IN_SSL_KX)) {
|
| + /* we ignore hashes we don't support */
|
| + continue;
|
| }
|
| + for (j = 0; j < ss->ssl3.hs.numClientSigAndHash; j++) {
|
| + const SSLSignatureAndHashAlg *clientPref =
|
| + &ss->ssl3.hs.clientSigAndHash[j];
|
| + if (clientPref->hashAlg == serverPref->hashAlg &&
|
| + clientPref->sigAlg == sigAlg) {
|
| + out->hashAlg = serverPref->hashAlg;
|
| + return SECSuccess;
|
| + }
|
| + }
|
| }
|
|
|
| PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
|
| @@ -9240,7 +9670,7 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
|
| SECItem signed_hash = {siBuffer, NULL, 0};
|
| SSL3Hashes hashes;
|
| SECKEYPublicKey * sdPub; /* public key for step-down */
|
| - SSL3SignatureAndHashAlgorithm sigAndHash;
|
| + SSLSignatureAndHashAlg sigAndHash;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -9287,6 +9717,10 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
|
| 2 + sdPub->u.rsa.publicExponent.len +
|
| 2 + signed_hash.len;
|
|
|
| + if (ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + length += 2;
|
| + }
|
| +
|
| rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* err set by AppendHandshake. */
|
| @@ -9320,6 +9754,11 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
|
| PORT_Free(signed_hash.data);
|
| return SECSuccess;
|
|
|
| + case ssl_kea_dh: {
|
| + rv = ssl3_SendDHServerKeyExchange(ss);
|
| + return rv;
|
| + }
|
| +
|
| #ifndef NSS_DISABLE_ECC
|
| case kt_ecdh: {
|
| rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash);
|
| @@ -9327,7 +9766,6 @@ ssl3_SendServerKeyExchange(sslSocket *ss)
|
| }
|
| #endif /* NSS_DISABLE_ECC */
|
|
|
| - case kt_dh:
|
| case kt_null:
|
| default:
|
| PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
|
| @@ -9339,6 +9777,36 @@ loser:
|
| return SECFailure;
|
| }
|
|
|
| +static SECStatus
|
| +ssl3_EncodeCertificateRequestSigAlgs(sslSocket *ss, PRUint8 *buf,
|
| + unsigned maxLen, PRUint32 *len)
|
| +{
|
| + unsigned int i;
|
| +
|
| + PORT_Assert(maxLen >= ss->ssl3.signatureAlgorithmCount * 2);
|
| + if (maxLen < ss->ssl3.signatureAlgorithmCount * 2) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + *len = 0;
|
| + for (i = 0; i < ss->ssl3.signatureAlgorithmCount; ++i) {
|
| + const SSLSignatureAndHashAlg *alg = &ss->ssl3.signatureAlgorithms[i];
|
| + /* Note that we don't support a handshake hash with anything other than
|
| + * SHA-256, so asking for a signature from clients for something else
|
| + * would be inviting disaster. */
|
| + if (alg->hashAlg == ssl_hash_sha256) {
|
| + buf[(*len)++] = (PRUint8)alg->hashAlg;
|
| + buf[(*len)++] = (PRUint8)alg->sigAlg;
|
| + }
|
| + }
|
| +
|
| + if (*len == 0) {
|
| + PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
|
|
| static SECStatus
|
| ssl3_SendCertificateRequest(sslSocket *ss)
|
| @@ -9347,7 +9815,6 @@ ssl3_SendCertificateRequest(sslSocket *ss)
|
| SECItem * name;
|
| CERTDistNames *ca_list;
|
| const PRUint8 *certTypes;
|
| - const PRUint8 *sigAlgs;
|
| SECItem * names = NULL;
|
| SECStatus rv;
|
| int length;
|
| @@ -9355,7 +9822,8 @@ ssl3_SendCertificateRequest(sslSocket *ss)
|
| int calen = 0;
|
| int nnames = 0;
|
| int certTypesLength;
|
| - int sigAlgsLength;
|
| + PRUint8 sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2];
|
| + unsigned int sigAlgsLength = 0;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: send certificate_request handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -9382,12 +9850,15 @@ ssl3_SendCertificateRequest(sslSocket *ss)
|
|
|
| certTypes = certificate_types;
|
| certTypesLength = sizeof certificate_types;
|
| - sigAlgs = supported_signature_algorithms;
|
| - sigAlgsLength = sizeof supported_signature_algorithms;
|
|
|
| length = 1 + certTypesLength + 2 + calen;
|
| if (isTLS12) {
|
| - length += 2 + sigAlgsLength;
|
| + rv = ssl3_EncodeCertificateRequestSigAlgs(ss, sigAlgs, sizeof(sigAlgs),
|
| + &sigAlgsLength);
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| + }
|
| + length += 2 + sigAlgsLength;
|
| }
|
|
|
| rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
|
| @@ -9453,7 +9924,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
| int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
|
| SSL3AlertDescription desc = handshake_failure;
|
| PRBool isTLS, isTLS12;
|
| - SSL3SignatureAndHashAlgorithm sigAndHash;
|
| + SSLSignatureAndHashAlg sigAndHash;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -9469,6 +9940,13 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
| goto alert_loser;
|
| }
|
|
|
| + if (!hashes) {
|
| + PORT_Assert(0);
|
| + desc = internal_error;
|
| + errCode = SEC_ERROR_LIBRARY_FAILURE;
|
| + goto alert_loser;
|
| + }
|
| +
|
| if (isTLS12) {
|
| rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
|
| &sigAndHash);
|
| @@ -9476,7 +9954,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
| goto loser; /* malformed or unsupported. */
|
| }
|
| rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| - &sigAndHash, ss->sec.peerCert);
|
| + ss, &sigAndHash, ss->sec.peerCert);
|
| if (rv != SECSuccess) {
|
| errCode = PORT_GetError();
|
| desc = decrypt_error;
|
| @@ -9485,7 +9963,7 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
|
|
| /* We only support CertificateVerify messages that use the handshake
|
| * hash. */
|
| - if (sigAndHash.hashAlg != hashes->hashAlg) {
|
| + if (sigAndHash.hashAlg != hashes->hashAlg) {
|
| errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM;
|
| desc = decrypt_error;
|
| goto alert_loser;
|
| @@ -9616,18 +10094,17 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
|
| PRUint32 length,
|
| SECKEYPrivateKey *serverKey)
|
| {
|
| - PK11SymKey * pms;
|
| #ifndef NO_PKCS11_BYPASS
|
| 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;
|
| -#endif
|
| PRBool isTLS = PR_FALSE;
|
| + SECItem pmsItem = {siBuffer, NULL, 0};
|
| + unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
|
| +#endif
|
| SECStatus rv;
|
| SECItem enc_pms;
|
| - unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
|
| - SECItem pmsItem = {siBuffer, NULL, 0};
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| @@ -9635,8 +10112,10 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
|
|
|
| enc_pms.data = b;
|
| enc_pms.len = length;
|
| +#ifndef NO_PKCS11_BYPASS
|
| pmsItem.data = rsaPmsBuf;
|
| pmsItem.len = sizeof rsaPmsBuf;
|
| +#endif
|
|
|
| if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */
|
| PRInt32 kLen;
|
| @@ -9648,13 +10127,24 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
|
| if ((unsigned)kLen < enc_pms.len) {
|
| enc_pms.len = kLen;
|
| }
|
| +#ifndef NO_PKCS11_BYPASS
|
| isTLS = PR_TRUE;
|
| +#endif
|
| } else {
|
| +#ifndef NO_PKCS11_BYPASS
|
| isTLS = (PRBool)(ss->ssl3.hs.kea_def->tls_keygen != 0);
|
| +#endif
|
| }
|
|
|
| #ifndef NO_PKCS11_BYPASS
|
| if (ss->opt.bypassPKCS11) {
|
| + /* We have not implemented a tls_ExtendedMasterKeyDeriveBypass
|
| + * and will not negotiate this extension in bypass mode. This
|
| + * assert just double-checks that.
|
| + */
|
| + PORT_Assert(
|
| + !ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn));
|
| +
|
| /* 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
|
| @@ -9682,8 +10172,8 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
|
| }
|
| }
|
| /* have PMS, build MS without PKCS11 */
|
| - rv = ssl3_MasterKeyDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
|
| - PR_TRUE);
|
| + rv = ssl3_MasterSecretDeriveBypass(pwSpec, cr, sr, &pmsItem, isTLS,
|
| + PR_TRUE);
|
| if (rv != SECSuccess) {
|
| pwSpec->msItem.data = pwSpec->raw_master_secret;
|
| pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
|
| @@ -9693,49 +10183,163 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss,
|
| } else
|
| #endif
|
| {
|
| + PK11SymKey *tmpPms[2] = {NULL, NULL};
|
| + PK11SlotInfo *slot;
|
| + int useFauxPms = 0;
|
| +#define currentPms tmpPms[!useFauxPms]
|
| +#define unusedPms tmpPms[useFauxPms]
|
| +#define realPms tmpPms[1]
|
| +#define fauxPms tmpPms[0]
|
| +
|
| #ifndef NO_PKCS11_BYPASS
|
| double_bypass:
|
| #endif
|
| - /*
|
| - * 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);
|
|
|
| - ssl_GetSpecWriteLock(ss);
|
| - pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
|
| - ssl_ReleaseSpecWriteLock(ss);
|
| - PK11_FreeSlot(slot);
|
| - }
|
| + /*
|
| + * Get as close to algorithm 2 from RFC 5246; Section 7.4.7.1
|
| + * as we can within the constraints of the PKCS#11 interface.
|
| + *
|
| + * 1. Unconditionally generate a bogus PMS (what RFC 5246
|
| + * calls R).
|
| + * 2. Attempt the RSA decryption to recover the PMS (what
|
| + * RFC 5246 calls M).
|
| + * 3. Set PMS = (M == NULL) ? R : M
|
| + * 4. Use ssl3_ComputeMasterSecret(PMS) to attempt to derive
|
| + * the MS from PMS. This includes performing the version
|
| + * check and length check.
|
| + * 5. If either the initial RSA decryption failed or
|
| + * ssl3_ComputeMasterSecret(PMS) failed, then discard
|
| + * M and set PMS = R. Else, discard R and set PMS = M.
|
| + *
|
| + * We do two derivations here because we can't rely on having
|
| + * a function that only performs the PMS version and length
|
| + * check. The only redundant cost is that this runs the PRF,
|
| + * which isn't necessary here.
|
| + */
|
| +
|
| + /* Generate the bogus PMS (R) */
|
| + slot = PK11_GetSlotFromPrivateKey(serverKey);
|
| + if (!slot) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + if (!PK11_DoesMechanism(slot, CKM_SSL3_MASTER_KEY_DERIVE)) {
|
| + PK11_FreeSlot(slot);
|
| + slot = PK11_GetBestSlot(CKM_SSL3_MASTER_KEY_DERIVE, NULL);
|
| + if (!slot) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| + }
|
|
|
| - if (pms == NULL) {
|
| - /* last gasp. */
|
| + ssl_GetSpecWriteLock(ss);
|
| + fauxPms = ssl3_GenerateRSAPMS(ss, ss->ssl3.prSpec, slot);
|
| + ssl_ReleaseSpecWriteLock(ss);
|
| + PK11_FreeSlot(slot);
|
| +
|
| + if (fauxPms == NULL) {
|
| ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
|
| return SECFailure;
|
| }
|
|
|
| + /*
|
| + * 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.
|
| + */
|
| + realPms = PK11_PubUnwrapSymKey(serverKey, &enc_pms,
|
| + CKM_SSL3_MASTER_KEY_DERIVE, CKA_DERIVE, 0);
|
| + /* Temporarily use the PMS if unwrapping the real PMS fails. */
|
| + useFauxPms |= (realPms == NULL);
|
| +
|
| + /* Attempt to derive the MS from the PMS. This is the only way to
|
| + * check the version field in the RSA PMS. If this fails, we
|
| + * then use the faux PMS in place of the PMS. Note that this
|
| + * operation should never fail if we are using the faux PMS
|
| + * since it is correctly formatted. */
|
| + rv = ssl3_ComputeMasterSecret(ss, currentPms, NULL);
|
| +
|
| + /* If we succeeded, then select the true PMS and discard the
|
| + * FPMS. Else, select the FPMS and select the true PMS */
|
| + useFauxPms |= (rv != SECSuccess);
|
| +
|
| + if (unusedPms) {
|
| + PK11_FreeSymKey(unusedPms);
|
| + }
|
| +
|
| /* This step will derive the MS from the PMS, among other things. */
|
| - rv = ssl3_InitPendingCipherSpec(ss, pms);
|
| - PK11_FreeSymKey(pms);
|
| + rv = ssl3_InitPendingCipherSpec(ss, currentPms);
|
| + PK11_FreeSymKey(currentPms);
|
| }
|
|
|
| if (rv != SECSuccess) {
|
| SEND_ALERT
|
| return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */
|
| }
|
| +
|
| +#undef currentPms
|
| +#undef unusedPms
|
| +#undef realPms
|
| +#undef fauxPms
|
| +
|
| return SECSuccess;
|
| }
|
|
|
| +static SECStatus
|
| +ssl3_HandleDHClientKeyExchange(sslSocket *ss,
|
| + SSL3Opaque *b,
|
| + PRUint32 length,
|
| + SECKEYPublicKey *srvrPubKey,
|
| + SECKEYPrivateKey *serverKey)
|
| +{
|
| + PK11SymKey *pms;
|
| + SECStatus rv;
|
| + SECKEYPublicKey clntPubKey;
|
| + CK_MECHANISM_TYPE target;
|
| + PRBool isTLS;
|
| +
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| + PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| + PORT_Assert( srvrPubKey );
|
| +
|
| + clntPubKey.keyType = dhKey;
|
| + clntPubKey.u.dh.prime.len = srvrPubKey->u.dh.prime.len;
|
| + clntPubKey.u.dh.prime.data = srvrPubKey->u.dh.prime.data;
|
| + clntPubKey.u.dh.base.len = srvrPubKey->u.dh.base.len;
|
| + clntPubKey.u.dh.base.data = srvrPubKey->u.dh.base.data;
|
| +
|
| + rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.dh.publicValue,
|
| + 2, &b, &length);
|
| + if (rv != SECSuccess) {
|
| + goto loser;
|
| + }
|
| +
|
| + 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;
|
| +
|
| + /* Determine the PMS */
|
| + pms = PK11_PubDerive(serverKey, &clntPubKey, PR_FALSE, NULL, NULL,
|
| + CKM_DH_PKCS_DERIVE, target, CKA_DERIVE, 0, NULL);
|
| + if (pms == NULL) {
|
| + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
|
| + goto loser;
|
| + }
|
| +
|
| + rv = ssl3_InitPendingCipherSpec(ss, pms);
|
| + PK11_FreeSymKey(pms); pms = NULL;
|
| +
|
| +loser:
|
| + if (ss->dheKeyPair) {
|
| + ssl3_FreeKeyPair(ss->dheKeyPair);
|
| + ss->dheKeyPair = NULL;
|
| + }
|
| + return rv;
|
| +}
|
| +
|
|
|
| /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
|
| * ssl3 ClientKeyExchange message from the remote client
|
| @@ -9748,9 +10352,7 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| SECStatus rv;
|
| const ssl3KEADef *kea_def;
|
| ssl3KeyPair *serverKeyPair = NULL;
|
| -#ifndef NSS_DISABLE_ECC
|
| SECKEYPublicKey *serverPubKey = NULL;
|
| -#endif /* NSS_DISABLE_ECC */
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle client_key_exchange handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -9780,6 +10382,16 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB;
|
| } else
|
| skip:
|
| + if (kea_def->kea == kea_dhe_dss ||
|
| + kea_def->kea == kea_dhe_rsa) {
|
| + if (ss->dheKeyPair) {
|
| + serverKeyPair = ss->dheKeyPair;
|
| + if (serverKeyPair->pubKey) {
|
| + ss->sec.keaKeyBits =
|
| + SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey);
|
| + }
|
| + }
|
| + } else
|
| #ifndef NSS_DISABLE_ECC
|
| /* XXX Using SSLKEAType to index server certifiates
|
| * does not work for (EC)DHE ciphers. Until we have
|
| @@ -9825,6 +10437,21 @@ skip:
|
| }
|
| break;
|
|
|
| + case ssl_kea_dh:
|
| + if (ss->dheKeyPair && ss->dheKeyPair->pubKey) {
|
| + serverPubKey = ss->dheKeyPair->pubKey;
|
| + }
|
| + if (!serverPubKey) {
|
| + PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| + rv = ssl3_HandleDHClientKeyExchange(ss, b, length,
|
| + serverPubKey, serverKey);
|
| + if (rv != SECSuccess) {
|
| + SSL3_SendAlert(ss, alert_fatal, handshake_failure);
|
| + return SECFailure; /* error code set */
|
| + }
|
| + break;
|
|
|
| #ifndef NSS_DISABLE_ECC
|
| case kt_ecdh:
|
| @@ -10454,6 +11081,8 @@ ssl3_AuthCertificate(sslSocket *ss)
|
|
|
| ss->ssl3.hs.authCertificatePending = PR_FALSE;
|
|
|
| + PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
|
| + ssl_preinfo_all);
|
| /*
|
| * Ask caller-supplied callback function to validate cert chain.
|
| */
|
| @@ -10498,40 +11127,60 @@ ssl3_AuthCertificate(sslSocket *ss)
|
| ss->sec.authAlgorithm = ss->ssl3.hs.kea_def->signKeyType;
|
| ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
|
| if (pubKey) {
|
| + KeyType pubKeyType;
|
| + PRInt32 minKey;
|
| ss->sec.keaKeyBits = ss->sec.authKeyBits =
|
| SECKEY_PublicKeyStrengthInBits(pubKey);
|
| -#ifndef NSS_DISABLE_ECC
|
| - if (ss->sec.keaType == kt_ecdh) {
|
| - /* Get authKeyBits from signing key.
|
| - * XXX The code below uses a quick approximation of
|
| - * key size based on cert->signatureWrap.signature.data
|
| - * (which contains the DER encoded signature). The field
|
| - * cert->signatureWrap.signature.len contains the
|
| - * length of the encoded signature in bits.
|
| - */
|
| - 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)
|
| - ss->sec.authKeyBits -= 8;
|
| - /*
|
| - * 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) {
|
| - ss->sec.authKeyBits = cert->signatureWrap.signature.len;
|
| - /*
|
| - * XXX: if cert is not signed by rsa we should
|
| - * destroy pubKey and goto bad_cert
|
| - */
|
| + pubKeyType = SECKEY_GetPublicKeyType(pubKey);
|
| + minKey = ss->sec.authKeyBits;
|
| + switch (pubKeyType) {
|
| + case rsaKey:
|
| + case rsaPssKey:
|
| + case rsaOaepKey:
|
| + rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minKey);
|
| + if (rv != SECSuccess) {
|
| + minKey = SSL_RSA_MIN_MODULUS_BITS;
|
| + }
|
| + break;
|
| + case dsaKey:
|
| + rv = NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minKey);
|
| + if (rv != SECSuccess) {
|
| + minKey = SSL_DSA_MIN_P_BITS;
|
| }
|
| + break;
|
| + case dhKey:
|
| + rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minKey);
|
| + if (rv != SECSuccess) {
|
| + minKey = SSL_DH_MIN_P_BITS;
|
| + }
|
| + break;
|
| + default:
|
| + break;
|
| }
|
| -#endif /* NSS_DISABLE_ECC */
|
| +
|
| + /* Too small: not good enough. Send a fatal alert. */
|
| + /* We aren't checking EC here on the understanding that we only
|
| + * support curves we like, a decision that might need revisiting. */
|
| + if ( ss->sec.authKeyBits < minKey) {
|
| + PORT_SetError(SSL_ERROR_WEAK_SERVER_CERT_KEY);
|
| + (void)SSL3_SendAlert(ss, alert_fatal,
|
| + ss->version >= SSL_LIBRARY_VERSION_TLS_1_0
|
| + ? insufficient_security
|
| + : illegal_parameter);
|
| + SECKEY_DestroyPublicKey(pubKey);
|
| + return SECFailure;
|
| + }
|
| SECKEY_DestroyPublicKey(pubKey);
|
| pubKey = NULL;
|
| }
|
|
|
| - if (ss->ssl3.hs.kea_def->ephemeral) {
|
| + /* Ephemeral suites require ServerKeyExchange. Export cipher suites
|
| + * with RSA key exchange also require ServerKeyExchange if the
|
| + * authentication key exceeds the key size limit. */
|
| + if (ss->ssl3.hs.kea_def->ephemeral ||
|
| + (ss->ssl3.hs.kea_def->is_limited &&
|
| + ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa &&
|
| + ss->sec.authKeyBits > ss->ssl3.hs.kea_def->key_size_limit)) {
|
| ss->ssl3.hs.ws = wait_server_key; /* require server_key_exchange */
|
| } else {
|
| ss->ssl3.hs.ws = wait_cert_request; /* disallow server_key_exchange */
|
| @@ -10643,16 +11292,42 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
|
| const SSL3Hashes * hashes,
|
| TLSFinished * tlsFinished)
|
| {
|
| - const char * label;
|
| - unsigned int len;
|
| - SECStatus rv;
|
| + SECStatus rv;
|
| + CK_TLS_MAC_PARAMS tls_mac_params;
|
| + SECItem param = {siBuffer, NULL, 0};
|
| + PK11Context *prf_context;
|
| + unsigned int retLen;
|
|
|
| - label = isServer ? "server finished" : "client finished";
|
| - len = 15;
|
| + if (!spec->master_secret || spec->bypassCiphers) {
|
| + const char *label = isServer ? "server finished" : "client finished";
|
| + unsigned int len = 15;
|
|
|
| - rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
|
| - hashes->len, tlsFinished->verify_data,
|
| - sizeof tlsFinished->verify_data);
|
| + return ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
|
| + hashes->len, tlsFinished->verify_data,
|
| + sizeof tlsFinished->verify_data);
|
| + }
|
| +
|
| + if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + tls_mac_params.prfMechanism = CKM_TLS_PRF;
|
| + } else {
|
| + tls_mac_params.prfMechanism = CKM_SHA256;
|
| + }
|
| + tls_mac_params.ulMacLength = 12;
|
| + tls_mac_params.ulServerOrClient = isServer ? 1 : 2;
|
| + param.data = (unsigned char *)&tls_mac_params;
|
| + param.len = sizeof(tls_mac_params);
|
| + prf_context = PK11_CreateContextBySymKey(CKM_TLS_MAC, CKA_SIGN,
|
| + spec->master_secret, ¶m);
|
| + if (!prf_context)
|
| + return SECFailure;
|
| +
|
| + rv = PK11_DigestBegin(prf_context);
|
| + rv |= PK11_DigestOp(prf_context, hashes->u.raw, hashes->len);
|
| + rv |= PK11_DigestFinal(prf_context, tlsFinished->verify_data, &retLen,
|
| + sizeof tlsFinished->verify_data);
|
| + PORT_Assert(rv != SECSuccess || retLen == sizeof tlsFinished->verify_data);
|
| +
|
| + PK11_DestroyContext(prf_context, PR_TRUE);
|
|
|
| return rv;
|
| }
|
| @@ -11170,6 +11845,13 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
| return SECFailure;
|
| }
|
|
|
| + if (!hashes) {
|
| + PORT_Assert(0);
|
| + SSL3_SendAlert(ss, alert_fatal, internal_error);
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| isTLS = (PRBool)(ss->ssl3.crSpec->version > SSL_LIBRARY_VERSION_3_0);
|
| if (isTLS) {
|
| TLSFinished tlsFinished;
|
| @@ -11225,7 +11907,8 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
|
| * ServerHello message.)
|
| */
|
| if (isServer && !ss->ssl3.hs.isResuming &&
|
| - ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn)) {
|
| + ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn) &&
|
| + ssl3_KEAAllowsSessionTicket(ss->ssl3.hs.suite_def->key_exchange_alg)) {
|
| /* RFC 5077 Section 3.3: "In the case of a full handshake, the
|
| * server MUST verify the client's Finished message before sending
|
| * the ticket." Presumably, this also means that the client's
|
| @@ -11278,7 +11961,8 @@ xmit_loser:
|
| return rv;
|
| }
|
|
|
| - if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) {
|
| + if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa ||
|
| + ss->ssl3.hs.kea_def->kea == kea_dhe_rsa) {
|
| effectiveExchKeyType = kt_rsa;
|
| } else {
|
| effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
|
| @@ -11398,6 +12082,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| SECStatus rv = SECSuccess;
|
| SSL3HandshakeType type = ss->ssl3.hs.msg_type;
|
| SSL3Hashes hashes; /* computed hashes are put here. */
|
| + SSL3Hashes *hashesPtr = NULL; /* Set when hashes are computed */
|
| PRUint8 hdr[4];
|
| PRUint8 dtlsData[8];
|
|
|
| @@ -11408,7 +12093,8 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| * current message.
|
| */
|
| ssl_GetSpecReadLock(ss); /************************************/
|
| - if((type == finished) || (type == certificate_verify)) {
|
| + if(((type == finished) && (ss->ssl3.hs.ws == wait_finished)) ||
|
| + ((type == certificate_verify) && (ss->ssl3.hs.ws == wait_cert_verify))) {
|
| SSL3Sender sender = (SSL3Sender)0;
|
| ssl3CipherSpec *rSpec = ss->ssl3.prSpec;
|
|
|
| @@ -11417,6 +12103,9 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| rSpec = ss->ssl3.crSpec;
|
| }
|
| rv = ssl3_ComputeHandshakeHashes(ss, rSpec, &hashes, sender);
|
| + if (rv == SECSuccess) {
|
| + hashesPtr = &hashes;
|
| + }
|
| }
|
| ssl_ReleaseSpecReadLock(ss); /************************************/
|
| if (rv != SECSuccess) {
|
| @@ -11567,7 +12256,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY);
|
| return SECFailure;
|
| }
|
| - rv = ssl3_HandleCertificateVerify(ss, b, length, &hashes);
|
| + rv = ssl3_HandleCertificateVerify(ss, b, length, hashesPtr);
|
| break;
|
| case client_key_exchange:
|
| if (!ss->sec.isServer) {
|
| @@ -11586,7 +12275,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
| rv = ssl3_HandleNewSessionTicket(ss, b, length);
|
| break;
|
| case finished:
|
| - rv = ssl3_HandleFinished(ss, b, length, &hashes);
|
| + rv = ssl3_HandleFinished(ss, b, length, hashesPtr);
|
| break;
|
| default:
|
| (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
|
| @@ -11641,7 +12330,7 @@ ssl3_HandleHandshake(sslSocket *ss, sslBuffer *origBuf)
|
| #define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */
|
| if (ss->ssl3.hs.msg_len > MAX_HANDSHAKE_MSG_LEN) {
|
| (void)ssl3_DecodeError(ss);
|
| - PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
|
| + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE);
|
| return SECFailure;
|
| }
|
| #undef MAX_HANDSHAKE_MSG_LEN
|
| @@ -11942,7 +12631,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
|
| SSL3Opaque *givenHash;
|
| sslBuffer *plaintext;
|
| sslBuffer temp_buf;
|
| - PRUint64 dtls_seq_num;
|
| + PRUint64 dtls_seq_num = 0;
|
| unsigned int ivLen = 0;
|
| unsigned int originalLen = 0;
|
| unsigned int good;
|
| @@ -12423,6 +13112,7 @@ ssl3_InitState(sslSocket *ss)
|
| ss->ssl3.hs.sendingSCSV = PR_FALSE;
|
| ssl3_InitCipherSpec(ss, ss->ssl3.crSpec);
|
| ssl3_InitCipherSpec(ss, ss->ssl3.prSpec);
|
| + ss->ssl3.hs.preliminaryInfo = 0;
|
|
|
| ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello;
|
| #ifndef NSS_DISABLE_ECC
|
| @@ -12496,8 +13186,6 @@ ssl3_FreeKeyPair(ssl3KeyPair * keyPair)
|
| }
|
| }
|
|
|
| -
|
| -
|
| /*
|
| * Creates the public and private RSA keys for SSL Step down.
|
| * Called from SSL_ConfigSecureServer in sslsecur.c
|
| @@ -12529,7 +13217,6 @@ ssl3_CreateRSAStepDownKeys(sslSocket *ss)
|
| return rv;
|
| }
|
|
|
| -
|
| /* record the export policy for this cipher suite */
|
| SECStatus
|
| ssl3_SetPolicy(ssl3CipherSuite which, int policy)
|
| @@ -12631,6 +13318,79 @@ ssl3_CipherPrefGet(sslSocket *ss, ssl3CipherSuite which, PRBool *enabled)
|
| }
|
|
|
| SECStatus
|
| +SSL_SignaturePrefSet(PRFileDesc *fd, const SSLSignatureAndHashAlg *algorithms,
|
| + unsigned int count)
|
| +{
|
| + sslSocket *ss;
|
| + unsigned int i;
|
| +
|
| + ss = ssl_FindSocket(fd);
|
| + if (!ss) {
|
| + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SignaturePrefSet",
|
| + SSL_GETPID(), fd));
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + return SECFailure;
|
| + }
|
| +
|
| + if (!count || count > MAX_SIGNATURE_ALGORITHMS) {
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + return SECFailure;
|
| + }
|
| +
|
| + ss->ssl3.signatureAlgorithmCount = 0;
|
| + for (i = 0; i < count; ++i) {
|
| + if (!ssl3_IsSupportedSignatureAlgorithm(&algorithms[i])) {
|
| + SSL_DBG(("%d: SSL[%d]: invalid signature algorithm set %d/%d",
|
| + SSL_GETPID(), fd, algorithms[i].sigAlg,
|
| + algorithms[i].hashAlg));
|
| + continue;
|
| + }
|
| +
|
| + ss->ssl3.signatureAlgorithms[ss->ssl3.signatureAlgorithmCount++] =
|
| + algorithms[i];
|
| + }
|
| +
|
| + if (ss->ssl3.signatureAlgorithmCount == 0) {
|
| + PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +SECStatus
|
| +SSL_SignaturePrefGet(PRFileDesc *fd, SSLSignatureAndHashAlg *algorithms,
|
| + unsigned int *count, unsigned int maxCount)
|
| +{
|
| + sslSocket *ss;
|
| + unsigned int requiredSpace;
|
| +
|
| + ss = ssl_FindSocket(fd);
|
| + if (!ss) {
|
| + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SignaturePrefGet",
|
| + SSL_GETPID(), fd));
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + return SECFailure;
|
| + }
|
| +
|
| + if (!algorithms || !count ||
|
| + maxCount < ss->ssl3.signatureAlgorithmCount) {
|
| + PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| + return SECFailure;
|
| + }
|
| +
|
| + requiredSpace =
|
| + ss->ssl3.signatureAlgorithmCount * sizeof(SSLSignatureAndHashAlg);
|
| + PORT_Memcpy(algorithms, ss->ssl3.signatureAlgorithms, requiredSpace);
|
| + *count = ss->ssl3.signatureAlgorithmCount;
|
| + return SECSuccess;
|
| +}
|
| +
|
| +unsigned int
|
| +SSL_SignatureMaxCount() {
|
| + return MAX_SIGNATURE_ALGORITHMS;
|
| +}
|
| +
|
| +SECStatus
|
| ssl3_CipherOrderSet(sslSocket *ss, const ssl3CipherSuite *ciphers, unsigned int len)
|
| {
|
| /* |i| iterates over |ciphers| while |done| and |j| iterate over
|
| @@ -12675,6 +13435,9 @@ void
|
| ssl3_InitSocketPolicy(sslSocket *ss)
|
| {
|
| PORT_Memcpy(ss->cipherSuites, cipherSuites, sizeof cipherSuites);
|
| + PORT_Memcpy(ss->ssl3.signatureAlgorithms, defaultSignatureAlgorithms,
|
| + sizeof(defaultSignatureAlgorithms));
|
| + ss->ssl3.signatureAlgorithmCount = PR_ARRAY_SIZE(defaultSignatureAlgorithms);
|
| }
|
|
|
| SECStatus
|
| @@ -12764,7 +13527,7 @@ ssl3_ConstructV2CipherSpecsHack(sslSocket *ss, unsigned char *cs, int *size)
|
| /* ssl3_config_match_init was called by the caller of this function. */
|
| for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
|
| ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
|
| - if (config_match(suite, SSL_ALLOWED, PR_TRUE, &ss->vrange)) {
|
| + if (config_match(suite, SSL_ALLOWED, PR_TRUE, &ss->vrange, ss)) {
|
| if (cs != NULL) {
|
| *cs++ = 0x00;
|
| *cs++ = (suite->cipher_suite >> 8) & 0xFF;
|
| @@ -12898,6 +13661,10 @@ ssl3_DestroySSL3Info(sslSocket *ss)
|
| }
|
| }
|
|
|
| + if (ss->ssl3.dheGroups) {
|
| + PORT_Free(ss->ssl3.dheGroups);
|
| + }
|
| +
|
| ss->ssl3.initialized = PR_FALSE;
|
|
|
| SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE);
|
|
|