Blob Blame History Raw
diff --git a/lib/softoken/pkcs11.c b/lib/softoken/pkcs11.c
--- a/lib/softoken/pkcs11.c
+++ b/lib/softoken/pkcs11.c
@@ -388,16 +388,17 @@ 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_TLS12_MAC,		{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 --------------------------- */
@@ -468,22 +469,25 @@ 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_TLS12_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_TLS12_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_TLS12_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},
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -2512,20 +2527,62 @@ 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, HASH_AlgNULL);
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgNULL, 0);
 	break;
+    case CKM_TLS12_MAC: {
+	CK_TLS12_MAC_PARAMS *tls12_mac_params;
+	HASH_HashType tlsPrfHash;
+	const char *label;
+
+	if (pMechanism->ulParameterLen != sizeof(CK_TLS12_MAC_PARAMS)) {
+	    crv = CKR_MECHANISM_PARAM_INVALID;
+	    break;
+	}
+	tls12_mac_params = (CK_TLS12_MAC_PARAMS *)pMechanism->pParameter;
+	if (tls12_mac_params->prfMechanism == CKM_TLS_PRF) {
+	    /* The TLS 1.0 and 1.1 PRF */
+	    tlsPrfHash = HASH_AlgNULL;
+	    if (tls12_mac_params->ulMacLength != 12) {
+		crv = CKR_MECHANISM_PARAM_INVALID;
+		break;
+	    }
+	} else {
+	    /* The hash function for the TLS 1.2 PRF */
+	    tlsPrfHash =
+		GetHashTypeFromMechanism(tls12_mac_params->prfMechanism);
+	    if (tlsPrfHash == HASH_AlgNULL ||
+		tls12_mac_params->ulMacLength < 12) {
+		crv = CKR_MECHANISM_PARAM_INVALID;
+		break;
+	    }
+	}
+	if (tls12_mac_params->ulServerOrClient == 1) {
+	    label = "server finished";
+	} else if (tls12_mac_params->ulServerOrClient == 2) {
+	    label = "client finished";
+	} else {
+	    crv = CKR_MECHANISM_PARAM_INVALID;
+	    break;
+	}
+	crv = sftk_TLSPRFInit(context, key, key_type, tlsPrfHash,
+			      tls12_mac_params->ulMacLength);
+	if (crv == CKR_OK) {
+	    context->hashUpdate(context->hashInfo, label, 15);
+	}
+	break;
+    }
     case CKM_NSS_TLS_PRF_GENERAL_SHA256:
-	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256);
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256, 0);
 	break;
 
     case CKM_NSS_HMAC_CONSTANT_TIME: {
 	sftk_MACConstantTimeCtx *ctx =
 	    sftk_HMACConstantTime_New(pMechanism,key);
 	CK_ULONG *intpointer;
 
 	if (ctx == NULL) {
@@ -3109,20 +3166,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, HASH_AlgNULL);
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgNULL, 0);
 	break;
     case CKM_NSS_TLS_PRF_GENERAL_SHA256:
-	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256);
+	crv = sftk_TLSPRFInit(context, key, key_type, HASH_AlgSHA256, 0);
 	break;
 
     default:
 	crv = CKR_MECHANISM_INVALID;
 	break;
     }
 
     if (crv != CKR_OK) {
@@ -5916,22 +5973,23 @@
     CK_ULONG        tmpKeySize;
     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;
+    CK_MECHANISM_TYPE mechanism = pMechanism->mechanism;
     CK_AES_CBC_ENCRYPT_DATA_PARAMS *aesEncryptPtr;
     CK_DES_CBC_ENCRYPT_DATA_PARAMS *desEncryptPtr;
     void *cipherInfo;
     PRBool          isTLS = PR_FALSE;
-    PRBool          isSHA256 = PR_FALSE;
     PRBool          isDH = PR_FALSE;
+    HASH_HashType   tlsPrfHash = HASH_AlgNULL;
     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];
     unsigned char   des3key[24];
     PRBool          isFIPS;		
@@ -5969,17 +6027,17 @@
 	}
     }
     if (crv != CKR_OK) { sftk_FreeObject(key); return crv; }
 
     if (keySize == 0) {
 	keySize = sftk_MapKeySize(keyType);
     }
 
