From 9d98643622201dda4ee9a5217f26d546928d3961 Mon Sep 17 00:00:00 2001 From: "mcgreer%netscape.com" Date: Fri, 3 Aug 2001 18:50:54 +0000 Subject: [PATCH] fix for #92940, PKCS#12 broken in FIPS mode. Force keygen to occur on token, added new PKCS#11 mechanisms to handle PKCS#12 integrity key generation. --- security/nss/lib/pk11wrap/pk11func.h | 11 ++++++ security/nss/lib/pk11wrap/pk11skey.c | 47 +++++++++++++++++++++++++- security/nss/lib/pk11wrap/pk11slot.c | 3 ++ security/nss/lib/pkcs12/p12d.c | 50 +++++++++++++--------------- security/nss/lib/pkcs12/p12e.c | 36 ++++++++++++-------- security/nss/lib/softoken/pkcs11.c | 3 ++ security/nss/lib/softoken/pkcs11c.c | 45 ++++++++++++++++++++++++- security/nss/lib/softoken/pkcs11t.h | 3 ++ 8 files changed, 156 insertions(+), 42 deletions(-) diff --git a/security/nss/lib/pk11wrap/pk11func.h b/security/nss/lib/pk11wrap/pk11func.h index f3411681cb55..67fb9edc2bc5 100644 --- a/security/nss/lib/pk11wrap/pk11func.h +++ b/security/nss/lib/pk11wrap/pk11func.h @@ -455,6 +455,17 @@ void PK11_SetFortezzaHack(PK11SymKey *symKey) ; /********************************************************************** * PBE functions **********************************************************************/ + +/* This function creates PBE parameters from the given inputs. The result + * can be used to create a password integrity key for PKCS#12, by sending + * the return value to PK11_KeyGen along with the appropriate mechanism. + */ +SECItem * +PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations); + +/* free params created above (can be called after keygen is done */ +void PK11_DestroyPBEParams(SECItem *params); + SECAlgorithmID * PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt); PK11SymKey * diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c index 16417a8d8d3f..607deeba81bc 100644 --- a/security/nss/lib/pk11wrap/pk11skey.c +++ b/security/nss/lib/pk11wrap/pk11skey.c @@ -1207,7 +1207,7 @@ PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, int keySize, SECItem *keyid, PRBool isToken, void *wincx) { PK11SymKey *symKey; - CK_ATTRIBUTE genTemplate[4]; + CK_ATTRIBUTE genTemplate[5]; CK_ATTRIBUTE *attrs = genTemplate; int count = sizeof(genTemplate)/sizeof(genTemplate[0]); CK_SESSION_HANDLE session; @@ -1243,6 +1243,8 @@ PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *param, PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; } + PK11_SETATTRS(attrs, CKA_SIGN, &cktrue, sizeof(cktrue)); attrs++; + count = attrs - genTemplate; PR_ASSERT(count <= sizeof(genTemplate)/sizeof(CK_ATTRIBUTE)); @@ -4053,6 +4055,49 @@ PK11_DigestFinal(PK11Context *context,unsigned char *data, * ****************************************************************************/ +static void +pk11_destroy_ck_pbe_params(CK_PBE_PARAMS *pbe_params) +{ + if (pbe_params) { + if (pbe_params->pPassword) + PORT_ZFree(pbe_params->pPassword, PR_FALSE); + if (pbe_params->pSalt) + PORT_ZFree(pbe_params->pSalt, PR_FALSE); + PORT_ZFree(pbe_params, PR_TRUE); + } +} + +SECItem * +PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations) +{ + CK_PBE_PARAMS *pbe_params = NULL; + SECItem *paramRV = NULL; + pbe_params = (CK_PBE_PARAMS *)PORT_ZAlloc(sizeof(CK_PBE_PARAMS)); + pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwd->len); + if (pbe_params->pPassword != NULL) { + PORT_Memcpy(pbe_params->pPassword, pwd->data, pwd->len); + pbe_params->ulPasswordLen = pwd->len; + } else goto loser; + pbe_params->pSalt = (CK_CHAR_PTR)PORT_ZAlloc(salt->len); + if (pbe_params->pSalt != NULL) { + PORT_Memcpy(pbe_params->pSalt, salt->data, salt->len); + pbe_params->ulSaltLen = salt->len; + } else goto loser; + pbe_params->ulIteration = (CK_ULONG)iterations; + paramRV = SECITEM_AllocItem(NULL, NULL, sizeof(CK_PBE_PARAMS)); + paramRV->data = (unsigned char *)pbe_params; + return paramRV; +loser: + pk11_destroy_ck_pbe_params(pbe_params); + return NULL; +} + +void +PK11_DestroyPBEParams(SECItem *params) +{ + pk11_destroy_ck_pbe_params((CK_PBE_PARAMS *)params->data); +} + SECAlgorithmID * PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt) { diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c index 64601e46b8e5..595bf4065dfb 100644 --- a/security/nss/lib/pk11wrap/pk11slot.c +++ b/security/nss/lib/pk11wrap/pk11slot.c @@ -2829,6 +2829,9 @@ PK11_GetKeyGen(CK_MECHANISM_TYPE type) return CKM_GENERIC_SECRET_KEY_GEN; case CKM_PBE_MD2_DES_CBC: case CKM_PBE_MD5_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: + case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: + case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: diff --git a/security/nss/lib/pkcs12/p12d.c b/security/nss/lib/pkcs12/p12d.c index 9abae13c8f14..076e722ecd4d 100644 --- a/security/nss/lib/pkcs12/p12d.c +++ b/security/nss/lib/pkcs12/p12d.c @@ -1152,14 +1152,16 @@ static SECStatus sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx) { SECStatus rv = SECFailure; - PBEBitGenContext *pbeCtxt = NULL; - SECItem *hmacKey = NULL, hmacRes; + SECItem hmacRes; unsigned char buf[IN_BUF_LEN]; unsigned int bufLen; int iteration; PK11Context *pk11cx; - SECOidTag algtag; SECItem ignore = {0}; + PK11SymKey *symKey; + SECItem *params; + SECOidTag algtag; + CK_MECHANISM_TYPE integrityMech; if(!p12dcx || p12dcx->error) { return SECFailure; @@ -1171,28 +1173,28 @@ sec_pkcs12_decoder_verify_mac(SEC_PKCS12DecoderContext *p12dcx) } else { iteration = 1; } - pbeCtxt = PBE_CreateContext(SECOID_GetAlgorithmTag( - &p12dcx->macData.safeMac.digestAlgorithm), - pbeBitGenIntegrityKey, p12dcx->pwitem, - &p12dcx->macData.macSalt, 160, iteration); - if(!pbeCtxt) { - return SECFailure; - } - hmacKey = PBE_GenerateBits(pbeCtxt); - PBE_DestroyContext(pbeCtxt); - pbeCtxt = NULL; - if(!hmacKey) { - return SECFailure; + + params = PK11_CreatePBEParams(&p12dcx->macData.macSalt, p12dcx->pwitem, + iteration); + + algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm); + switch (algtag) { + case SEC_OID_SHA1: + integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break; + case SEC_OID_MD5: + integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break; + case SEC_OID_MD2: + integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break; + default: + goto loser; } + symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL); + PK11_DestroyPBEParams(params); + if (!symKey) goto loser; /* init hmac */ - algtag = SECOID_GetAlgorithmTag(&p12dcx->macData.safeMac.digestAlgorithm); - pk11cx = PK11_CreateContextByRawKey(NULL, - sec_pkcs12_algtag_to_mech(algtag), - PK11_OriginDerive, CKA_SIGN, - hmacKey, &ignore, NULL); - SECITEM_ZfreeItem(hmacKey, PR_TRUE); - hmacKey = NULL; + pk11cx = PK11_CreateContextBySymKey(sec_pkcs12_algtag_to_mech(algtag), + CKA_SIGN, symKey, &ignore); if(!pk11cx) { PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; @@ -1247,10 +1249,6 @@ loser: PK11_DestroyContext(pk11cx, PR_TRUE); } - if(hmacKey) { - SECITEM_ZfreeItem(hmacKey, PR_TRUE); - } - return rv; } diff --git a/security/nss/lib/pkcs12/p12e.c b/security/nss/lib/pkcs12/p12e.c index 4e6d76ebf3f6..22ff31104379 100644 --- a/security/nss/lib/pkcs12/p12e.c +++ b/security/nss/lib/pkcs12/p12e.c @@ -1660,9 +1660,11 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp) /* init password pased integrity mode */ if(p12exp->integrityEnabled) { - SECItem pwd = {siBuffer,NULL, 0}, *key; + SECItem pwd = {siBuffer,NULL, 0}; SECItem *salt = sec_pkcs12_generate_salt(); - PBEBitGenContext *pbeCtxt = NULL; + PK11SymKey *symKey; + SECItem *params; + CK_MECHANISM_TYPE integrityMech; /* zero out macData and set values */ PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData)); @@ -1676,7 +1678,6 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp) PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } - SECITEM_ZfreeItem(salt, PR_TRUE); /* generate HMAC key */ if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd, @@ -1684,25 +1685,32 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp) PR_TRUE, PR_TRUE)) { goto loser; } - pbeCtxt = PBE_CreateContext(p12exp->integrityInfo.pwdInfo.algorithm, - pbeBitGenIntegrityKey, &pwd, - &(p12enc->mac.macSalt), 160, 1); + + params = PK11_CreatePBEParams(salt, &pwd, 1); + SECITEM_ZfreeItem(salt, PR_TRUE); SECITEM_ZfreeItem(&pwd, PR_FALSE); - if(!pbeCtxt) { + + switch (p12exp->integrityInfo.pwdInfo.algorithm) { + case SEC_OID_SHA1: + integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break; + case SEC_OID_MD5: + integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break; + case SEC_OID_MD2: + integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break; + default: goto loser; } - key = PBE_GenerateBits(pbeCtxt); - PBE_DestroyContext(pbeCtxt); - if(!key) { + + symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL); + PK11_DestroyPBEParams(params); + if(!symKey) { goto loser; } /* initialize hmac */ - p12enc->hmacCx = PK11_CreateContextByRawKey(NULL, + p12enc->hmacCx = PK11_CreateContextBySymKey( sec_pkcs12_algtag_to_mech(p12exp->integrityInfo.pwdInfo.algorithm), - PK11_OriginDerive, CKA_SIGN, - key, &ignore, NULL); - SECITEM_ZfreeItem(key, PR_TRUE); + CKA_SIGN, symKey, &ignore); if(!p12enc->hmacCx) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index e0a73fa2bebb..4795a5d72d27 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -406,6 +406,9 @@ static struct mechanismList mechanisms[] = { {CKM_PBE_SHA1_RC2_128_CBC, {128,128, CKF_GENERATE}, PR_TRUE}, {CKM_PBE_SHA1_RC4_40, {40,40, CKF_GENERATE}, PR_TRUE}, {CKM_PBE_SHA1_RC4_128, {128,128, CKF_GENERATE}, PR_TRUE}, + {CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN, {1,32, CKF_GENERATE}, PR_TRUE}, + {CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN, {1,32, CKF_GENERATE}, PR_TRUE}, + {CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN, {1,32, CKF_GENERATE}, PR_TRUE}, }; static CK_ULONG mechanismCount = sizeof(mechanisms)/sizeof(mechanisms[0]); /* load up our token database */ diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index c96c8073f45f..634574a434d2 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -2832,6 +2832,40 @@ CK_RV NSC_GenerateRandom(CK_SESSION_HANDLE hSession, **************************** Key Functions: ************************ */ +CK_RV +pk11_pbe_hmac_key_gen(CK_MECHANISM_PTR pMechanism, char *buf, + unsigned long *len, PRBool faultyPBE3DES) +{ + PBEBitGenContext *pbeCx; + SECItem pwd, salt, *key; + SECOidTag hashAlg; + unsigned long keylenbits; + CK_PBE_PARAMS *pbe_params = NULL; + pbe_params = (CK_PBE_PARAMS *)pMechanism->pParameter; + pwd.data = (unsigned char *)pbe_params->pPassword; + pwd.len = (unsigned int)pbe_params->ulPasswordLen; + salt.data = (unsigned char *)pbe_params->pSalt; + salt.len = (unsigned int)pbe_params->ulSaltLen; + switch (pMechanism->mechanism) { + case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: + hashAlg = SEC_OID_SHA1; keylenbits = 160; break; + case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: + hashAlg = SEC_OID_MD5; keylenbits = 128; break; + case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: + hashAlg = SEC_OID_MD2; keylenbits = 128; break; + default: + return CKR_MECHANISM_INVALID; + } + pbeCx = PBE_CreateContext(hashAlg, pbeBitGenIntegrityKey, &pwd, + &salt, keylenbits, pbe_params->ulIteration); + key = PBE_GenerateBits(pbeCx); + PORT_Memcpy(buf, key->data, key->len); + *len = key->len; + PBE_DestroyContext(pbeCx); + SECITEM_ZfreeItem(key, PR_TRUE); + return CKR_OK; +} + /* * generate a password based encryption key. This code uses * PKCS5 to do the work. Note that it calls PBE_PK11ParamToAlgid, which is @@ -3041,7 +3075,7 @@ CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession, int i; PK11Slot *slot = pk11_SlotFromSessionHandle(hSession); char buf[MAX_KEY_LEN]; - enum {pk11_pbe, pk11_ssl, pk11_bulk} key_gen_type; + enum {pk11_pbe, pk11_pbe_hmac, pk11_ssl, pk11_bulk} key_gen_type; SECOidTag algtag = SEC_OID_UNKNOWN; SSL3RSAPreMasterSecret *rsa_pms; CK_VERSION *version; @@ -3106,6 +3140,11 @@ CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession, break; case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: faultyPBE3DES = PR_TRUE; + case CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN: + case CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN: + case CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN: + key_gen_type = pk11_pbe_hmac; + break; case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: case CKM_NETSCAPE_PBE_SHA1_DES_CBC: @@ -3142,6 +3181,10 @@ CK_RV NSC_GenerateKey(CK_SESSION_HANDLE hSession, * now to the actual key gen. */ switch (key_gen_type) { + case pk11_pbe_hmac: + crv = pk11_pbe_hmac_key_gen(pMechanism, buf, &key_length, + faultyPBE3DES); + break; case pk11_pbe: crv = pk11_pbe_key_gen(algtag, pMechanism, buf, &key_length, faultyPBE3DES); diff --git a/security/nss/lib/softoken/pkcs11t.h b/security/nss/lib/softoken/pkcs11t.h index c626036c8143..6cb3e74c4f8a 100644 --- a/security/nss/lib/softoken/pkcs11t.h +++ b/security/nss/lib/softoken/pkcs11t.h @@ -1112,6 +1112,9 @@ typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; #define CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4 0x80000006L #define CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4 0x80000007L #define CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC 0x80000008L +#define CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN 0x80000009L +#define CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN 0x8000000aL +#define CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN 0x8000000bL #define CKM_TLS_MASTER_KEY_DERIVE 0x80000371L #define CKM_TLS_KEY_AND_MAC_DERIVE 0x80000372L #define CKM_TLS_PRF_GENERAL 0x80000373L