Bug 577019, Bug 480514: Implement TLS 1.2 mechanisms in softoken.
authorAdam Langley <agl@chromium.org>
Wed, 20 Mar 2013 12:39:09 -0700
changeset 10699 3c57b01376b9757a63a4bf10889bfaedd0eff0b7
parent 10698 aedd2de13989986c33fb57aa15cba074269a43e1
child 10700 b40e4878cf84e7463f7e229e352fe0cf66b41f4f
push id12
push userwtc@google.com
push dateWed, 20 Mar 2013 19:39:43 +0000
bugs577019, 480514
Bug 577019, Bug 480514: Implement TLS 1.2 mechanisms in softoken. Add NSS vendor-defined mechanisms CKM_NSS_TLS_PRF_GENERAL_SHA256, CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256, CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256, and CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256. r=wtc.
cmd/lib/pk11table.c
lib/pk11wrap/pk11mech.c
lib/pk11wrap/pk11slot.c
lib/softoken/pkcs11.c
lib/softoken/pkcs11c.c
lib/softoken/pkcs11i.h
lib/softoken/tlsprf.c
lib/util/pkcs11n.h
--- a/cmd/lib/pk11table.c
+++ b/cmd/lib/pk11table.c
@@ -370,18 +370,21 @@ const Constant _consts[] = {
 	mkEntry(CKM_XOR_BASE_AND_DATA, Mechanism),
 	mkEntry(CKM_EXTRACT_KEY_FROM_KEY, Mechanism),
 	mkEntry(CKM_SSL3_PRE_MASTER_KEY_GEN, Mechanism),
 	mkEntry(CKM_SSL3_MASTER_KEY_DERIVE, Mechanism),
 	mkEntry(CKM_SSL3_KEY_AND_MAC_DERIVE, Mechanism),
 	mkEntry(CKM_SSL3_MASTER_KEY_DERIVE_DH, Mechanism),
 	mkEntry(CKM_TLS_PRE_MASTER_KEY_GEN, Mechanism),
 	mkEntry(CKM_TLS_MASTER_KEY_DERIVE, Mechanism),
+	mkEntry(CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256, Mechanism),
 	mkEntry(CKM_TLS_KEY_AND_MAC_DERIVE, Mechanism),
+	mkEntry(CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256, Mechanism),
 	mkEntry(CKM_TLS_MASTER_KEY_DERIVE_DH, Mechanism),
+	mkEntry(CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256, Mechanism),
 	mkEntry(CKM_SSL3_MD5_MAC, Mechanism),
 	mkEntry(CKM_SSL3_SHA1_MAC, Mechanism),
 	mkEntry(CKM_MD5_KEY_DERIVATION, Mechanism),
 	mkEntry(CKM_MD2_KEY_DERIVATION, Mechanism),
 	mkEntry(CKM_SHA1_KEY_DERIVATION, Mechanism),
 	mkEntry(CKM_SHA256_KEY_DERIVATION, Mechanism),
 	mkEntry(CKM_SHA384_KEY_DERIVATION, Mechanism),
 	mkEntry(CKM_SHA512_KEY_DERIVATION, Mechanism),
@@ -468,16 +471,17 @@ const Constant _consts[] = {
 	mkEntry(CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC, Mechanism),
 	mkEntry(CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4, Mechanism),
 	mkEntry(CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4, Mechanism),
 	mkEntry(CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC, Mechanism),
 	mkEntry(CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN, Mechanism),
 	mkEntry(CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN, Mechanism),
 	mkEntry(CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN, Mechanism),
 	mkEntry(CKM_TLS_PRF_GENERAL, Mechanism),
+	mkEntry(CKM_NSS_TLS_PRF_GENERAL_SHA256, Mechanism),
 
 	mkEntry(CKR_OK, Result),
 	mkEntry(CKR_CANCEL, Result),
 	mkEntry(CKR_HOST_MEMORY, Result),
 	mkEntry(CKR_SLOT_ID_INVALID, Result),
 	mkEntry(CKR_GENERAL_ERROR, Result),
 	mkEntry(CKR_FUNCTION_FAILED, Result),
 	mkEntry(CKR_ARGUMENTS_BAD, Result),
--- a/lib/pk11wrap/pk11mech.c
+++ b/lib/pk11wrap/pk11mech.c
@@ -365,33 +365,37 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type,u
     case CKM_SSL3_PRE_MASTER_KEY_GEN:
     case CKM_GENERIC_SECRET_KEY_GEN:
     case CKM_SSL3_MASTER_KEY_DERIVE:
     case CKM_SSL3_MASTER_KEY_DERIVE_DH:
     case CKM_SSL3_KEY_AND_MAC_DERIVE:
     case CKM_SSL3_SHA1_MAC:
     case CKM_SSL3_MD5_MAC:
     case CKM_TLS_MASTER_KEY_DERIVE:
+    case CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256:
     case CKM_TLS_MASTER_KEY_DERIVE_DH:
+    case CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256:
     case CKM_TLS_KEY_AND_MAC_DERIVE:
+    case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
     case CKM_SHA_1_HMAC:
     case CKM_SHA_1_HMAC_GENERAL:
     case CKM_SHA224_HMAC:
     case CKM_SHA224_HMAC_GENERAL:
     case CKM_SHA256_HMAC:
     case CKM_SHA256_HMAC_GENERAL:
     case CKM_SHA384_HMAC:
     case CKM_SHA384_HMAC_GENERAL:
     case CKM_SHA512_HMAC:
     case CKM_SHA512_HMAC_GENERAL:
     case CKM_MD2_HMAC:
     case CKM_MD2_HMAC_GENERAL:
     case CKM_MD5_HMAC:
     case CKM_MD5_HMAC_GENERAL:
     case CKM_TLS_PRF_GENERAL:
+    case CKM_NSS_TLS_PRF_GENERAL_SHA256:
 	return CKK_GENERIC_SECRET;
     default:
 	return pk11_lookup(type)->keyType;
     }
 }
 
 /*
  * Get the Key Gen Mechanism needed for the given 
@@ -555,32 +559,34 @@ PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE
         return CKM_EC_KEY_PAIR_GEN; 
     case CKM_SSL3_PRE_MASTER_KEY_GEN:
     case CKM_SSL3_MASTER_KEY_DERIVE:
     case CKM_SSL3_KEY_AND_MAC_DERIVE:
     case CKM_SSL3_SHA1_MAC:
     case CKM_SSL3_MD5_MAC:
     case CKM_TLS_MASTER_KEY_DERIVE:
     case CKM_TLS_KEY_AND_MAC_DERIVE:
+    case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
 	return CKM_SSL3_PRE_MASTER_KEY_GEN;
     case CKM_SHA_1_HMAC:
     case CKM_SHA_1_HMAC_GENERAL:
     case CKM_SHA224_HMAC:
     case CKM_SHA224_HMAC_GENERAL:
     case CKM_SHA256_HMAC:
     case CKM_SHA256_HMAC_GENERAL:
     case CKM_SHA384_HMAC:
     case CKM_SHA384_HMAC_GENERAL:
     case CKM_SHA512_HMAC:
     case CKM_SHA512_HMAC_GENERAL:
     case CKM_MD2_HMAC:
     case CKM_MD2_HMAC_GENERAL:
     case CKM_MD5_HMAC:
     case CKM_MD5_HMAC_GENERAL:
     case CKM_TLS_PRF_GENERAL:
+    case CKM_NSS_TLS_PRF_GENERAL_SHA256:
     case CKM_GENERIC_SECRET_KEY_GEN:
 	return CKM_GENERIC_SECRET_KEY_GEN;
     case CKM_PBE_MD2_DES_CBC:
     case CKM_PBE_MD5_DES_CBC:
     case CKM_PBA_SHA1_WITH_SHA1_HMAC:
     case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN:
     case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN:
     case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN:
--- a/lib/pk11wrap/pk11slot.c
+++ b/lib/pk11wrap/pk11slot.c
@@ -875,16 +875,17 @@ PK11_GetSlotList(CK_MECHANISM_TYPE type)
 	return &pk11_ecSlotList;
     case CKM_SSL3_PRE_MASTER_KEY_GEN:
     case CKM_SSL3_MASTER_KEY_DERIVE:
     case CKM_SSL3_SHA1_MAC:
     case CKM_SSL3_MD5_MAC:
 	return &pk11_sslSlotList;
     case CKM_TLS_MASTER_KEY_DERIVE:
     case CKM_TLS_KEY_AND_MAC_DERIVE:
+    case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
 	return &pk11_tlsSlotList;
     case CKM_IDEA_CBC:
     case CKM_IDEA_ECB:
 	return &pk11_ideaSlotList;
     case CKM_FAKE_RANDOM:
 	return &pk11_randomSlotList;
     }
     return NULL;
--- a/lib/softoken/pkcs11.c
+++ b/lib/softoken/pkcs11.c
@@ -382,16 +382,18 @@ static const struct mechanismList mechan
      {CKM_SHA256_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
      {CKM_SHA384,		{0,   0, CKF_DIGEST},		PR_FALSE},
      {CKM_SHA384_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
      {CKM_SHA384_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
      {CKM_SHA512,		{0,   0, CKF_DIGEST},		PR_FALSE},
      {CKM_SHA512_HMAC,		{1, 128, CKF_SN_VR},		PR_TRUE},
      {CKM_SHA512_HMAC_GENERAL,	{1, 128, CKF_SN_VR},		PR_TRUE},
      {CKM_TLS_PRF_GENERAL,	{0, 512, CKF_SN_VR},		PR_FALSE},
+     {CKM_NSS_TLS_PRF_GENERAL_SHA256,
+				{0, 512, CKF_SN_VR},		PR_FALSE},
      /* ------------------------- HKDF Operations -------------------------- */
      {CKM_NSS_HKDF_SHA1,        {1, 128, CKF_DERIVE},           PR_TRUE},
      {CKM_NSS_HKDF_SHA256,      {1, 128, CKF_DERIVE},           PR_TRUE},
      {CKM_NSS_HKDF_SHA384,      {1, 128, CKF_DERIVE},           PR_TRUE},
      {CKM_NSS_HKDF_SHA512,      {1, 128, CKF_DERIVE},           PR_TRUE},
      /* ------------------------- CAST Operations --------------------------- */
 #ifdef NSS_SOFTOKEN_DOES_CAST
      /* Cast operations are not supported ( yet? ) */