-    switch (pMechanism->mechanism) {
+    switch (mechanism) {
       case CKM_NSS_JPAKE_ROUND2_SHA1:   /* fall through */
       case CKM_NSS_JPAKE_ROUND2_SHA256: /* fall through */
       case CKM_NSS_JPAKE_ROUND2_SHA384: /* fall through */
       case CKM_NSS_JPAKE_ROUND2_SHA512:
           extractValue = PR_FALSE;
           classType = CKO_PRIVATE_KEY;
           break;
       case CKM_NSS_JPAKE_FINAL_SHA1:   /* fall through */
@@ -6017,39 +6075,57 @@
         att = sftk_FindAttribute(sourceKey,CKA_VALUE);
         if (att == NULL) {
             sftk_FreeObject(key);
             sftk_FreeObject(sourceKey);
             return CKR_KEY_HANDLE_INVALID;
         }
     }
 
-    switch (pMechanism->mechanism) {
+    switch (mechanism) {
     /*
      * generate the master secret 
      */
+    case CKM_TLS12_MASTER_KEY_DERIVE:
+    case CKM_TLS12_MASTER_KEY_DERIVE_DH:
     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_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256))
-		isDH = PR_TRUE;
+	if ((mechanism == CKM_TLS12_MASTER_KEY_DERIVE) ||
+	    (mechanism == CKM_TLS12_MASTER_KEY_DERIVE_DH)) {
+	    CK_TLS12_MASTER_KEY_DERIVE_PARAMS *tls12_master =
+		(CK_TLS12_MASTER_KEY_DERIVE_PARAMS *) pMechanism->pParameter;
+	    tlsPrfHash = GetHashTypeFromMechanism(tls12_master->prfHashMechanism);
+	    if (tlsPrfHash == HASH_AlgNULL) {
+		crv = CKR_MECHANISM_PARAM_INVALID;
+		break;
+	    }
+	} else if ((mechanism == CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256) ||
+		   (mechanism == CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256)) {
+	    tlsPrfHash = HASH_AlgSHA256;
+	}
+
+	if ((mechanism != CKM_SSL3_MASTER_KEY_DERIVE) &&
+	    (mechanism != CKM_SSL3_MASTER_KEY_DERIVE_DH)) {
+	    isTLS = PR_TRUE;
+	}
+	if ((mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) ||
+	    (mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH) ||
+	    (mechanism == CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256) ||
+	    (mechanism == CKM_TLS12_MASTER_KEY_DERIVE_DH)) {
+	    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);
 	if ((att2 == NULL) || (*(CK_KEY_TYPE *)att2->attrib.pValue !=
@@ -6106,18 +6182,18 @@
 
  	    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;
 
-	    if (isSHA256) {
-		status = TLS_P_hash(HASH_AlgSHA256, &pms, "master secret",
+	    if (tlsPrfHash != HASH_AlgNULL) {
+		status = TLS_P_hash(tlsPrfHash, &pms, "master secret",
 				    &crsr, &master, isFIPS);
 	    } else {
 		status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS);
 	    }
 	    if (status != SECSuccess) {
 	    	crv = CKR_FUNCTION_FAILED;
 		break;
 	    }
@@ -6170,31 +6246,44 @@
 	    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_TLS12_KEY_AND_MAC_DERIVE:
     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;
 	unsigned int            block_needed;
 	unsigned char           srcrdata[SSL3_RANDOM_LENGTH * 2];
 	unsigned char           crsrdata[SSL3_RANDOM_LENGTH * 2];
 
+        if (mechanism == CKM_TLS12_KEY_AND_MAC_DERIVE) {
+	    CK_TLS12_KEY_MAT_PARAMS *tls12_keys =
+		(CK_TLS12_KEY_MAT_PARAMS *) pMechanism->pParameter;
+	    tlsPrfHash = GetHashTypeFromMechanism(tls12_keys->prfHashMechanism);
+	    if (tlsPrfHash == HASH_AlgNULL) {
+		crv = CKR_MECHANISM_PARAM_INVALID;
+		break;
+	    }
+        } else if (mechanism == CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256) {
+	    tlsPrfHash = HASH_AlgSHA256;
+	}
+
+        if (mechanism != CKM_SSL3_KEY_AND_MAC_DERIVE) {
+	    isTLS = PR_TRUE;
+	}
+
 	crv = sftk_DeriveSensitiveCheck(sourceKey,key);
 	if (crv != CKR_OK) break;
 
 	if (att->attrib.ulValueLen != SSL3_MASTER_SECRET_LENGTH) {
 	    crv = CKR_KEY_FUNCTION_NOT_PERMITTED;
 	    break;
 	}
 	att2 = sftk_FindAttribute(sourceKey,CKA_KEY_TYPE);
@@ -6264,18 +6353,18 @@
 
 	    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;
 
-	    if (isSHA256) {
-		status = TLS_P_hash(HASH_AlgSHA256, &master, "key expansion",
+	    if (tlsPrfHash != HASH_AlgNULL) {
+		status = TLS_P_hash(tlsPrfHash, &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;
 	    }
@@ -7011,17 +7100,17 @@
 					SEC_ASN1_GET(SEC_OctetStringTemplate), 
 					&ecPoint);
 	    if (rv != SECSuccess) {
 		goto ec_loser;
 	    }
 	    ecPoint = newPoint;
 	}
 
-	if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
+	if (mechanism == CKM_ECDH1_COFACTOR_DERIVE) {
 	    withCofactor = PR_TRUE;
 	} else {
 	    /* When not using cofactor derivation, one should
 	     * validate the public key to avoid small subgroup
 	     * attacks.
 	     */
 	    if (EC_ValidatePublicKey(&privKey->u.ec.ecParams, &ecPoint) 
 		!= SECSuccess) {
diff --git a/lib/softoken/pkcs11i.h b/lib/softoken/pkcs11i.h
--- a/lib/softoken/pkcs11i.h
+++ b/lib/softoken/pkcs11i.h
@@ -25,6 +25,11 @@
  * the expense of space.
  */
 
+
+/* Was present in older nss-util, is missing in newer. Definition required to build. */
+#define CKM_TLS12_MAC                       0x000003E5
+
+
 /* 
  * The attribute allocation strategy is static allocation:
  *   Attributes are pre-allocated as part of the session object and used from
@@ -733,13 +733,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,
-		  HASH_HashType       hash_alg);
+		  HASH_HashType       hash_alg,
+		  unsigned int        out_len);
 
 SEC_END_PROTOS
 
 #endif /* _PKCS11I_H_ */
diff --git a/lib/softoken/tlsprf.c b/lib/softoken/tlsprf.c
--- a/lib/softoken/tlsprf.c
+++ b/lib/softoken/tlsprf.c
@@ -1,16 +1,17 @@
 /* tlsprf.c - TLS Pseudo Random Function (PRF) implementation
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "pkcs11i.h"
 #include "blapi.h"
+#include "secerr.h"
 
 #define SFTK_OFFSETOF(str, memb) ((PRPtrdiff)(&(((str *)0)->memb)))
 
 static void sftk_TLSPRFNull(void *data, PRBool freeit)
 {
     return;
 } 
 
@@ -18,16 +19,17 @@ 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 int   cxOutLen;	/* bytes of output if nonzero                */
     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;
@@ -82,17 +84,24 @@ sftk_TLSPRFUpdate(TLSPRFContext *cx,
 
     secretItem.data = cx->cxBufPtr;
     secretItem.len  = cx->cxKeyLen;
 
     seedItem.data = cx->cxBufPtr + cx->cxKeyLen;
     seedItem.len  = cx->cxDataLen;
 
     sigItem.data = sig;
-    sigItem.len  = maxLen;
+    if (cx->cxOutLen == 0) {
+	sigItem.len = maxLen;
+    } else if (cx->cxOutLen <= maxLen) {
+	sigItem.len = cx->cxOutLen;
+    } else {
+	PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+	return SECFailure;
+    }
 
     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)
@@ -137,17 +146,18 @@ sftk_TLSPRFHashDestroy(TLSPRFContext *cx
 	PORT_ZFree(cx, cx->cxSize);
     }
 }
 
 CK_RV
 sftk_TLSPRFInit(SFTKSessionContext *context, 
 		  SFTKObject *        key, 
 		  CK_KEY_TYPE         key_type,
-		  HASH_HashType       hash_alg)
+		  HASH_HashType       hash_alg,
+		  unsigned int        out_len)
 {
     SFTKAttribute * keyVal;
     TLSPRFContext * prf_cx;
     CK_RV           crv = CKR_HOST_MEMORY;
     PRUint32        keySize;
     PRUint32        blockSize;
 
     if (key_type != CKK_GENERIC_SECRET)
@@ -164,16 +174,17 @@ sftk_TLSPRFInit(SFTKSessionContext *cont
     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;
+    prf_cx->cxOutLen  = out_len;
     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;