| Index: net/third_party/nss/ssl/ssl3con.c
|
| ===================================================================
|
| --- net/third_party/nss/ssl/ssl3con.c (revision 199250)
|
| +++ net/third_party/nss/ssl/ssl3con.c (working copy)
|
| @@ -15,6 +15,7 @@
|
| #include "keyhi.h"
|
| #include "secder.h"
|
| #include "secitem.h"
|
| +#include "sechash.h"
|
|
|
| #include "sslimpl.h"
|
| #include "sslproto.h"
|
| @@ -800,15 +801,101 @@
|
| return rv;
|
| }
|
|
|
| +#define SSL_MAX_RSA_ASN1_PREFIX 20
|
| +
|
| +/* ssl3_GetPKCS1v15ASN1Data sets |out| and |out_len| to point to a buffer that
|
| + * contains ASN.1 data that should be prepended to a hash of the given type in
|
| + * order to create a structure that is valid for use in a PKCS#1 v1.5 RSA
|
| + * signature. |out_len| will not be set to a value greater than
|
| + * SSL_MAX_RSA_ASN1_PREFIX. */
|
| +static SECStatus
|
| +ssl3_GetPKCS1v15ASN1Data(SECOidTag hashAlg,
|
| + const SSL3Opaque** out, unsigned int *out_len)
|
| +{
|
| + /* These are ASN1 DER structures:
|
| + * DigestInfo ::= SEQUENCE {
|
| + * digestAlgorithm AlgorithmIdentifier,
|
| + * digest OCTET STRING
|
| + * }
|
| + */
|
| + static const unsigned char kMD5[] = {
|
| + 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
|
| + 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
|
| + 0x04, 0x10
|
| + };
|
| + static const unsigned char kSHA1[] = {
|
| + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
|
| + 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
|
| + };
|
| + static const unsigned char kSHA224[] = {
|
| + 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
|
| + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
|
| + 0x00, 0x04, 0x1c
|
| + };
|
| + static const unsigned char kSHA256[] = {
|
| + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
|
| + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
|
| + 0x00, 0x04, 0x20
|
| + };
|
| + static const unsigned char kSHA384[] = {
|
| + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
|
| + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
|
| + 0x00, 0x04, 0x30
|
| + };
|
| + static const unsigned char kSHA512[] = {
|
| + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
|
| + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
|
| + 0x00, 0x04, 0x40
|
| + };
|
| +
|
| + switch (hashAlg) {
|
| + case SEC_OID_UNKNOWN:
|
| + *out_len = 0;
|
| + break;
|
| + case SEC_OID_MD5:
|
| + *out = kMD5;
|
| + *out_len = sizeof(kMD5);
|
| + break;
|
| + case SEC_OID_SHA1:
|
| + *out = kSHA1;
|
| + *out_len = sizeof(kSHA1);
|
| + break;
|
| + case SEC_OID_SHA224:
|
| + *out = kSHA224;
|
| + *out_len = sizeof(kSHA224);
|
| + break;
|
| + case SEC_OID_SHA256:
|
| + *out = kSHA256;
|
| + *out_len = sizeof(kSHA256);
|
| + break;
|
| + case SEC_OID_SHA384:
|
| + *out = kSHA384;
|
| + *out_len = sizeof(kSHA384);
|
| + break;
|
| + case SEC_OID_SHA512:
|
| + *out = kSHA512;
|
| + *out_len = sizeof(kSHA512);
|
| + break;
|
| + default:
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| +
|
| + return SECSuccess;
|
| +}
|
| +
|
| /* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
|
| SECStatus
|
| ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf,
|
| PRBool isTLS)
|
| {
|
| - SECStatus rv = SECFailure;
|
| - PRBool doDerEncode = PR_FALSE;
|
| - int signatureLen;
|
| - SECItem hashItem;
|
| + SECStatus rv = SECFailure;
|
| + PRBool doDerEncode = PR_FALSE;
|
| + int signatureLen;
|
| + SECItem hashItem;
|
| + unsigned int len;
|
| + const SSL3Opaque* asn1Prefix;
|
| + SSL3Opaque asn1AndHash[HASH_LENGTH_MAX + SSL_MAX_RSA_ASN1_PREFIX];
|
|
|
| buf->data = NULL;
|
| signatureLen = PK11_SignatureLen(key);
|
| @@ -824,19 +911,44 @@
|
|
|
| switch (key->keyType) {
|
| case rsaKey:
|
| - hashItem.data = hash->md5;
|
| - hashItem.len = sizeof(SSL3Hashes);
|
| + rv = ssl3_GetPKCS1v15ASN1Data(hash->hashAlg, &asn1Prefix, &len);
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| + }
|
| + if (len + hash->len > sizeof(asn1AndHash)) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| + memcpy(asn1AndHash, asn1Prefix, len);
|
| + memcpy(asn1AndHash + len, hash->u.raw, hash->len);
|
| + len += hash->len;
|
| + hashItem.data = asn1AndHash;
|
| + hashItem.len = len;
|
| break;
|
| case dsaKey:
|
| doDerEncode = isTLS;
|
| - hashItem.data = hash->sha;
|
| - hashItem.len = sizeof(hash->sha);
|
| + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + * In that case, we use just the SHA1 part. */
|
| + if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + hashItem.data = hash->u.s.sha;
|
| + hashItem.len = sizeof(hash->u.s.sha);
|
| + } else {
|
| + hashItem.data = hash->u.raw;
|
| + hashItem.len = hash->len;
|
| + }
|
| break;
|
| #ifdef NSS_ENABLE_ECC
|
| case ecKey:
|
| doDerEncode = PR_TRUE;
|
| - hashItem.data = hash->sha;
|
| - hashItem.len = sizeof(hash->sha);
|
| + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + * In that case, we use just the SHA1 part. */
|
| + if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + hashItem.data = hash->u.s.sha;
|
| + hashItem.len = sizeof(hash->u.s.sha);
|
| + } else {
|
| + hashItem.data = hash->u.raw;
|
| + hashItem.len = hash->len;
|
| + }
|
| break;
|
| #endif /* NSS_ENABLE_ECC */
|
| default:
|
| @@ -879,9 +991,9 @@
|
| SECItem * signature = NULL;
|
| SECStatus rv;
|
| SECItem hashItem;
|
| -#ifdef NSS_ENABLE_ECC
|
| + const SSL3Opaque* asn1Prefix;
|
| + SSL3Opaque asn1AndHash[HASH_LENGTH_MAX + SSL_MAX_RSA_ASN1_PREFIX];
|
| unsigned int len;
|
| -#endif /* NSS_ENABLE_ECC */
|
|
|
|
|
| PRINT_BUF(60, (NULL, "check signed hashes",
|
| @@ -895,12 +1007,30 @@
|
|
|
| switch (key->keyType) {
|
| case rsaKey:
|
| - hashItem.data = hash->md5;
|
| - hashItem.len = sizeof(SSL3Hashes);
|
| + rv = ssl3_GetPKCS1v15ASN1Data(hash->hashAlg, &asn1Prefix, &len);
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| + }
|
| + if (len + hash->len > sizeof(asn1AndHash)) {
|
| + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| + memcpy(asn1AndHash, asn1Prefix, len);
|
| + memcpy(asn1AndHash + len, hash->u.raw, hash->len);
|
| + len += hash->len;
|
| + hashItem.data = asn1AndHash;
|
| + hashItem.len = len;
|
| break;
|
| case dsaKey:
|
| - hashItem.data = hash->sha;
|
| - hashItem.len = sizeof(hash->sha);
|
| + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + * In that case, we use just the SHA1 part. */
|
| + if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + hashItem.data = hash->u.s.sha;
|
| + hashItem.len = sizeof(hash->u.s.sha);
|
| + } else {
|
| + hashItem.data = hash->u.raw;
|
| + hashItem.len = hash->len;
|
| + }
|
| /* Allow DER encoded DSA signatures in SSL 3.0 */
|
| if (isTLS || buf->len != SECKEY_SignatureLen(key)) {
|
| signature = DSAU_DecodeDerSig(buf);
|
| @@ -914,8 +1044,15 @@
|
|
|
| #ifdef NSS_ENABLE_ECC
|
| case ecKey:
|
| - hashItem.data = hash->sha;
|
| - hashItem.len = sizeof(hash->sha);
|
| + /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated hash.
|
| + * In that case, we use just the SHA1 part. */
|
| + if (hash->hashAlg == SEC_OID_UNKNOWN) {
|
| + hashItem.data = hash->u.s.sha;
|
| + hashItem.len = sizeof(hash->u.s.sha);
|
| + } else {
|
| + hashItem.data = hash->u.raw;
|
| + hashItem.len = hash->len;
|
| + }
|
| /*
|
| * ECDSA signatures always encode the integers r and s
|
| * using ASN (unlike DSA where ASN encoding is used
|
| @@ -961,33 +1098,66 @@
|
| /* Called from ssl3_ComputeExportRSAKeyHash
|
| * ssl3_ComputeDHKeyHash
|
| * which are called from ssl3_HandleServerKeyExchange.
|
| + *
|
| + * hashAlg: either the OID for a hash function or SEC_OID_UNKNOWN to specify
|
| + * the pre-1.2, MD5/SHA1 combination hash.
|
| */
|
| SECStatus
|
| -ssl3_ComputeCommonKeyHash(PRUint8 * hashBuf, unsigned int bufLen,
|
| - SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| +ssl3_ComputeCommonKeyHash(SECOidTag hashAlg,
|
| + PRUint8 * hashBuf, unsigned int bufLen,
|
| + SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| {
|
| SECStatus rv = SECSuccess;
|
|
|
| #ifndef NO_PKCS11_BYPASS
|
| if (bypassPKCS11) {
|
| - MD5_HashBuf (hashes->md5, hashBuf, bufLen);
|
| - SHA1_HashBuf(hashes->sha, hashBuf, bufLen);
|
| + 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 {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| } else
|
| #endif
|
| {
|
| - rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| - rv = SECFailure;
|
| - goto done;
|
| - }
|
| + 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->sha, hashBuf, bufLen);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| - rv = SECFailure;
|
| + 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_SIGN_HASHES_FAILURE);
|
| + rv = SECFailure;
|
| + } else {
|
| + rv = PK11_HashBuf(hashAlg, hashes->u.raw, hashBuf, bufLen);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
|
| + rv = SECFailure;
|
| + }
|
| + }
|
| }
|
| }
|
| + hashes->hashAlg = hashAlg;
|
| +
|
| done:
|
| return rv;
|
| }
|
| @@ -997,7 +1167,8 @@
|
| ** ssl3_HandleServerKeyExchange.
|
| */
|
| static SECStatus
|
| -ssl3_ComputeExportRSAKeyHash(SECItem modulus, SECItem publicExponent,
|
| +ssl3_ComputeExportRSAKeyHash(SECOidTag hashAlg,
|
| + SECItem modulus, SECItem publicExponent,
|
| SSL3Random *client_rand, SSL3Random *server_rand,
|
| SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| {
|
| @@ -1033,11 +1204,15 @@
|
| pBuf += publicExponent.len;
|
| PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
|
|
|
| - rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11);
|
| + rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, bypassPKCS11);
|
|
|
| PRINT_BUF(95, (NULL, "RSAkey hash: ", hashBuf, bufLen));
|
| - PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", hashes->md5, MD5_LENGTH));
|
| - PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", hashes->sha, SHA1_LENGTH));
|
| + if (hashAlg == SEC_OID_UNKNOWN) {
|
| + PRINT_BUF(95, (NULL, "RSAkey hash: MD5 result", hashes->u.s.md5, MD5_LENGTH));
|
| + PRINT_BUF(95, (NULL, "RSAkey hash: SHA1 result", hashes->u.s.sha, SHA1_LENGTH));
|
| + } else {
|
| + PRINT_BUF(95, (NULL, "RSAkey hash: ", hashes->u.raw, hashes->len));
|
| + }
|
|
|
| if (hashBuf != buf && hashBuf != NULL)
|
| PORT_Free(hashBuf);
|
| @@ -1047,9 +1222,10 @@
|
| /* Caller must set hiLevel error code. */
|
| /* Called from ssl3_HandleServerKeyExchange. */
|
| static SECStatus
|
| -ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
|
| - SSL3Random *client_rand, SSL3Random *server_rand,
|
| - SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| +ssl3_ComputeDHKeyHash(SECOidTag hashAlg,
|
| + SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
|
| + SSL3Random *client_rand, SSL3Random *server_rand,
|
| + SSL3Hashes *hashes, PRBool bypassPKCS11)
|
| {
|
| PRUint8 * hashBuf;
|
| PRUint8 * pBuf;
|
| @@ -1088,11 +1264,15 @@
|
| pBuf += dh_Ys.len;
|
| PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
|
|
|
| - rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11);
|
| + rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes, bypassPKCS11);
|
|
|
| PRINT_BUF(95, (NULL, "DHkey hash: ", hashBuf, bufLen));
|
| - PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", hashes->md5, MD5_LENGTH));
|
| - PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH));
|
| + if (hashAlg == SEC_OID_UNKNOWN) {
|
| + PRINT_BUF(95, (NULL, "DHkey hash: MD5 result", hashes->u.s.md5, MD5_LENGTH));
|
| + PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result", hashes->u.s.sha, SHA1_LENGTH));
|
| + } else {
|
| + PRINT_BUF(95, (NULL, "DHkey hash: ", hashes->u.raw, hashes->len));
|
| + }
|
|
|
| if (hashBuf != buf && hashBuf != NULL)
|
| PORT_Free(hashBuf);
|
| @@ -3190,6 +3370,8 @@
|
| unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
|
| PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
|
| (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
|
| + PRBool 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
|
| @@ -3208,7 +3390,12 @@
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
|
| PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);
|
| - if (isTLS) {
|
| + if (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;
|
| + keyFlags = CKF_SIGN | CKF_VERIFY;
|
| + } else if (isTLS) {
|
| if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
|
| else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
|
| key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
|
| @@ -3366,6 +3553,8 @@
|
| unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
|
| PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
|
| (pwSpec->version > SSL_LIBRARY_VERSION_3_0));
|
| + PRBool isTLS12=
|
| + (PRBool)(isTLS && pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
|
| /* following variables used in PKCS11 path */
|
| const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
|
| PK11SlotInfo * slot = NULL;
|
| @@ -3423,7 +3612,9 @@
|
| params.data = (unsigned char *)&key_material_params;
|
| params.len = sizeof(key_material_params);
|
|
|
| - if (isTLS) {
|
| + if (isTLS12) {
|
| + key_derive = CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256;
|
| + } else if (isTLS) {
|
| key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
|
| } else {
|
| key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
|
| @@ -3480,19 +3671,64 @@
|
| return SECFailure;
|
| }
|
|
|
| +/* ssl3_InitTLS12HandshakeHash creates a handshake hash function for TLS 1.2,
|
| + * if needed, and hashes in any buffered messages in ss->ssl3.hs.messages. */
|
| +static SECStatus
|
| +ssl3_InitTLS12HandshakeHash(sslSocket *ss)
|
| +{
|
| + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2 &&
|
| + ss->ssl3.hs.tls12_handshake_hash == NULL) {
|
| + /* If we ever support ciphersuites where the PRF hash isn't SHA-256
|
| + * then this will need to be updated. */
|
| + ss->ssl3.hs.tls12_handshake_hash =
|
| + PK11_CreateDigestContext(SEC_OID_SHA256);
|
| + if (!ss->ssl3.hs.tls12_handshake_hash ||
|
| + SECSuccess != PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash)) {
|
| + ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| + }
|
| +
|
| + if (ss->ssl3.hs.tls12_handshake_hash && ss->ssl3.hs.messages.len > 0) {
|
| + if (SECSuccess != PK11_DigestOp(
|
| + ss->ssl3.hs.tls12_handshake_hash,
|
| + ss->ssl3.hs.messages.buf,
|
| + ss->ssl3.hs.messages.len)) {
|
| + ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| + }
|
| +
|
| + if (ss->ssl3.hs.messages.buf && !ss->opt.bypassPKCS11) {
|
| + PORT_Free(ss->ssl3.hs.messages.buf);
|
| + ss->ssl3.hs.messages.buf = NULL;
|
| + ss->ssl3.hs.messages.len = 0;
|
| + ss->ssl3.hs.messages.space = 0;
|
| + }
|
| +
|
| + return SECSuccess;
|
| +}
|
| +
|
| static SECStatus
|
| ssl3_RestartHandshakeHashes(sslSocket *ss)
|
| {
|
| SECStatus rv = SECSuccess;
|
|
|
| + ss->ssl3.hs.messages.len = 0;
|
| #ifndef NO_PKCS11_BYPASS
|
| if (ss->opt.bypassPKCS11) {
|
| - ss->ssl3.hs.messages.len = 0;
|
| MD5_Begin((MD5Context *)ss->ssl3.hs.md5_cx);
|
| SHA1_Begin((SHA1Context *)ss->ssl3.hs.sha_cx);
|
| } else
|
| #endif
|
| {
|
| + if (ss->ssl3.hs.tls12_handshake_hash) {
|
| + rv = PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
|
| + return rv;
|
| + }
|
| + }
|
| rv = PK11_DigestBegin(ss->ssl3.hs.md5);
|
| if (rv != SECSuccess) {
|
| ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| @@ -3519,25 +3755,21 @@
|
| * that the master secret will wind up in ...
|
| */
|
| SSL_TRC(30,("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
|
| -#ifndef NO_PKCS11_BYPASS
|
| - if (ss->opt.bypassPKCS11) {
|
| - PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space);
|
| - ss->ssl3.hs.messages.buf = NULL;
|
| - ss->ssl3.hs.messages.space = 0;
|
| - } else
|
| -#endif
|
| - {
|
| - ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5);
|
| - ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1);
|
| - if (md5 == NULL) {
|
| - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| - goto loser;
|
| - }
|
| - if (sha == NULL) {
|
| - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| - goto loser;
|
| - }
|
| + PORT_Assert(!ss->ssl3.hs.messages.buf && !ss->ssl3.hs.messages.space);
|
| + ss->ssl3.hs.messages.buf = NULL;
|
| + ss->ssl3.hs.messages.space = 0;
|
| +
|
| + ss->ssl3.hs.md5 = md5 = PK11_CreateDigestContext(SEC_OID_MD5);
|
| + ss->ssl3.hs.sha = sha = PK11_CreateDigestContext(SEC_OID_SHA1);
|
| + ss->ssl3.hs.tls12_handshake_hash = NULL;
|
| + if (md5 == NULL) {
|
| + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| + goto loser;
|
| }
|
| + if (sha == NULL) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| + goto loser;
|
| + }
|
| if (SECSuccess == ssl3_RestartHandshakeHashes(ss)) {
|
| return SECSuccess;
|
| }
|
| @@ -3574,6 +3806,17 @@
|
|
|
| PRINT_BUF(90, (NULL, "MD5 & SHA handshake hash input:", b, l));
|
|
|
| + if ((ss->version == 0 || ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) &&
|
| + !ss->opt.bypassPKCS11 &&
|
| + ss->ssl3.hs.tls12_handshake_hash == NULL) {
|
| + /* For TLS 1.2 connections we need to buffer the handshake messages
|
| + * until we have established which PRF hash function to use. */
|
| + rv = sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| + }
|
| + }
|
| +
|
| #ifndef NO_PKCS11_BYPASS
|
| if (ss->opt.bypassPKCS11) {
|
| MD5_Update((MD5Context *)ss->ssl3.hs.md5_cx, b, l);
|
| @@ -3584,16 +3827,20 @@
|
| return rv;
|
| }
|
| #endif
|
| - rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| - return rv;
|
| + if (ss->ssl3.hs.tls12_handshake_hash) {
|
| + rv = PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, b, l);
|
| + } else {
|
| + rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| + return rv;
|
| + }
|
| + rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| + return rv;
|
| + }
|
| }
|
| - rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
|
| - if (rv != SECSuccess) {
|
| - ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| - return rv;
|
| - }
|
| return rv;
|
| }
|
|
|
| @@ -3744,6 +3991,25 @@
|
| return rv; /* error code set by AppendHandshake, if applicable. */
|
| }
|
|
|
| +/* ssl3_AppendSignatureAndHashAlgorithm appends the serialisation of
|
| + * |sigAndHash| to the current handshake message. */
|
| +SECStatus
|
| +ssl3_AppendSignatureAndHashAlgorithm(
|
| + sslSocket *ss, const SSL3SignatureAndHashAlgorithm* sigAndHash)
|
| +{
|
| + unsigned char serialized[2];
|
| +
|
| + serialized[0] = ssl3_OIDToTLSHashFunction(sigAndHash->hashAlg);
|
| + if (serialized[0] == 0) {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| +
|
| + serialized[1] = sigAndHash->sigAlg;
|
| +
|
| + return ssl3_AppendHandshake(ss, serialized, sizeof(serialized));
|
| +}
|
| +
|
| /**************************************************************************
|
| * Consume Handshake functions.
|
| *
|
| @@ -3850,6 +4116,145 @@
|
| return SECSuccess;
|
| }
|
|
|
| +/* tls12HashOIDMap contains the mapping between TLS hash identifiers and the
|
| + * SECOidTag used internally by NSS. */
|
| +static const struct {
|
| + int tlsHash;
|
| + SECOidTag oid;
|
| +} tls12HashOIDMap[] = {
|
| + { 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 }
|
| +};
|
| +
|
| +/* ssl3_TLSHashFunctionToOID converts a TLS hash identifier into an OID value.
|
| + * If the hash is not recognised, SEC_OID_UNKNOWN is returned.
|
| + *
|
| + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| +SECOidTag ssl3_TLSHashFunctionToOID(int hashFunc)
|
| +{
|
| + size_t i;
|
| +
|
| + for (i = 0; i < sizeof(tls12HashOIDMap) / sizeof(tls12HashOIDMap[0]); i++) {
|
| + if (hashFunc == tls12HashOIDMap[i].tlsHash) {
|
| + return tls12HashOIDMap[i].oid;
|
| + }
|
| + }
|
| + return SEC_OID_UNKNOWN;
|
| +}
|
| +
|
| +/* ssl3_OIDToTLSHashFunction converts an OID to a TLS hash function identifier.
|
| + * If the hash is not recognised, zero is returned.
|
| + *
|
| + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| +int ssl3_OIDToTLSHashFunction(SECOidTag oid)
|
| +{
|
| + size_t i;
|
| +
|
| + for (i = 0; i < sizeof(tls12HashOIDMap) / sizeof(tls12HashOIDMap[0]); i++) {
|
| + if (oid == tls12HashOIDMap[i].oid) {
|
| + return tls12HashOIDMap[i].tlsHash;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +/* ssl3_TLSSignatureAlgorithmForKeyType returns the TLS signature algorithm
|
| + * identifier for a given KeyType. */
|
| +static SECStatus ssl3_TLSSignatureAlgorithmForKeyType(
|
| + KeyType keyType, TLS12SignatureAlgorithm *out)
|
| +{
|
| + switch (keyType) {
|
| + case rsaKey:
|
| + *out = tls_sig_rsa;
|
| + return SECSuccess;
|
| + case dsaKey:
|
| + *out = tls_sig_dsa;
|
| + return SECSuccess;
|
| + case ecKey:
|
| + *out = tls_sig_ecdsa;
|
| + return SECSuccess;
|
| + }
|
| + PORT_SetError(SEC_ERROR_INVALID_KEY);
|
| + return SECFailure;
|
| +}
|
| +
|
| +/* ssl3_TLSSignatureAlgorithmForKey returns the TLS 1.2 signature algorithm
|
| + * identifier for the given private key. */
|
| +static SECStatus ssl3_TLSSignatureAlgorithmForPrivateKey(
|
| + SECKEYPrivateKey *key, TLS12SignatureAlgorithm *out)
|
| +{
|
| + return ssl3_TLSSignatureAlgorithmForKeyType(key->keyType, out);
|
| +}
|
| +
|
| +/* ssl3_TLSSignatureAlgorithmForCert returns the TLS 1.2 signature algorithm
|
| + * identifier for the given certificate. */
|
| +static SECStatus ssl3_TLSSignatureAlgorithmForCertificate(
|
| + CERTCertificate *cert, TLS12SignatureAlgorithm *out)
|
| +{
|
| + SECKEYPublicKey *key;
|
| +
|
| + key = CERT_ExtractPublicKey(cert);
|
| + if (key == NULL) {
|
| + ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
|
| + return SECFailure;
|
| + }
|
| +
|
| + return ssl3_TLSSignatureAlgorithmForKeyType(key->keyType, out);
|
| +}
|
| +
|
| +/* 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. */
|
| +SECStatus ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| + const SSL3SignatureAndHashAlgorithm *sigAndHash, CERTCertificate* cert)
|
| +{
|
| + SECStatus rv;
|
| + TLS12SignatureAlgorithm sigAlg;
|
| +
|
| + rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg);
|
| + if (rv != SECSuccess) {
|
| + return SECFailure;
|
| + }
|
| + if (sigAlg != sigAndHash->sigAlg) {
|
| + PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
|
| + return SECFailure;
|
| + }
|
| + return SECSuccess;
|
| +}
|
| +
|
| +/* ssl3_ConsumeSignatureAndHashAlgorithm reads a SignatureAndHashAlgorithm
|
| + * structure from |b| and puts the resulting value into |out|. |b| and |length|
|
| + * are updated accordingly.
|
| + *
|
| + * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */
|
| +SECStatus
|
| +ssl3_ConsumeSignatureAndHashAlgorithm(sslSocket *ss,
|
| + SSL3Opaque **b,
|
| + PRUint32 *length,
|
| + SSL3SignatureAndHashAlgorithm *out) {
|
| + unsigned char bytes[2];
|
| + SECStatus rv;
|
| +
|
| + rv = ssl3_ConsumeHandshake(ss, bytes, sizeof(bytes), b, length);
|
| + if (rv != SECSuccess) {
|
| + return rv;
|
| + }
|
| +
|
| + out->hashAlg = ssl3_TLSHashFunctionToOID(bytes[0]);
|
| + if (out->hashAlg == SEC_OID_UNKNOWN) {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| +
|
| + out->sigAlg = bytes[1];
|
| + return SECSuccess;
|
| +}
|
| +
|
| /**************************************************************************
|
| * end of Consume Handshake functions.
|
| **************************************************************************/
|
| @@ -3876,6 +4281,7 @@
|
| SSL3Opaque sha_inner[MAX_MAC_LENGTH];
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
|
| + hashes->hashAlg = SEC_OID_UNKNOWN;
|
|
|
| #ifndef NO_PKCS11_BYPASS
|
| if (ss->opt.bypassPKCS11) {
|
| @@ -3939,9 +4345,9 @@
|
| MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size);
|
| MD5_Update(md5cx, md5_inner, MD5_LENGTH);
|
| }
|
| - MD5_End(md5cx, hashes->md5, &outLength, MD5_LENGTH);
|
| + MD5_End(md5cx, hashes->u.s.md5, &outLength, MD5_LENGTH);
|
|
|
| - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH));
|
| + PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH));
|
|
|
| if (!isTLS) {
|
| PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2,
|
| @@ -3953,16 +4359,58 @@
|
| SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size);
|
| SHA1_Update(shacx, sha_inner, SHA1_LENGTH);
|
| }
|
| - SHA1_End(shacx, hashes->sha, &outLength, SHA1_LENGTH);
|
| + SHA1_End(shacx, hashes->u.s.sha, &outLength, SHA1_LENGTH);
|
|
|
| - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH));
|
| + PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
|
|
|
| + hashes->len = MD5_LENGTH + SHA1_LENGTH;
|
| rv = SECSuccess;
|
| #undef md5cx
|
| #undef shacx
|
| } else
|
| #endif
|
| - {
|
| + if (ss->ssl3.hs.tls12_handshake_hash) {
|
| + PK11Context *h;
|
| + unsigned int stateLen;
|
| + 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.tls12_handshake_hash;
|
| + stateBuf = PK11_SaveContextAlloc(h, stackBuf,
|
| + sizeof(stackBuf), &stateLen);
|
| + if (stateBuf == NULL) {
|
| + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
|
| + goto tls12Loser;
|
| + }
|
| + rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len,
|
| + sizeof(hashes->u.raw));
|
| + if (rv != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
|
| + rv = SECFailure;
|
| + goto tls12Loser;
|
| + }
|
| + /* 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;
|
| + rv = SECSuccess;
|
| +
|
| +tls12Loser:
|
| + if (stateBuf) {
|
| + if (PK11_RestoreContext(ss->ssl3.hs.tls12_handshake_hash, stateBuf,
|
| + stateLen) != SECSuccess) {
|
| + ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
|
| + rv = SECFailure;
|
| + }
|
| + if (stateBuf != stackBuf) {
|
| + PORT_ZFree(stateBuf, stateLen);
|
| + }
|
| + }
|
| + } else {
|
| /* compute hases with PKCS11 */
|
| PK11Context * md5;
|
| PK11Context * sha = NULL;
|
| @@ -4051,7 +4499,7 @@
|
| rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size);
|
| rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH);
|
| }
|
| - rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH);
|
| + rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH);
|
| PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH);
|
| if (rv != SECSuccess) {
|
| ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
|
| @@ -4059,7 +4507,7 @@
|
| goto loser;
|
| }
|
|
|
| - PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH));
|
| + PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH));
|
|
|
| if (!isTLS) {
|
| PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2,
|
| @@ -4071,7 +4519,7 @@
|
| rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size);
|
| rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH);
|
| }
|
| - rv |= PK11_DigestFinal(sha, hashes->sha, &outLength, SHA1_LENGTH);
|
| + rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH);
|
| PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH);
|
| if (rv != SECSuccess) {
|
| ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
|
| @@ -4079,8 +4527,9 @@
|
| goto loser;
|
| }
|
|
|
| - PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH));
|
| + PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
|
|
|
| + hashes->len = MD5_LENGTH + SHA1_LENGTH;
|
| rv = SECSuccess;
|
|
|
| loser:
|
| @@ -5343,8 +5792,11 @@
|
| {
|
| SECStatus rv = SECFailure;
|
| PRBool isTLS;
|
| + PRBool isTLS12;
|
| SECItem buf = {siBuffer, NULL, 0};
|
| SSL3Hashes hashes;
|
| + unsigned int len;
|
| + SSL3SignatureAndHashAlgorithm sigAndHash;
|
|
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
| @@ -5360,6 +5812,7 @@
|
| }
|
|
|
| isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
|
| + isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2);
|
| if (ss->ssl3.platformClientKey) {
|
| #ifdef NSS_PLATFORM_CLIENT_AUTH
|
| rv = ssl3_PlatformSignHashes(
|
| @@ -5385,6 +5838,11 @@
|
| sid->u.ssl3.clAuthModuleID = PK11_GetModuleID(slot);
|
| sid->u.ssl3.clAuthValid = PR_TRUE;
|
| PK11_FreeSlot(slot);
|
| +
|
| + if (isTLS12) {
|
| + rv = ssl3_TLSSignatureAlgorithmForPrivateKey(
|
| + ss->ssl3.clientPrivateKey, &sigAndHash.sigAlg);
|
| + }
|
| }
|
| SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
|
| ss->ssl3.clientPrivateKey = NULL;
|
| @@ -5393,10 +5851,25 @@
|
| goto done; /* err code was set by ssl3_SignHashes */
|
| }
|
|
|
| - rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, buf.len + 2);
|
| + len = buf.len + 2 + (isTLS12 ? 2 : 0);
|
| +
|
| + rv = ssl3_AppendHandshakeHeader(ss, certificate_verify, len);
|
| if (rv != SECSuccess) {
|
| goto done; /* error code set by AppendHandshake */
|
| }
|
| + if (isTLS12) {
|
| + /* We always sign using the handshake hash function. It's possible that
|
| + * a server could support SHA-256 as the handshake hash but not as a
|
| + * signature hash. In that case we wouldn't be able to do client
|
| + * certificates with it. The alternative is to buffer all handshake
|
| + * messages. */
|
| + sigAndHash.hashAlg = hashes.hashAlg;
|
| +
|
| + rv = ssl3_AppendSignatureAndHashAlgorithm(ss, &sigAndHash);
|
| + if (rv != SECSuccess) {
|
| + goto done; /* err set by AppendHandshake. */
|
| + }
|
| + }
|
| rv = ssl3_AppendHandshakeVariable(ss, buf.data, buf.len, 2);
|
| if (rv != SECSuccess) {
|
| goto done; /* error code set by AppendHandshake */
|
| @@ -5504,6 +5977,12 @@
|
| }
|
| isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
|
|
|
| + rv = ssl3_InitTLS12HandshakeHash(ss);
|
| + if (rv != SECSuccess) {
|
| + desc = internal_error;
|
| + goto alert_loser;
|
| + }
|
| +
|
| rv = ssl3_ConsumeHandshake(
|
| ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
|
| if (rv != SECSuccess) {
|
| @@ -5840,7 +6319,10 @@
|
| SSL3AlertDescription desc = illegal_parameter;
|
| SSL3Hashes hashes;
|
| SECItem signature = {siBuffer, NULL, 0};
|
| + SSL3SignatureAndHashAlgorithm sigAndHash;
|
|
|
| + sigAndHash.hashAlg = SEC_OID_UNKNOWN;
|
| +
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake",
|
| SSL_GETPID(), ss->fd));
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
|
| @@ -5874,6 +6356,17 @@
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| }
|
| + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, &sigAndHash);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed or unsupported. */
|
| + }
|
| + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| + &sigAndHash, ss->sec.peerCert);
|
| + if (rv != SECSuccess) {
|
| + goto loser;
|
| + }
|
| + }
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| @@ -5891,7 +6384,7 @@
|
| /*
|
| * check to make sure the hash is signed by right guy
|
| */
|
| - rv = ssl3_ComputeExportRSAKeyHash(modulus, exponent,
|
| + rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg, modulus, exponent,
|
| &ss->ssl3.hs.client_random,
|
| &ss->ssl3.hs.server_random,
|
| &hashes, ss->opt.bypassPKCS11);
|
| @@ -5964,6 +6457,17 @@
|
| }
|
| if (dh_Ys.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_Ys))
|
| goto alert_loser;
|
| + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, &sigAndHash);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed or unsupported. */
|
| + }
|
| + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| + &sigAndHash, ss->sec.peerCert);
|
| + if (rv != SECSuccess) {
|
| + goto loser;
|
| + }
|
| + }
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| @@ -5985,7 +6489,7 @@
|
| /*
|
| * check to make sure the hash is signed by right guy
|
| */
|
| - rv = ssl3_ComputeDHKeyHash(dh_p, dh_g, dh_Ys,
|
| + 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);
|
| @@ -6862,6 +7366,12 @@
|
| goto alert_loser;
|
| }
|
|
|
| + rv = ssl3_InitTLS12HandshakeHash(ss);
|
| + if (rv != SECSuccess) {
|
| + desc = internal_error;
|
| + goto alert_loser;
|
| + }
|
| +
|
| /* grab the client random data. */
|
| rv = ssl3_ConsumeHandshake(
|
| ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
|
| @@ -7703,6 +8213,12 @@
|
| ss->sec.ci.sid = sid;
|
| /* do not worry about memory leak of sid since it now belongs to ci */
|
|
|
| + rv = ssl3_InitTLS12HandshakeHash(ss);
|
| + if (rv != SECSuccess) {
|
| + desc = internal_error;
|
| + goto alert_loser;
|
| + }
|
| +
|
| /* We have to update the handshake hashes before we can send stuff */
|
| rv = ssl3_UpdateHandshakeHashes(ss, buffer, length);
|
| if (rv != SECSuccess) {
|
| @@ -7851,7 +8367,83 @@
|
| return SECSuccess;
|
| }
|
|
|
| +/* ssl3_PickSignatureHashFunction selects a hash function to use when signing
|
| + * elements of the handshake. Prior to TLS 1.2, the MD5/SHA1 combination is
|
| + * always used. With TLS 1.2, a client may advertise its support for signature
|
| + * and hash combinations. */
|
| +SECStatus
|
| +ssl3_PickSignatureHashFunction(sslSocket *ss,
|
| + SSL3SignatureAndHashAlgorithm* out)
|
| +{
|
| + TLS12SignatureAlgorithm sigAlg;
|
| + unsigned int i, j;
|
| + /* hashPreference expresses our preferences for hash functions, most
|
| + * preferable first. */
|
| + static const PRUint8 hashPreference[] = {
|
| + tls_hash_sha256,
|
| + tls_hash_sha384,
|
| + tls_hash_sha512,
|
| + tls_hash_sha1,
|
| + };
|
|
|
| + switch (ss->ssl3.hs.kea_def->kea) {
|
| + case kea_rsa:
|
| + case kea_rsa_export:
|
| + case kea_rsa_export_1024:
|
| + case kea_dhe_rsa:
|
| + case kea_dhe_rsa_export:
|
| + case kea_rsa_fips:
|
| + case kea_ecdh_rsa:
|
| + case kea_ecdhe_rsa:
|
| + sigAlg = tls_sig_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;
|
| + case kea_ecdh_ecdsa:
|
| + case kea_ecdhe_ecdsa:
|
| + sigAlg = tls_sig_ecdsa;
|
| + break;
|
| + default:
|
| + 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;
|
| + }
|
| +
|
| + 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;
|
| + }
|
| +
|
| +
|
| + for (i = 0; i < sizeof(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 = *sh;
|
| + return SECSuccess;
|
| + }
|
| + }
|
| + }
|
| +
|
| + return SECFailure;
|
| +}
|
| +
|
| +
|
| static SECStatus
|
| ssl3_SendServerKeyExchange(sslSocket *ss)
|
| {
|
| @@ -7862,6 +8454,7 @@
|
| SECItem signed_hash = {siBuffer, NULL, 0};
|
| SSL3Hashes hashes;
|
| SECKEYPublicKey * sdPub; /* public key for step-down */
|
| + SSL3SignatureAndHashAlgorithm sigAndHash;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -7869,6 +8462,11 @@
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
|
| PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
|
|
|
| + if (SECSuccess != ssl3_PickSignatureHashFunction(ss, &sigAndHash)) {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| +
|
| switch (kea_def->exchKeyType) {
|
| case kt_rsa:
|
| /* Perform SSL Step-Down here. */
|
| @@ -7878,7 +8476,8 @@
|
| PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
|
| return SECFailure;
|
| }
|
| - rv = ssl3_ComputeExportRSAKeyHash(sdPub->u.rsa.modulus,
|
| + rv = ssl3_ComputeExportRSAKeyHash(sigAndHash.hashAlg,
|
| + sdPub->u.rsa.modulus,
|
| sdPub->u.rsa.publicExponent,
|
| &ss->ssl3.hs.client_random,
|
| &ss->ssl3.hs.server_random,
|
| @@ -7921,6 +8520,13 @@
|
| goto loser; /* err set by AppendHandshake. */
|
| }
|
|
|
| + if (ss->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) {
|
| @@ -8046,6 +8652,7 @@
|
| int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
|
| SSL3AlertDescription desc = handshake_failure;
|
| PRBool isTLS;
|
| + SSL3SignatureAndHashAlgorithm sigAndHash;
|
|
|
| SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
|
| SSL_GETPID(), ss->fd));
|
| @@ -8058,6 +8665,26 @@
|
| goto alert_loser;
|
| }
|
|
|
| + if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
|
| + &sigAndHash);
|
| + if (rv != SECSuccess) {
|
| + goto loser; /* malformed or unsupported. */
|
| + }
|
| + rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
|
| + &sigAndHash, ss->sec.peerCert);
|
| + if (rv != SECSuccess) {
|
| + goto loser;
|
| + }
|
| +
|
| + /* We only support CertificateVerify messages that use the handshake
|
| + * hash. */
|
| + if (sigAndHash.hashAlg != hashes->hashAlg) {
|
| + PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_FUNCTION);
|
| + return SECFailure;
|
| + }
|
| + }
|
| +
|
| rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
|
| if (rv != SECSuccess) {
|
| goto loser; /* malformed. */
|
| @@ -9173,8 +9800,8 @@
|
| label = isServer ? "server finished" : "client finished";
|
| len = 15;
|
|
|
| - rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->md5,
|
| - sizeof *hashes, tlsFinished->verify_data,
|
| + rv = ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw,
|
| + hashes->len, tlsFinished->verify_data,
|
| sizeof tlsFinished->verify_data);
|
|
|
| return rv;
|
| @@ -9193,9 +9820,13 @@
|
|
|
| if (spec->master_secret && !spec->bypassCiphers) {
|
| SECItem param = {siBuffer, NULL, 0};
|
| + CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL;
|
| + if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
|
| + mech = CKM_NSS_TLS_PRF_GENERAL_SHA256;
|
| + }
|
| PK11Context *prf_context =
|
| - PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN,
|
| - spec->master_secret, ¶m);
|
| + PK11_CreateContextBySymKey(mech, CKA_SIGN, spec->master_secret,
|
| + ¶m);
|
| unsigned int retLen;
|
|
|
| if (!prf_context)
|
| @@ -9529,15 +10160,19 @@
|
| if (rv != SECSuccess)
|
| goto fail; /* err set by AppendHandshake. */
|
| } else {
|
| - if (isServer)
|
| - ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes;
|
| - else
|
| - ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes;
|
| - ss->ssl3.hs.finishedBytes = sizeof hashes;
|
| - rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes);
|
| + unsigned char *ssl3FinishedStorage;
|
| +
|
| + if (isServer) {
|
| + ssl3FinishedStorage = &ss->ssl3.hs.finishedMsgs.sFinished[1][0];
|
| + } else {
|
| + ssl3FinishedStorage = &ss->ssl3.hs.finishedMsgs.sFinished[0][0];
|
| + }
|
| + memcpy(ssl3FinishedStorage, hashes.u.raw, hashes.len);
|
| + ss->ssl3.hs.finishedBytes = hashes.len;
|
| + rv = ssl3_AppendHandshakeHeader(ss, finished, hashes.len);
|
| if (rv != SECSuccess)
|
| goto fail; /* err set by AppendHandshake. */
|
| - rv = ssl3_AppendHandshake(ss, &hashes, sizeof hashes);
|
| + rv = ssl3_AppendHandshake(ss, hashes.u.raw, hashes.len);
|
| if (rv != SECSuccess)
|
| goto fail; /* err set by AppendHandshake. */
|
| }
|
| @@ -9686,18 +10321,22 @@
|
| return SECFailure;
|
| }
|
| } else {
|
| - if (length != sizeof(SSL3Hashes)) {
|
| + unsigned char *ssl3FinishedStorage;
|
| +
|
| + if (length != hashes->len) {
|
| (void)ssl3_IllegalParameter(ss);
|
| PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
|
| return SECFailure;
|
| }
|
|
|
| - if (!isServer)
|
| - ss->ssl3.hs.finishedMsgs.sFinished[1] = *hashes;
|
| - else
|
| - ss->ssl3.hs.finishedMsgs.sFinished[0] = *hashes;
|
| - ss->ssl3.hs.finishedBytes = sizeof *hashes;
|
| - if (0 != NSS_SecureMemcmp(hashes, b, length)) {
|
| + if (!isServer) {
|
| + ssl3FinishedStorage = &ss->ssl3.hs.finishedMsgs.sFinished[1][0];
|
| + } else {
|
| + ssl3FinishedStorage = &ss->ssl3.hs.finishedMsgs.sFinished[0][0];
|
| + }
|
| + memcpy(ssl3FinishedStorage, hashes->u.raw, hashes->len);
|
| + ss->ssl3.hs.finishedBytes = hashes->len;
|
| + if (0 != NSS_SecureMemcmp(hashes->u.raw, b, length)) {
|
| (void)ssl3_HandshakeFailure(ss);
|
| PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
|
| return SECFailure;
|
| @@ -11286,6 +11925,12 @@
|
| if (ss->ssl3.hs.sha) {
|
| PK11_DestroyContext(ss->ssl3.hs.sha,PR_TRUE);
|
| }
|
| + if (ss->ssl3.hs.tls12_handshake_hash) {
|
| + PK11_DestroyContext(ss->ssl3.hs.tls12_handshake_hash,PR_TRUE);
|
| + }
|
| + if (ss->ssl3.hs.clientSigAndHash) {
|
| + PORT_Free(ss->ssl3.hs.clientSigAndHash);
|
| + }
|
| if (ss->ssl3.hs.messages.buf) {
|
| PORT_Free(ss->ssl3.hs.messages.buf);
|
| ss->ssl3.hs.messages.buf = NULL;
|
|
|