@@ -449,18 +451,24 @@ static const struct mechanismList mechan
      {CKM_MD5_KEY_DERIVATION,		{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
      {CKM_MD2_KEY_DERIVATION,		{ 0, 16, CKF_DERIVE},   PR_FALSE}, 
      {CKM_SHA1_KEY_DERIVATION,		{ 0, 20, CKF_DERIVE},   PR_FALSE}, 
      {CKM_SHA224_KEY_DERIVATION,	{ 0, 28, CKF_DERIVE},   PR_FALSE}, 
      {CKM_SHA256_KEY_DERIVATION,	{ 0, 32, CKF_DERIVE},   PR_FALSE}, 
      {CKM_SHA384_KEY_DERIVATION,	{ 0, 48, CKF_DERIVE},   PR_FALSE}, 
      {CKM_SHA512_KEY_DERIVATION,	{ 0, 64, CKF_DERIVE},   PR_FALSE}, 
      {CKM_TLS_MASTER_KEY_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256,
+					{48, 48, CKF_DERIVE},	PR_FALSE},
      {CKM_TLS_MASTER_KEY_DERIVE_DH,	{8, 128, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256,
+					{8, 128, CKF_DERIVE},	PR_FALSE},
      {CKM_TLS_KEY_AND_MAC_DERIVE,	{48, 48, CKF_DERIVE},   PR_FALSE}, 
+     {CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256,
+					{48, 48, CKF_DERIVE},	PR_FALSE},
      /* ---------------------- PBE Key Derivations  ------------------------ */
      {CKM_PBE_MD2_DES_CBC,		{8, 8, CKF_DERIVE},   PR_TRUE},
      {CKM_PBE_MD5_DES_CBC,		{8, 8, CKF_DERIVE},   PR_TRUE},
      /* ------------------ NETSCAPE PBE Key Derivations  ------------------- */
      {CKM_NETSCAPE_PBE_SHA1_DES_CBC,	     { 8, 8, CKF_GENERATE}, PR_TRUE},
      {CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC, {24,24, CKF_GENERATE}, PR_TRUE},
      {CKM_PBE_SHA1_DES3_EDE_CBC,	     {24,24, CKF_GENERATE}, PR_TRUE},
      {CKM_PBE_SHA1_DES2_EDE_CBC,	     {24,24, CKF_GENERATE}, PR_TRUE},
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -2242,17 +2242,20 @@ finish_rsa:
 	crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
 					*(CK_ULONG *)pMechanism->pParameter);
 	break;
     case CKM_SSL3_SHA1_MAC:
 	crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
 					*(CK_ULONG *)pMechanism->pParameter);
 	break;
     case CKM_TLS_PRF_GENERAL:
-	crv = sftk_TLSPRFInit(context, key, key_type);
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgNULL);
+	break;
+    case CKM_NSS_TLS_PRF_GENERAL_SHA256:
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256);
 	break;
 
     case CKM_NSS_HMAC_CONSTANT_TIME: {
 	sftk_MACConstantTimeCtx *ctx =
 	    sftk_HMACConstantTime_New(pMechanism,key);
 	CK_ULONG *intpointer;
 
 	if (ctx == NULL) {
@@ -2798,17 +2801,20 @@ finish_rsa:
 	crv = sftk_doSSLMACInit(context,SEC_OID_MD5,key,
 					*(CK_ULONG *)pMechanism->pParameter);
 	break;
     case CKM_SSL3_SHA1_MAC:
 	crv = sftk_doSSLMACInit(context,SEC_OID_SHA1,key,
 					*(CK_ULONG *)pMechanism->pParameter);
 	break;
     case CKM_TLS_PRF_GENERAL:
-	crv = sftk_TLSPRFInit(context, key, key_type);
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgNULL);
+	break;
+    case CKM_NSS_TLS_PRF_GENERAL_SHA256:
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256);
 	break;
 
     default:
 	crv = CKR_MECHANISM_INVALID;
 	break;
     }
 
     if (crv != CKR_OK) {
@@ -5466,16 +5472,17 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
     CK_ULONG        IVSize;
     CK_ULONG        keySize	= 0;
     CK_RV           crv 	= CKR_OK;
     CK_BBOOL        cktrue	= CK_TRUE;
     CK_KEY_TYPE     keyType	= CKK_GENERIC_SECRET;
     CK_OBJECT_CLASS classType	= CKO_SECRET_KEY;
     CK_KEY_DERIVATION_STRING_DATA *stringPtr;
     PRBool          isTLS = PR_FALSE;
+    PRBool          isSHA256 = PR_FALSE;
     PRBool          isDH = PR_FALSE;
     SECStatus       rv;
     int             i;
     unsigned int    outLen;
     unsigned char   sha_out[SHA1_LENGTH];
     unsigned char   key_block[NUM_MIXERS * MD5_LENGTH];
     unsigned char   key_block2[MD5_LENGTH];
     PRBool          isFIPS;		
@@ -5565,29 +5572,34 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
             return CKR_KEY_HANDLE_INVALID;
         }
     }
 
     switch (pMechanism->mechanism) {
     /*
      * generate the master secret 
      */
+    case CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256:
+    case CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256:
+	isSHA256 = PR_TRUE;
+	/* fall thru */
     case CKM_TLS_MASTER_KEY_DERIVE:
     case CKM_TLS_MASTER_KEY_DERIVE_DH:
 	isTLS = PR_TRUE;
 	/* fall thru */
     case CKM_SSL3_MASTER_KEY_DERIVE:
     case CKM_SSL3_MASTER_KEY_DERIVE_DH:
       {
 	CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master;
 	SSL3RSAPreMasterSecret *          rsa_pms;
 	unsigned char                     crsrdata[SSL3_RANDOM_LENGTH * 2];
 
         if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
-            (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH))
+            (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH) ||
+            (pMechanism->mechanism == CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256))
 		isDH = PR_TRUE;
 
 	/* first do the consistancy checks */
 	if (!isDH && (att->attrib.ulValueLen != SSL3_PMS_LENGTH)) {
 	    crv = CKR_KEY_TYPE_INCONSISTENT;
 	    break;
 	}
 	att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
