--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -9,16 +9,17 @@
/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */
#include "cert.h"
#include "ssl.h"
#include "cryptohi.h" /* for DSAU_ stuff */
#include "keyhi.h"
#include "secder.h"
#include "secitem.h"
+#include "sechash.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "sslerr.h"
#include "prtime.h"
#include "prinrval.h"
#include "prerror.h"
#include "pratom.h"
@@ -57,16 +58,17 @@ static SECStatus ssl3_SendFinished(
static SECStatus ssl3_SendServerHello( sslSocket *ss);
static SECStatus ssl3_SendServerHelloDone( sslSocket *ss);
static SECStatus ssl3_SendServerKeyExchange( sslSocket *ss);
static SECStatus ssl3_NewHandshakeHashes( sslSocket *ss);
static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss,
const unsigned char *b,
unsigned int l);
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,
int inputLen);
#define MAX_SEND_BUF_LENGTH 32000 /* watch for 16-bit integer overflow */
#define MIN_SEND_BUF_LENGTH 4000
@@ -804,51 +806,70 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEY
PRBool isTLS)
{
SECStatus rv = SECFailure;
PRBool doDerEncode = PR_FALSE;
int signatureLen;
SECItem hashItem;
buf->data = NULL;
- signatureLen = PK11_SignatureLen(key);
- if (signatureLen <= 0) {
- PORT_SetError(SEC_ERROR_INVALID_KEY);
- goto done;
- }
-
- buf->len = (unsigned)signatureLen;
- buf->data = (unsigned char *)PORT_Alloc(signatureLen);
- if (!buf->data)
- goto done; /* error code was set. */
switch (key->keyType) {
case rsaKey:
- hashItem.data = hash->md5;
- hashItem.len = sizeof(SSL3Hashes);
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->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:
PORT_SetError(SEC_ERROR_INVALID_KEY);
goto done;
}
PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
- rv = PK11_Sign(key, buf, &hashItem);
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ signatureLen = PK11_SignatureLen(key);
+ if (signatureLen <= 0) {
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ goto done;
+ }
+
+ buf->len = (unsigned)signatureLen;
+ buf->data = (unsigned char *)PORT_Alloc(signatureLen);
+ if (!buf->data)
+ goto done; /* error code was set. */
+
+ rv = PK11_Sign(key, buf, &hashItem);
+ } else {
+ rv = SGN_Digest(key, hash->hashAlg, buf, &hashItem);
+ }
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
} else if (doDerEncode) {
SECItem derSig = {siBuffer, NULL, 0};
/* This also works for an ECDSA signature */
rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
if (rv == SECSuccess) {
@@ -872,135 +893,187 @@ done:
SECStatus
ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert,
SECItem *buf, PRBool isTLS, void *pwArg)
{
SECKEYPublicKey * key;
SECItem * signature = NULL;
SECStatus rv;
SECItem hashItem;
-#ifdef NSS_ENABLE_ECC
- unsigned int len;
-#endif /* NSS_ENABLE_ECC */
+ SECOidTag encAlg;
+ SECOidTag hashAlg;
PRINT_BUF(60, (NULL, "check signed hashes",
buf->data, buf->len));
key = CERT_ExtractPublicKey(cert);
if (key == NULL) {
ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
return SECFailure;
}
+ hashAlg = hash->hashAlg;
switch (key->keyType) {
case rsaKey:
- hashItem.data = hash->md5;
- hashItem.len = sizeof(SSL3Hashes);
+ encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ hashItem.data = hash->u.raw;
+ hashItem.len = hash->len;
break;
case dsaKey:
- hashItem.data = hash->sha;
- hashItem.len = sizeof(hash->sha);
+ encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
+ /* 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);
if (!signature) {
PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
return SECFailure;
}
buf = signature;
}
break;
#ifdef NSS_ENABLE_ECC
case ecKey:
- hashItem.data = hash->sha;
- hashItem.len = sizeof(hash->sha);
- /*
- * ECDSA signatures always encode the integers r and s
- * using ASN (unlike DSA where ASN encoding is used
- * with TLS but not with SSL3)
+ encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ /* SEC_OID_UNKNOWN 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.
*/
- len = SECKEY_SignatureLen(key);
- if (len == 0) {
- SECKEY_DestroyPublicKey(key);
- PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
- return SECFailure;
- }
- signature = DSAU_DecodeDerSigToLen(buf, len);
- if (!signature) {
- PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
- return SECFailure;
- }
- buf = signature;
+ if (hash->hashAlg == SEC_OID_UNKNOWN) {
+ hashAlg = SEC_OID_SHA1;
+ 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:
SECKEY_DestroyPublicKey(key);
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
return SECFailure;
}
PRINT_BUF(60, (NULL, "hash(es) to be verified",
hashItem.data, hashItem.len));
- rv = PK11_Verify(key, buf, &hashItem, pwArg);
+ if (hashAlg == SEC_OID_UNKNOWN || key->keyType == dsaKey) {
+ /* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded.
+ * DSA signatures are DER-encoded in TLS but not in SSL3 and the code
+ * above always removes the DER encoding of DSA signatures when
+ * present. Thus DSA signatures are always verified with PK11_Verify.
+ */
+ rv = PK11_Verify(key, buf, &hashItem, pwArg);
+ } else {
+ rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg,
+ pwArg);
+ }
SECKEY_DestroyPublicKey(key);
if (signature) {
SECITEM_FreeItem(signature, PR_TRUE);
}
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
return rv;
}
/* Caller must set hiLevel error code. */
/* Called from ssl3_ComputeExportRSAKeyHash
* ssl3_ComputeDHKeyHash
* 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.
*/
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 if (hashAlg == SEC_OID_SHA384) {
+ SHA384_HashBuf(hashes->u.raw, hashBuf, bufLen);
+ hashes->len = SHA384_LENGTH;
+ } else {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ 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;
- }
-
- rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen);
- if (rv != SECSuccess) {
- ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
- rv = SECFailure;
- }
- }
+ 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;
+ }
+ }
+ }
+ hashes->hashAlg = hashAlg;
+
done:
return rv;
}
/* Caller must set hiLevel error code.
** Called from ssl3_SendServerKeyExchange and
** 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)
{
PRUint8 * hashBuf;
PRUint8 * pBuf;
SECStatus rv = SECSuccess;
unsigned int bufLen;
PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 4096/8 + 2 + 4096/8];
@@ -1026,33 +1099,42 @@ ssl3_ComputeExportRSAKeyHash(SECItem mod
pBuf += modulus.len;
pBuf[0] = (PRUint8)(publicExponent.len >> 8);
pBuf[1] = (PRUint8)(publicExponent.len);
pBuf += 2;
memcpy(pBuf, publicExponent.data, publicExponent.len);
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: result",
+ hashes->u.raw, hashes->len));
+ }
if (hashBuf != buf && hashBuf != NULL)
PORT_Free(hashBuf);
return rv;
}
/* Caller must set hiLevel error code. */
/* Called from ssl3_HandleServerKeyExchange. */
static SECStatus
-ssl3_ComputeDHKeyHash(SECItem dh_p, SECItem dh_g, SECItem dh_Ys,
- SSL3Random *client_rand, SSL3Random *server_rand,
- SSL3Hashes *hashes, 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;
SECStatus rv = SECSuccess;
unsigned int bufLen;
PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 4096/8 + 2 + 4096/8];
bufLen = 2*SSL3_RANDOM_LENGTH + 2 + dh_p.len + 2 + dh_g.len + 2 + dh_Ys.len;
@@ -1081,21 +1163,29 @@ ssl3_ComputeDHKeyHash(SECItem dh_p, SECI
pBuf += dh_g.len;
pBuf[0] = (PRUint8)(dh_Ys.len >> 8);
pBuf[1] = (PRUint8)(dh_Ys.len);
pBuf += 2;
memcpy(pBuf, dh_Ys.data, dh_Ys.len);
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: result",
+ hashes->u.raw, hashes->len));
+ }
if (hashBuf != buf && hashBuf != NULL)
PORT_Free(hashBuf);
return rv;
}
static void
ssl3_BumpSequenceNumber(SSL3SequenceNumber *num)
@@ -3172,16 +3262,18 @@ static SECStatus
ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms)
{
ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
const ssl3KEADef *kea_def= ss->ssl3.hs.kea_def;
unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
(pwSpec->version > SSL_LIBRARY_VERSION_3_0));
+ PRBool 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.
*/
PRBool isDH = (PRBool) ((ss->ssl3.hs.kea_def->exchKeyType == kt_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == kt_ecdh));
SECStatus rv = SECFailure;
@@ -3190,17 +3282,22 @@ ssl3_DeriveMasterSecret(sslSocket *ss, P
SECItem params;
CK_FLAGS keyFlags;
CK_VERSION pms_version;
CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
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;
keyFlags = CKF_SIGN | CKF_VERIFY;
} else {
if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
@@ -3348,16 +3445,18 @@ static SECStatus
ssl3_DeriveConnectionKeysPKCS11(sslSocket *ss)
{
ssl3CipherSpec * pwSpec = ss->ssl3.pwSpec;
const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
unsigned char * cr = (unsigned char *)&ss->ssl3.hs.client_random;
unsigned char * sr = (unsigned char *)&ss->ssl3.hs.server_random;
PRBool isTLS = (PRBool)(kea_def->tls_keygen ||
(pwSpec->version > SSL_LIBRARY_VERSION_3_0));
+ 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;
PK11SymKey * symKey = NULL;
void * pwArg = ss->pkcs11PinArg;
int keySize;
CK_SSL3_KEY_MAT_PARAMS key_material_params;
CK_SSL3_KEY_MAT_OUT returnedKeys;
@@ -3405,17 +3504,19 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocke
calg = cipher_def->calg;
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 (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;
}
/* 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,
@@ -3462,29 +3563,73 @@ ssl3_DeriveConnectionKeysPKCS11(sslSocke
loser:
if (symKey) PK11_FreeSymKey(symKey);
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
+/* ssl3_InitTLS12HandshakeHash creates a handshake hash context 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 ||
+ PK11_DigestBegin(ss->ssl3.hs.tls12_handshake_hash) != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ if (ss->ssl3.hs.tls12_handshake_hash && ss->ssl3.hs.messages.len > 0) {
+ if (PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash,
+ ss->ssl3.hs.messages.buf,
+ ss->ssl3.hs.messages.len) != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ 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);
return rv;
}
rv = PK11_DigestBegin(ss->ssl3.hs.sha);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
@@ -3501,34 +3646,30 @@ ssl3_NewHandshakeHashes(sslSocket *ss)
PK11Context *sha = NULL;
/*
* note: We should probably lookup an SSL3 slot for these
* handshake hashes in hopes that we wind up with the same slots
* 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;
}
loser:
if (md5 != NULL) {
PK11_DestroyContext(md5, PR_TRUE);
@@ -3556,35 +3697,54 @@ ssl3_UpdateHandshakeHashes(sslSocket *ss
unsigned int l)
{
SECStatus rv = SECSuccess;
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
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);
SHA1_Update((SHA1Context *)ss->ssl3.hs.sha_cx, b, l);
#if defined(NSS_SURVIVE_DOUBLE_BYPASS_FAILURE)
rv = sslBuffer_Append(&ss->ssl3.hs.messages, b, l);
#endif
return rv;
}
#endif
- 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;
+ if (ss->ssl3.hs.tls12_handshake_hash) {
+ rv = PK11_DigestOp(ss->ssl3.hs.tls12_handshake_hash, b, l);
+ if (rv != SECSuccess) {
+ ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ return rv;
+ }
+ } 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;
+ }
}
return rv;
}
/**************************************************************************
* Append Handshake functions.
* All these functions set appropriate error codes.
* Most rely on ssl3_AppendHandshake to set the error code.
@@ -3726,16 +3886,35 @@ ssl3_AppendHandshakeHeader(sslSocket *ss
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshake, if applicable. */
}
}
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_OIDToTLSHashAlgorithm(sigAndHash->hashAlg);
+ if (serialized[0] == 0) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+
+ serialized[1] = sigAndHash->sigAlg;
+
+ return ssl3_AppendHandshake(ss, serialized, sizeof(serialized));
+}
+
/**************************************************************************
* Consume Handshake functions.
*
* All data used in these functions is protected by two locks,
* the RecvBufLock and the SSL3HandshakeLock
**************************************************************************/
/* Read up the next "bytes" number of bytes from the (decrypted) input
@@ -3832,16 +4011,157 @@ ssl3_ConsumeHandshakeVariable(sslSocket
i->data = *b;
i->len = count;
*b += count;
*length -= count;
}
return SECSuccess;
}
+/* tlsHashOIDMap contains the mapping between TLS hash identifiers and the
+ * SECOidTag used internally by NSS. */
+static const struct {
+ int 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 }
+};
+
+/* ssl3_TLSHashAlgorithmToOID 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_TLSHashAlgorithmToOID(int hashFunc)
+{
+ unsigned int i;
+
+ for (i = 0; i < PR_ARRAY_SIZE(tlsHashOIDMap); i++) {
+ if (hashFunc == tlsHashOIDMap[i].tlsHash) {
+ return tlsHashOIDMap[i].oid;
+ }
+ }
+ 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)
+{
+ 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;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_KEY);
+ return SECFailure;
+ }
+}
+
+/* ssl3_TLSSignatureAlgorithmForCertificate returns the TLS 1.2 signature
+ * algorithm identifier for the given certificate. */
+static SECStatus
+ssl3_TLSSignatureAlgorithmForCertificate(CERTCertificate *cert,
+ TLSSignatureAlgorithm *out)
+{
+ SECKEYPublicKey *key;
+ KeyType keyType;
+
+ key = CERT_ExtractPublicKey(cert);
+ if (key == NULL) {
+ ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ keyType = key->keyType;
+ SECKEY_DestroyPublicKey(key);
+ return ssl3_TLSSignatureAlgorithmForKeyType(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;
+ TLSSignatureAlgorithm sigAlg;
+
+ rv = ssl3_TLSSignatureAlgorithmForCertificate(cert, &sigAlg);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ 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_TLSHashAlgorithmToOID(bytes[0]);
+ if (out->hashAlg == SEC_OID_UNKNOWN) {
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+ }
+
+ out->sigAlg = bytes[1];
+ return SECSuccess;
+}
+
/**************************************************************************
* end of Consume Handshake functions.
**************************************************************************/
/* Extract the hashes of handshake messages to this point.
* Called from ssl3_SendCertificateVerify
* ssl3_SendFinished
* ssl3_HandleHandshakeMessage
@@ -3858,16 +4178,17 @@ ssl3_ComputeHandshakeHashes(sslSocket *
{
SECStatus rv = SECSuccess;
PRBool isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0);
unsigned int outLength;
SSL3Opaque md5_inner[MAX_MAC_LENGTH];
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) {
/* compute them without PKCS11 */
PRUint64 md5_cx[MAX_MAC_CONTEXT_LLONGS];
PRUint64 sha_cx[MAX_MAC_CONTEXT_LLONGS];
#define md5cx ((MD5Context *)md5_cx)
@@ -3921,40 +4242,82 @@ ssl3_ComputeHandshakeHashes(sslSocket *
mac_defs[mac_md5].pad_size));
PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH));
MD5_Begin(md5cx);
MD5_Update(md5cx, spec->msItem.data, spec->msItem.len);
MD5_Update(md5cx, mac_pad_2, mac_defs[mac_md5].pad_size);
MD5_Update(md5cx, md5_inner, MD5_LENGTH);
}
- MD5_End(md5cx, hashes->md5, &outLength, MD5_LENGTH);
-
- PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->md5, MD5_LENGTH));
+ MD5_End(md5cx, hashes->u.s.md5, &outLength, 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,
mac_defs[mac_sha].pad_size));
PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH));
SHA1_Begin(shacx);
SHA1_Update(shacx, spec->msItem.data, spec->msItem.len);
SHA1_Update(shacx, mac_pad_2, mac_defs[mac_sha].pad_size);
SHA1_Update(shacx, sha_inner, SHA1_LENGTH);
}
- SHA1_End(shacx, hashes->sha, &outLength, SHA1_LENGTH);
-
- PRINT_BUF(60, (NULL, "SHA outer: result", hashes->sha, SHA1_LENGTH));
-
+ SHA1_End(shacx, hashes->u.s.sha, &outLength, 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 tls12_loser;
+ }
+ 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 tls12_loser;
+ }
+ /* 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;
+
+tls12_loser:
+ 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;
unsigned char *md5StateBuf = NULL;
unsigned char *shaStateBuf = NULL;
unsigned int md5StateLen, shaStateLen;
unsigned char md5StackBuf[256];
unsigned char shaStackBuf[512];
@@ -4033,46 +4396,47 @@ ssl3_ComputeHandshakeHashes(sslSocket *
mac_defs[mac_md5].pad_size));
PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH));
rv |= PK11_DigestBegin(md5);
rv |= PK11_DigestKey(md5, spec->master_secret);
rv |= PK11_DigestOp(md5, mac_pad_2, mac_defs[mac_md5].pad_size);
rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH);
}
- rv |= PK11_DigestFinal(md5, hashes->md5, &outLength, MD5_LENGTH);
+ 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);
rv = SECFailure;
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,
mac_defs[mac_sha].pad_size));
PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH));
rv |= PK11_DigestBegin(sha);
rv |= PK11_DigestKey(sha,spec->master_secret);
rv |= PK11_DigestOp(sha, mac_pad_2, mac_defs[mac_sha].pad_size);
rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH);
}
- 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);
rv = SECFailure;
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:
if (md5StateBuf) {
if (PK11_RestoreContext(ss->ssl3.hs.md5, md5StateBuf, md5StateLen)
!= SECSuccess)
{
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
@@ -5325,33 +5689,39 @@ loser:
}
/* Called from ssl3_HandleServerHelloDone(). */
static SECStatus
ssl3_SendCertificateVerify(sslSocket *ss)
{
SECStatus rv = SECFailure;
PRBool isTLS;
+ PRBool isTLS12;
SECItem buf = {siBuffer, NULL, 0};
SSL3Hashes hashes;
+ KeyType keyType;
+ unsigned int len;
+ SSL3SignatureAndHashAlgorithm sigAndHash;
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: send certificate_verify handshake",
SSL_GETPID(), ss->fd));
ssl_GetSpecReadLock(ss);
rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
goto done; /* err code was set by ssl3_ComputeHandshakeHashes */
}
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+ keyType = ss->ssl3.clientPrivateKey->keyType;
rv = ssl3_SignHashes(&hashes, ss->ssl3.clientPrivateKey, &buf, isTLS);
if (rv == SECSuccess) {
PK11SlotInfo * slot;
sslSessionID * sid = ss->sec.ci.sid;
/* Remember the info about the slot that did the signing.
** Later, when doing an SSL restart handshake, verify this.
** These calls are mere accessors, and can't fail.
@@ -5364,20 +5734,40 @@ ssl3_SendCertificateVerify(sslSocket *ss
PK11_FreeSlot(slot);
}
SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
ss->ssl3.clientPrivateKey = NULL;
if (rv != SECSuccess) {
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) {
+ rv = ssl3_TLSSignatureAlgorithmForKeyType(keyType,
+ &sigAndHash.sigAlg);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ /* 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 */
}
done:
if (buf.data)
PORT_Free(buf.data);
@@ -5460,16 +5850,23 @@ ssl3_HandleServerHello(sslSocket *ss, SS
if (rv != SECSuccess) {
desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
: handshake_failure;
errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
goto alert_loser;
}
isTLS = (ss->version > SSL_LIBRARY_VERSION_3_0);
+ rv = ssl3_InitTLS12HandshakeHash(ss);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+
rv = ssl3_ConsumeHandshake(
ss, &ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH, &b, &length);
if (rv != SECSuccess) {
goto loser; /* alert has been sent */
}
rv = ssl3_ConsumeHandshakeVariable(ss, &sidBytes, 1, &b, &length);
if (rv != SECSuccess) {
@@ -5768,22 +6165,25 @@ ssl3_BigIntGreaterThanOne(const SECItem*
* ssl3 ServerKeyExchange message.
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
PLArenaPool * arena = NULL;
SECKEYPublicKey *peerKey = NULL;
- PRBool isTLS;
+ PRBool isTLS, isTLS12;
SECStatus rv;
int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
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) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
if (ss->ssl3.hs.ws != wait_server_key &&
ss->ssl3.hs.ws != wait_server_cert) {
@@ -5793,31 +6193,44 @@ ssl3_HandleServerKeyExchange(sslSocket *
}
if (ss->sec.peerCert == NULL) {
errCode = SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH;
desc = unexpected_message;
goto alert_loser;
}
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
switch (ss->ssl3.hs.kea_def->exchKeyType) {
case kt_rsa: {
SECItem modulus = {siBuffer, NULL, 0};
SECItem exponent = {siBuffer, NULL, 0};
rv = ssl3_ConsumeHandshakeVariable(ss, &modulus, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
rv = ssl3_ConsumeHandshakeVariable(ss, &exponent, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
+ if (isTLS12) {
+ 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. */
}
if (length != 0) {
if (isTLS)
desc = decode_error;
goto alert_loser; /* malformed. */
@@ -5825,17 +6238,17 @@ ssl3_HandleServerKeyExchange(sslSocket *
/* failures after this point are not malformed handshakes. */
/* TLS: send decrypt_error if signature failed. */
desc = isTLS ? decrypt_error : handshake_failure;
/*
* check to make sure the hash is signed by right guy
*/
- rv = ssl3_ComputeExportRSAKeyHash(modulus, exponent,
+ 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);
goto alert_loser;
}
@@ -5898,16 +6311,28 @@ ssl3_HandleServerKeyExchange(sslSocket *
if (dh_g.len > dh_p.len || !ssl3_BigIntGreaterThanOne(&dh_g))
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))
goto alert_loser;
+ if (isTLS12) {
+ 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. */
}
if (length != 0) {
if (isTLS)
desc = decode_error;
goto alert_loser; /* malformed. */
@@ -5919,17 +6344,17 @@ ssl3_HandleServerKeyExchange(sslSocket *
/* failures after this point are not malformed handshakes. */
/* TLS: send decrypt_error if signature failed. */
desc = isTLS ? decrypt_error : handshake_failure;
/*
* check to make sure the hash is signed by right guy
*/
- rv = ssl3_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);
if (rv != SECSuccess) {
errCode =
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto alert_loser;
}
@@ -6647,16 +7072,23 @@ ssl3_HandleClientHello(sslSocket *ss, SS
rv = ssl3_NegotiateVersion(ss, version, PR_TRUE);
if (rv != SECSuccess) {
desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version
: handshake_failure;
errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
goto alert_loser;
}
+ rv = ssl3_InitTLS12HandshakeHash(ss);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+
/* grab the client random data. */
rv = ssl3_ConsumeHandshake(
ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed */
}
/* grab the client's SID, if present. */
@@ -7388,16 +7820,23 @@ ssl3_HandleV2ClientHello(sslSocket *ss,
rv = ssl3_NegotiateVersion(ss, version, PR_TRUE);
if (rv != SECSuccess) {
/* send back which ever alert client will understand. */
desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version : handshake_failure;
errCode = SSL_ERROR_NO_CYPHER_OVERLAP;
goto alert_loser;
}
+ rv = ssl3_InitTLS12HandshakeHash(ss);
+ if (rv != SECSuccess) {
+ desc = internal_error;
+ errCode = PORT_GetError();
+ goto alert_loser;
+ }
+
/* if we get a non-zero SID, just ignore it. */
if (length !=
SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length + rand_length) {
SSL_DBG(("%d: SSL3[%d]: bad v2 client hello message, len=%d should=%d",
SSL_GETPID(), ss->fd, length,
SSL_HL_CLIENT_HELLO_HBYTES + suite_length + sid_length +
rand_length));
goto loser; /* malformed */ /* alert_loser */
@@ -7635,44 +8074,129 @@ ssl3_SendServerHello(sslSocket *ss)
rv = ssl3_SetupPendingCipherSpec(ss);
if (rv != SECSuccess) {
return rv; /* err set by ssl3_SetupPendingCipherSpec */
}
return SECSuccess;
}
+/* 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
+ * used. With TLS 1.2, a client may advertise its support for signature and
+ * hash combinations. */
+static SECStatus
+ssl3_PickSignatureHashAlgorithm(sslSocket *ss,
+ SSL3SignatureAndHashAlgorithm* out)
+{
+ TLSSignatureAlgorithm sigAlg;
+ unsigned int i, j;
+ /* hashPreference expresses our preferences for hash algorithms, 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_dh_rsa:
+ case kea_dh_rsa_export:
+ 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 < 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;
+ }
+ }
+ }
+
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
+ return SECFailure;
+}
+
static SECStatus
ssl3_SendServerKeyExchange(sslSocket *ss)
{
const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
SECStatus rv = SECFailure;
int length;
PRBool isTLS;
SECItem signed_hash = {siBuffer, NULL, 0};
SSL3Hashes hashes;
SECKEYPublicKey * sdPub; /* public key for step-down */
+ SSL3SignatureAndHashAlgorithm sigAndHash;
SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake",
SSL_GETPID(), ss->fd));
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
+ if (ssl3_PickSignatureHashAlgorithm(ss, &sigAndHash) != SECSuccess) {
+ return SECFailure;
+ }
+
switch (kea_def->exchKeyType) {
case kt_rsa:
/* Perform SSL Step-Down here. */
sdPub = ss->stepDownKeyPair->pubKey;
PORT_Assert(sdPub != NULL);
if (!sdPub) {
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,
&hashes, ss->opt.bypassPKCS11);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
return rv;
}
@@ -7705,27 +8229,34 @@ ssl3_SendServerKeyExchange(sslSocket *ss
rv = ssl3_AppendHandshakeVariable(
ss, sdPub->u.rsa.publicExponent.data,
sdPub->u.rsa.publicExponent.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);
return SECSuccess;
#ifdef NSS_ENABLE_ECC
case kt_ecdh: {
- rv = ssl3_SendECDHServerKeyExchange(ss);
+ rv = ssl3_SendECDHServerKeyExchange(ss, &sigAndHash);
return rv;
}
#endif /* NSS_ENABLE_ECC */
case kt_dh:
case kt_null:
default:
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
@@ -7829,36 +8360,61 @@ ssl3_SendServerHelloDone(sslSocket *ss)
static SECStatus
ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
SSL3Hashes *hashes)
{
SECItem signed_hash = {siBuffer, NULL, 0};
SECStatus rv;
int errCode = SSL_ERROR_RX_MALFORMED_CERT_VERIFY;
SSL3AlertDescription desc = handshake_failure;
- PRBool isTLS;
+ PRBool isTLS, isTLS12;
+ SSL3SignatureAndHashAlgorithm sigAndHash;
SSL_TRC(3, ("%d: SSL3[%d]: handle certificate_verify handshake",
SSL_GETPID(), ss->fd));
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
+
if (ss->ssl3.hs.ws != wait_cert_verify || ss->sec.peerCert == NULL) {
desc = unexpected_message;
errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY;
goto alert_loser;
}
+ if (isTLS12) {
+ 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) {
+ errCode = PORT_GetError();
+ desc = decrypt_error;
+ goto alert_loser;
+ }
+
+ /* We only support CertificateVerify messages that use the handshake
+ * hash. */
+ if (sigAndHash.hashAlg != hashes->hashAlg) {
+ errCode = SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM;
+ desc = decrypt_error;
+ goto alert_loser;
+ }
+ }
+
rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
if (rv != SECSuccess) {
goto loser; /* malformed. */
}
- isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
-
/* XXX verify that the key & kea match */
rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
isTLS, ss->pkcs11PinArg);
if (rv != SECSuccess) {
errCode = PORT_GetError();
desc = isTLS ? decrypt_error : handshake_failure;
goto alert_loser;
}
@@ -8927,28 +9483,28 @@ done:
ssl_ReleaseRecvBufLock(ss);
return rv;
}
static SECStatus
ssl3_ComputeTLSFinished(ssl3CipherSpec *spec,
PRBool isServer,
- const SSL3Finished * hashes,
+ const SSL3Hashes * hashes,
TLSFinished * tlsFinished)
{
const char * label;
unsigned int len;
SECStatus rv;
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;
}
/* The calling function must acquire and release the appropriate
* lock (e.g., ssl_GetSpecReadLock / ssl_ReleaseSpecReadLock for
* ss->ssl3.crSpec).
@@ -8956,22 +9512,26 @@ ssl3_ComputeTLSFinished(ssl3CipherSpec *
SECStatus
ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label,
unsigned int labelLen, const unsigned char *val, unsigned int valLen,
unsigned char *out, unsigned int outLen)
{
SECStatus rv = SECSuccess;
if (spec->master_secret && !spec->bypassCiphers) {
- SECItem param = {siBuffer, NULL, 0};
- PK11Context *prf_context =
- PK11_CreateContextBySymKey(CKM_TLS_PRF_GENERAL, CKA_SIGN,
- spec->master_secret, ¶m);
+ SECItem param = {siBuffer, NULL, 0};
+ CK_MECHANISM_TYPE mech = CKM_TLS_PRF_GENERAL;
+ PK11Context *prf_context;
unsigned int retLen;
+ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
+ mech = CKM_NSS_TLS_PRF_GENERAL_SHA256;
+ }
+ prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN,
+ spec->master_secret, ¶m);
if (!prf_context)
return SECFailure;
rv = PK11_DigestBegin(prf_context);
rv |= PK11_DigestOp(prf_context, (unsigned char *) label, labelLen);
rv |= PK11_DigestOp(prf_context, val, valLen);
rv |= PK11_DigestFinal(prf_context, out, &retLen, outLen);
PORT_Assert(rv != SECSuccess || retLen == outLen);
@@ -9102,17 +9662,17 @@ ssl3_RecordKeyLog(sslSocket *ss)
static SECStatus
ssl3_SendFinished(sslSocket *ss, PRInt32 flags)
{
ssl3CipherSpec *cwSpec;
PRBool isTLS;
PRBool isServer = ss->sec.isServer;
SECStatus rv;
SSL3Sender sender = isServer ? sender_server : sender_client;
- SSL3Finished hashes;
+ SSL3Hashes hashes;
TLSFinished tlsFinished;
SSL_TRC(3, ("%d: SSL3[%d]: send finished handshake", SSL_GETPID(), ss->fd));
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
ssl_GetSpecReadLock(ss);
@@ -9136,24 +9696,25 @@ ssl3_SendFinished(sslSocket *ss, PRInt32
rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof tlsFinished);
if (rv != SECSuccess)
goto fail; /* err set by AppendHandshake. */
rv = ssl3_AppendHandshake(ss, &tlsFinished, sizeof tlsFinished);
if (rv != SECSuccess)
goto fail; /* err set by AppendHandshake. */
} else {
if (isServer)
- ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes;
+ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes.u.s;
else
- ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes;
- ss->ssl3.hs.finishedBytes = sizeof hashes;
- rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes);
+ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes.u.s;
+ PORT_Assert(hashes.len == sizeof hashes.u.s);
+ ss->ssl3.hs.finishedBytes = sizeof hashes.u.s;
+ rv = ssl3_AppendHandshakeHeader(ss, finished, sizeof hashes.u.s);
if (rv != SECSuccess)
goto fail; /* err set by AppendHandshake. */
- rv = ssl3_AppendHandshake(ss, &hashes, sizeof hashes);
+ rv = ssl3_AppendHandshake(ss, &hashes.u.s, sizeof hashes.u.s);
if (rv != SECSuccess)
goto fail; /* err set by AppendHandshake. */
}
rv = ssl3_FlushHandshake(ss, flags);
if (rv != SECSuccess) {
goto fail; /* error code set by ssl3_FlushHandshake */
}
@@ -9292,28 +9853,29 @@ ssl3_HandleFinished(sslSocket *ss, SSL3O
ss->ssl3.hs.finishedBytes = sizeof tlsFinished;
if (rv != SECSuccess ||
0 != NSS_SecureMemcmp(&tlsFinished, b, length)) {
(void)SSL3_SendAlert(ss, alert_fatal, decrypt_error);
PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
return SECFailure;
}
} else {
- if (length != sizeof(SSL3Hashes)) {
+ if (length != sizeof(SSL3Finished)) {
(void)ssl3_IllegalParameter(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_FINISHED);
return SECFailure;
}
if (!isServer)
- ss->ssl3.hs.finishedMsgs.sFinished[1] = *hashes;
+ ss->ssl3.hs.finishedMsgs.sFinished[1] = hashes->u.s;
else
- ss->ssl3.hs.finishedMsgs.sFinished[0] = *hashes;
- ss->ssl3.hs.finishedBytes = sizeof *hashes;
- if (0 != NSS_SecureMemcmp(hashes, b, length)) {
+ ss->ssl3.hs.finishedMsgs.sFinished[0] = hashes->u.s;
+ PORT_Assert(hashes->len == sizeof hashes->u.s);
+ ss->ssl3.hs.finishedBytes = sizeof hashes->u.s;
+ if (0 != NSS_SecureMemcmp(&hashes->u.s, b, length)) {
(void)ssl3_HandshakeFailure(ss);
PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
return SECFailure;
}
}
ssl_GetXmitBufLock(ss); /*************************************/
@@ -10802,16 +11364,22 @@ ssl3_DestroySSL3Info(sslSocket *ss)
}
#endif
if (ss->ssl3.hs.md5) {
PK11_DestroyContext(ss->ssl3.hs.md5,PR_TRUE);
}
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;
ss->ssl3.hs.messages.len = 0;
ss->ssl3.hs.messages.space = 0;
}
/* free the SSL3Buffer (msg_body) */
--- a/lib/ssl/ssl3ecc.c
+++ b/lib/ssl/ssl3ecc.c
@@ -202,19 +202,20 @@ params2ecName(SECKEYECParams * params)
return i;
}
return ec_noName;
}
/* Caller must set hiLevel error code. */
static SECStatus
-ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint,
- SSL3Random *client_rand, SSL3Random *server_rand,
- SSL3Hashes *hashes, PRBool bypassPKCS11)
+ssl3_ComputeECDHKeyHash(SECOidTag hashAlg,
+ SECItem ec_params, SECItem server_ecpoint,
+ SSL3Random *client_rand, SSL3Random *server_rand,
+ SSL3Hashes *hashes, PRBool bypassPKCS11)
{
PRUint8 * hashBuf;
PRUint8 * pBuf;
SECStatus rv = SECSuccess;
unsigned int bufLen;
/*
* XXX For now, we only support named curves (the appropriate
* checks are made before this method is called) so ec_params
@@ -240,43 +241,47 @@ ssl3_ComputeECDHKeyHash(SECItem ec_param
memcpy(pBuf, ec_params.data, ec_params.len);
pBuf += ec_params.len;
pBuf[0] = (PRUint8)(server_ecpoint.len);
pBuf += 1;
memcpy(pBuf, server_ecpoint.data, server_ecpoint.len);
pBuf += server_ecpoint.len;
PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen);
- rv = ssl3_ComputeCommonKeyHash(hashBuf, bufLen, hashes, bypassPKCS11);
+ rv = ssl3_ComputeCommonKeyHash(hashAlg, hashBuf, bufLen, hashes,
+ bypassPKCS11);
PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen));
- PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH));
- PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH));
+ PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result",
+ hashes->u.s.md5, MD5_LENGTH));
+ PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result",
+ hashes->u.s.sha, SHA1_LENGTH));
if (hashBuf != buf)
PORT_Free(hashBuf);
return rv;
}
/* Called from ssl3_SendClientKeyExchange(). */
SECStatus
ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey)
{
PK11SymKey * pms = NULL;
SECStatus rv = SECFailure;
- PRBool isTLS;
+ PRBool isTLS, isTLS12;
CK_MECHANISM_TYPE target;
SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */
SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
/* Generate ephemeral EC keypair */
if (svrPubKey->keyType != ecKey) {
PORT_SetError(SEC_ERROR_BAD_KEY);
goto loser;
}
/* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */
privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams,
@@ -285,18 +290,23 @@ ssl3_SendECDHClientKeyExchange(sslSocket
ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL);
rv = SECFailure;
goto loser;
}
PRINT_BUF(50, (ss, "ECDH public value:",
pubKey->u.ec.publicValue.data,
pubKey->u.ec.publicValue.len));
- if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH;
- else target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ if (isTLS12) {
+ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256;
+ } else if (isTLS) {
+ target = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ } else {
+ target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ }
/* Determine the PMS */
pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL,
CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
CKD_NULL, NULL, NULL);
if (pms == NULL) {
SSL3AlertDescription desc = illegal_parameter;
@@ -350,17 +360,17 @@ ssl3_HandleECDHClientKeyExchange(sslSock
PRUint32 length,
SECKEYPublicKey *srvrPubKey,
SECKEYPrivateKey *srvrPrivKey)
{
PK11SymKey * pms;
SECStatus rv;
SECKEYPublicKey clntPubKey;
CK_MECHANISM_TYPE target;
- PRBool isTLS;
+ PRBool isTLS, isTLS12;
PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
clntPubKey.keyType = ecKey;
clntPubKey.u.ec.DEREncodedParams.len =
srvrPubKey->u.ec.DEREncodedParams.len;
clntPubKey.u.ec.DEREncodedParams.data =
@@ -369,19 +379,25 @@ ssl3_HandleECDHClientKeyExchange(sslSock
rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue,
1, &b, &length);
if (rv != SECSuccess) {
SEND_ALERT
return SECFailure; /* XXX Who sets the error code?? */
}
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
- if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH;
- else target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ if (isTLS12) {
+ target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256;
+ } else if (isTLS) {
+ target = CKM_TLS_MASTER_KEY_DERIVE_DH;
+ } else {
+ target = CKM_SSL3_MASTER_KEY_DERIVE_DH;
+ }
/* Determine the PMS */
pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL,
CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0,
CKD_NULL, NULL, NULL);
if (pms == NULL) {
/* last gasp. */
@@ -567,28 +583,32 @@ ssl3_CreateECDHEphemeralKeys(sslSocket *
return SECSuccess;
}
SECStatus
ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
PLArenaPool * arena = NULL;
SECKEYPublicKey *peerKey = NULL;
- PRBool isTLS;
+ PRBool isTLS, isTLS12;
SECStatus rv;
int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH;
SSL3AlertDescription desc = illegal_parameter;
SSL3Hashes hashes;
SECItem signature = {siBuffer, NULL, 0};
SECItem ec_params = {siBuffer, NULL, 0};
SECItem ec_point = {siBuffer, NULL, 0};
unsigned char paramBuf[3]; /* only for curve_type == named_curve */
+ SSL3SignatureAndHashAlgorithm sigAndHash;
+
+ sigAndHash.hashAlg = SEC_OID_UNKNOWN;
isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
/* XXX This works only for named curves, revisit this when
* we support generic curves.
*/
ec_params.len = sizeof paramBuf;
ec_params.data = paramBuf;
rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length);
if (rv != SECSuccess) {
@@ -610,16 +630,29 @@ ssl3_HandleECDHServerKeyExchange(sslSock
}
/* Fail if the ec point uses compressed representation */
if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM;
desc = handshake_failure;
goto alert_loser;
}
+ if (isTLS12) {
+ 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. */
}
if (length != 0) {
if (isTLS)
desc = decode_error;
@@ -632,20 +665,20 @@ ssl3_HandleECDHServerKeyExchange(sslSock
/* failures after this point are not malformed handshakes. */
/* TLS: send decrypt_error if signature failed. */
desc = isTLS ? decrypt_error : handshake_failure;
/*
* check to make sure the hash is signed by right guy
*/
- rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point,
- &ss->ssl3.hs.client_random,
- &ss->ssl3.hs.server_random,
- &hashes, ss->opt.bypassPKCS11);
+ rv = ssl3_ComputeECDHKeyHash(sigAndHash.hashAlg, ec_params, ec_point,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
if (rv != SECSuccess) {
errCode =
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto alert_loser;
}
rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature,
isTLS, ss->pkcs11PinArg);
@@ -699,32 +732,33 @@ loser:
return SECFailure;
no_memory: /* no-memory error has already been set. */
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
return SECFailure;
}
SECStatus
-ssl3_SendECDHServerKeyExchange(sslSocket *ss)
+ssl3_SendECDHServerKeyExchange(
+ sslSocket *ss,
+ const SSL3SignatureAndHashAlgorithm *sigAndHash)
{
-const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
+ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def;
SECStatus rv = SECFailure;
int length;
- PRBool isTLS;
+ PRBool isTLS, isTLS12;
SECItem signed_hash = {siBuffer, NULL, 0};
SSL3Hashes hashes;
SECKEYPublicKey * ecdhePub;
SECItem ec_params = {siBuffer, NULL, 0};
unsigned char paramBuf[3];
ECName curve;
SSL3KEAType certIndex;
-
/* Generate ephemeral ECDH key pair and send the public key */
curve = ssl3_GetCurveNameForServerSocket(ss);
if (curve == ec_noName) {
goto loser;
}
rv = ssl3_CreateECDHEphemeralKeys(ss, curve);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
@@ -743,26 +777,29 @@ const ssl3KEADef * kea_def = ss-
ec_params.data[0] = ec_type_named;
ec_params.data[1] = 0x00;
ec_params.data[2] = curve;
} else {
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
goto loser;
}
- rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue,
- &ss->ssl3.hs.client_random,
- &ss->ssl3.hs.server_random,
- &hashes, ss->opt.bypassPKCS11);
+ rv = ssl3_ComputeECDHKeyHash(sigAndHash->hashAlg,
+ ec_params,
+ ecdhePub->u.ec.publicValue,
+ &ss->ssl3.hs.client_random,
+ &ss->ssl3.hs.server_random,
+ &hashes, ss->opt.bypassPKCS11);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto loser;
}
isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0);
+ isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2);
/* XXX SSLKEAType isn't really a good choice for
* indexing certificates but that's all we have
* for now.
*/
if (kea_def->kea == kea_ecdhe_rsa)
certIndex = kt_rsa;
else /* kea_def->kea == kea_ecdhe_ecdsa */
@@ -776,17 +813,17 @@ const ssl3KEADef * kea_def = ss-
if (signed_hash.data == NULL) {
/* how can this happen and rv == SECSuccess ?? */
PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE);
goto loser;
}
length = ec_params.len +
1 + ecdhePub->u.ec.publicValue.len +
- 2 + signed_hash.len;
+ (isTLS12 ? 2 : 0) + 2 + signed_hash.len;
rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len);
if (rv != SECSuccess) {
@@ -794,16 +831,23 @@ const ssl3KEADef * kea_def = ss-
}
rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data,
ecdhePub->u.ec.publicValue.len, 1);
if (rv != SECSuccess) {
goto loser; /* err set by AppendHandshake. */
}
+ if (isTLS12) {
+ 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);
return SECSuccess;