@@ -5645,17 +5657,22 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 
  	    crsr.data   = crsrdata;
 	    crsr.len    = sizeof crsrdata;
  	    master.data = key_block;
 	    master.len  = SSL3_MASTER_SECRET_LENGTH;
  	    pms.data    = (unsigned char*)att->attrib.pValue;
 	    pms.len     =                 att->attrib.ulValueLen;
 
-	    status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
+	    if (isSHA256) {
+		status = TLS_P_hash(HASH_AlgSHA256, &pms, "master secret",
+				    &crsr, &master, isFIPS);
+	    } else {
+		status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
+	    }
 	    if (status != SECSuccess) {
 	    	crv = CKR_FUNCTION_FAILED;
 		break;
 	    }
 	} else {
 	    /* now allocate the hash contexts */
 	    md5 = MD5_NewContext();
 	    if (md5 == NULL) { 
@@ -5704,16 +5721,19 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 	    if (crv != CKR_OK) break;
 	    /* While we're here, we might as well force this, too. */
 	    crv = sftk_forceAttribute(key,CKA_DERIVE,&cktrue,sizeof(CK_BBOOL));
 	    if (crv != CKR_OK) break;
 	}
 	break;
       }
 
+    case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
+	isSHA256 = PR_TRUE;
+	/* fall thru */
     case CKM_TLS_KEY_AND_MAC_DERIVE:
 	isTLS = PR_TRUE;
 	/* fall thru */
     case CKM_SSL3_KEY_AND_MAC_DERIVE:
       {
 	CK_SSL3_KEY_MAT_PARAMS *ssl3_keys;
 	CK_SSL3_KEY_MAT_OUT *   ssl3_keys_out;
 	CK_ULONG                effKeySize;
@@ -5795,18 +5815,23 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 
 	    srcr.data   = srcrdata;
 	    srcr.len    = sizeof srcrdata;
 	    keyblk.data = key_block;
 	    keyblk.len  = block_needed;
 	    master.data = (unsigned char*)att->attrib.pValue;
 	    master.len  =                 att->attrib.ulValueLen;
 
-	    status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
-			      isFIPS);
+	    if (isSHA256) {
+		status = TLS_P_hash(HASH_AlgSHA256, &master, "key expansion",
+				    &srcr, &keyblk, isFIPS);
+	    } else {
+		status = TLS_PRF(&master, "key expansion", &srcr, &keyblk,
+				 isFIPS);
+	    }
 	    if (status != SECSuccess) {
 		goto key_and_mac_derive_fail;
 	    }
 	} else {
 	    unsigned int block_bytes = 0;
 	    /* key_block = 
 	     *     MD5(master_secret + SHA('A' + master_secret + 
 	     *                      ServerHello.random + ClientHello.random)) +
@@ -5953,17 +5978,17 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE h
 		MD5_Begin(md5);
             	MD5_Update(md5, srcrdata, sizeof srcrdata);
 		MD5_End(md5, key_block2, &outLen, MD5_LENGTH);
 		PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize);
 
 	    } else {
 
 		/*
-		** Generate TLS Export write keys and IVs.
+		** Generate TLS 1.0 Export write keys and IVs.
 		*/
 		SECStatus     status;
 		SECItem       secret = { siBuffer, NULL, 0 };
 		SECItem       crsr   = { siBuffer, NULL, 0 };
 		SECItem       keyblk = { siBuffer, NULL, 0 };
 
 		/*
 		** client_write_key[CipherSpec.key_material]
--- a/lib/softoken/pkcs11i.h
+++ b/lib/softoken/pkcs11i.h
@@ -732,13 +732,14 @@ void sftk_MACConstantTime_DestroyContext
 
 /****************************************
  * implement TLS Pseudo Random Function (PRF)
  */
 
 extern CK_RV
 sftk_TLSPRFInit(SFTKSessionContext *context, 
 		  SFTKObject *        key, 
-		  CK_KEY_TYPE         key_type);
+		  CK_KEY_TYPE         key_type,
+		  HASH_HashType       hash_alg);
 
 SEC_END_PROTOS
 
 #endif /* _PKCS11I_H_ */
--- a/lib/softoken/tlsprf.c
+++ b/lib/softoken/tlsprf.c
@@ -18,16 +18,17 @@ static void sftk_TLSPRFNull(void *data, 
 typedef struct {
     PRUint32	   cxSize;	/* size of allocated block, in bytes.        */
     PRUint32       cxBufSize;   /* sizeof buffer at cxBufPtr.                */
     unsigned char *cxBufPtr;	/* points to real buffer, may be cxBuf.      */
     PRUint32	   cxKeyLen;	/* bytes of cxBufPtr containing key.         */
     PRUint32	   cxDataLen;	/* bytes of cxBufPtr containing data.        */
     SECStatus	   cxRv;	/* records failure of void functions.        */
     PRBool	   cxIsFIPS;	/* true if conforming to FIPS 198.           */
+    HASH_HashType  cxHashAlg;	/* hash algorithm to use for TLS 1.2+        */
     unsigned char  cxBuf[512];	/* actual size may be larger than 512.       */
 } TLSPRFContext;
 
 static void
 sftk_TLSPRFHashUpdate(TLSPRFContext *cx, const unsigned char *data, 
                         unsigned int data_len)
 {
     PRUint32 bytesUsed = cx->cxKeyLen + cx->cxDataLen;
@@ -84,17 +85,22 @@ sftk_TLSPRFUpdate(TLSPRFContext *cx,
     secretItem.len  = cx->cxKeyLen;
 
     seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
     seedItem.len  = cx->cxDataLen;
 
     sigItem.data = sig;
     sigItem.len  = maxLen;
 
-    rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
+    if (cx->cxHashAlg != HASH_AlgNULL) {
+	rv = TLS_P_hash(cx->cxHashAlg, &secretItem, NULL, &seedItem, &sigItem,
+			cx->cxIsFIPS);
+    } else {
+	rv = TLS_PRF(&secretItem, NULL, &seedItem, &sigItem, cx->cxIsFIPS);
+    }
     if (rv == SECSuccess && sigLen != NULL)
     	*sigLen = sigItem.len;
     return rv;
 
 }
 
 static SECStatus
 sftk_TLSPRFVerify(TLSPRFContext *cx, 
@@ -131,17 +137,18 @@ sftk_TLSPRFHashDestroy(TLSPRFContext *cx
 	    PORT_ZFree(cx->cxBufPtr, cx->cxBufSize);
 	PORT_ZFree(cx, cx->cxSize);
     }
 }
 
 CK_RV
 sftk_TLSPRFInit(SFTKSessionContext *context, 
 		  SFTKObject *        key, 
-		  CK_KEY_TYPE         key_type)
+		  CK_KEY_TYPE         key_type,
+		  HASH_HashType       hash_alg)
 {
     SFTKAttribute * keyVal;
     TLSPRFContext * prf_cx;
     CK_RV           crv = CKR_HOST_MEMORY;
     PRUint32        keySize;
     PRUint32        blockSize;
 
     if (key_type != CKK_GENERIC_SECRET)
@@ -157,16 +164,17 @@ sftk_TLSPRFInit(SFTKSessionContext *cont
     	goto done;
     prf_cx->cxSize    = blockSize;
     prf_cx->cxKeyLen  = keySize;
     prf_cx->cxDataLen = 0;
     prf_cx->cxBufSize = blockSize - SFTK_OFFSETOF(TLSPRFContext, cxBuf);
     prf_cx->cxRv      = SECSuccess;
     prf_cx->cxIsFIPS  = (key->slot->slotID == FIPS_SLOT_ID);
     prf_cx->cxBufPtr  = prf_cx->cxBuf;
+    prf_cx->cxHashAlg = hash_alg;
     if (keySize)
 	PORT_Memcpy(prf_cx->cxBufPtr, keyVal->attrib.pValue, keySize);
 
     context->hashInfo    = (void *) prf_cx;
     context->cipherInfo  = (void *) prf_cx;
     context->hashUpdate  = (SFTKHash)    sftk_TLSPRFHashUpdate;
     context->end         = (SFTKEnd)     sftk_TLSPRFEnd;
     context->update      = (SFTKCipher)  sftk_TLSPRFUpdate;
--- a/lib/util/pkcs11n.h
+++ b/lib/util/pkcs11n.h
@@ -207,16 +207,22 @@ static const char CKT_CVS_ID[] = "@(#) $
  * CKM_NSS_HMAC_CONSTANT_TIME: performs an HMAC authentication.
  * CKM_NSS_SSL3_MAC_CONSTANT_TIME: performs an authentication with SSLv3 MAC.
  *
  * Parameter type: CK_NSS_MAC_CONSTANT_TIME_PARAMS
  */
 #define CKM_NSS_HMAC_CONSTANT_TIME      (CKM_NSS + 19)
 #define CKM_NSS_SSL3_MAC_CONSTANT_TIME  (CKM_NSS + 20)
 
+/* TLS 1.2 mechanisms */
+#define CKM_NSS_TLS_PRF_GENERAL_SHA256          (CKM_NSS + 21)
+#define CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256    (CKM_NSS + 22)
+#define CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256   (CKM_NSS + 23)
+#define CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256 (CKM_NSS + 24)
+
 /*
  * HISTORICAL:
  * Do not attempt to use these. They are only used by NETSCAPE's internal
  * PKCS #11 interface. Most of these are place holders for other mechanism
  * and will change in the future.
  */
 #define CKM_NETSCAPE_PBE_SHA1_DES_CBC           0x80000002UL
 #define CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC    0x80000003UL