| Index: mozilla/security/nss/lib/pk11wrap/pk11pbe.c
|
| ===================================================================
|
| --- mozilla/security/nss/lib/pk11wrap/pk11pbe.c (revision 191424)
|
| +++ mozilla/security/nss/lib/pk11wrap/pk11pbe.c (working copy)
|
| @@ -1,1432 +0,0 @@
|
| -/* 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 "plarena.h"
|
| -
|
| -#include "seccomon.h"
|
| -#include "secitem.h"
|
| -#include "secport.h"
|
| -#include "hasht.h"
|
| -#include "pkcs11t.h"
|
| -#include "sechash.h"
|
| -#include "secasn1.h"
|
| -#include "secder.h"
|
| -#include "secoid.h"
|
| -#include "secerr.h"
|
| -#include "secmod.h"
|
| -#include "pk11func.h"
|
| -#include "secpkcs5.h"
|
| -#include "secmodi.h"
|
| -#include "secmodti.h"
|
| -#include "pkcs11.h"
|
| -#include "pk11func.h"
|
| -#include "secitem.h"
|
| -#include "key.h"
|
| -
|
| -typedef struct SEC_PKCS5PBEParameterStr SEC_PKCS5PBEParameter;
|
| -struct SEC_PKCS5PBEParameterStr {
|
| - PRArenaPool *poolp;
|
| - SECItem salt; /* octet string */
|
| - SECItem iteration; /* integer */
|
| - SECItem keyLength; /* PKCS5v2 only */
|
| - SECAlgorithmID *pPrfAlgId; /* PKCS5v2 only */
|
| - SECAlgorithmID prfAlgId; /* PKCS5v2 only */
|
| -};
|
| -
|
| -/* PKCS5 V2 has an algorithm ID for the encryption and for
|
| - * the key generation. This is valid for SEC_OID_PKCS5_PBES2
|
| - * and SEC_OID_PKCS5_PBMAC1
|
| - */
|
| -struct sec_pkcs5V2ParameterStr {
|
| - PRArenaPool *poolp;
|
| - SECAlgorithmID pbeAlgId; /* real pbe algorithms */
|
| - SECAlgorithmID cipherAlgId; /* encryption/mac */
|
| -};
|
| -
|
| -typedef struct sec_pkcs5V2ParameterStr sec_pkcs5V2Parameter;
|
| -
|
| -
|
| -/* template for PKCS 5 PBE Parameter. This template has been expanded
|
| - * based upon the additions in PKCS 12. This should eventually be moved
|
| - * if RSA updates PKCS 5.
|
| - */
|
| -const SEC_ASN1Template SEC_PKCS5PBEParameterTemplate[] =
|
| -{
|
| - { SEC_ASN1_SEQUENCE,
|
| - 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
|
| - { SEC_ASN1_OCTET_STRING,
|
| - offsetof(SEC_PKCS5PBEParameter, salt) },
|
| - { SEC_ASN1_INTEGER,
|
| - offsetof(SEC_PKCS5PBEParameter, iteration) },
|
| - { 0 }
|
| -};
|
| -
|
| -const SEC_ASN1Template SEC_V2PKCS12PBEParameterTemplate[] =
|
| -{
|
| - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
|
| - { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) },
|
| - { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) },
|
| - { 0 }
|
| -};
|
| -
|
| -SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
|
| -
|
| -/* SECOID_PKCS5_PBKDF2 */
|
| -const SEC_ASN1Template SEC_PKCS5V2PBEParameterTemplate[] =
|
| -{
|
| - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
|
| - /* This is really a choice, but since we only understand this
|
| - * choice, just inline it */
|
| - { SEC_ASN1_OCTET_STRING, offsetof(SEC_PKCS5PBEParameter, salt) },
|
| - { SEC_ASN1_INTEGER, offsetof(SEC_PKCS5PBEParameter, iteration) },
|
| - { SEC_ASN1_INTEGER|SEC_ASN1_OPTIONAL,
|
| - offsetof(SEC_PKCS5PBEParameter, keyLength) },
|
| - { SEC_ASN1_POINTER | SEC_ASN1_XTRN | SEC_ASN1_OPTIONAL,
|
| - offsetof(SEC_PKCS5PBEParameter, pPrfAlgId),
|
| - SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
|
| - { 0 }
|
| -};
|
| -
|
| -/* SEC_OID_PKCS5_PBES2, SEC_OID_PKCS5_PBMAC1 */
|
| -const SEC_ASN1Template SEC_PKCS5V2ParameterTemplate[] =
|
| -{
|
| - { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS5PBEParameter) },
|
| - { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(sec_pkcs5V2Parameter, pbeAlgId),
|
| - SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
|
| - { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
|
| - offsetof(sec_pkcs5V2Parameter, cipherAlgId),
|
| - SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
|
| - { 0 }
|
| -};
|
| -
|
| -
|
| -/*
|
| - * maps a PBE algorithm to a crypto algorithm. for PKCS12 and PKCS5v1
|
| - * for PKCS5v2 it returns SEC_OID_PKCS5_PBKDF2.
|
| - */
|
| -SECOidTag
|
| -sec_pkcs5GetCryptoFromAlgTag(SECOidTag algorithm)
|
| -{
|
| - switch(algorithm)
|
| - {
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
|
| - return SEC_OID_DES_EDE3_CBC;
|
| - case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
|
| - case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
|
| - case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
|
| - return SEC_OID_DES_CBC;
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
|
| - return SEC_OID_RC2_CBC;
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
|
| - return SEC_OID_RC4;
|
| - case SEC_OID_PKCS5_PBKDF2:
|
| - case SEC_OID_PKCS5_PBES2:
|
| - case SEC_OID_PKCS5_PBMAC1:
|
| - return SEC_OID_PKCS5_PBKDF2;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - return SEC_OID_UNKNOWN;
|
| -}
|
| -
|
| -/*
|
| - * get a new PKCS5 V2 Parameter from the algorithm id.
|
| - * if arena is passed in, use it, otherwise create a new arena.
|
| - */
|
| -sec_pkcs5V2Parameter *
|
| -sec_pkcs5_v2_get_v2_param(PRArenaPool *arena, SECAlgorithmID *algid)
|
| -{
|
| - PRArenaPool *localArena = NULL;
|
| - sec_pkcs5V2Parameter *pbeV2_param;
|
| - SECStatus rv;
|
| -
|
| - if (arena == NULL) {
|
| - localArena = arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
| - if (arena == NULL) {
|
| - return NULL;
|
| - }
|
| - }
|
| - pbeV2_param = PORT_ArenaZNew(arena, sec_pkcs5V2Parameter);
|
| - if (pbeV2_param == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| - rv = SEC_ASN1DecodeItem(arena, pbeV2_param,
|
| - SEC_PKCS5V2ParameterTemplate, &algid->parameters);
|
| - if (rv == SECFailure) {
|
| - goto loser;
|
| - }
|
| -
|
| - pbeV2_param->poolp = arena;
|
| - return pbeV2_param;
|
| -loser:
|
| - if (localArena) {
|
| - PORT_FreeArena(arena, PR_FALSE);
|
| - }
|
| - return NULL;
|
| -}
|
| -
|
| -void
|
| -sec_pkcs5_v2_destroy_v2_param(sec_pkcs5V2Parameter *param)
|
| -{
|
| - if (param && param->poolp) {
|
| - PORT_FreeArena(param->poolp, PR_TRUE);
|
| - }
|
| -}
|
| -
|
| -
|
| -/* maps crypto algorithm from PBE algorithm.
|
| - */
|
| -SECOidTag
|
| -SEC_PKCS5GetCryptoAlgorithm(SECAlgorithmID *algid)
|
| -{
|
| -
|
| - SECOidTag pbeAlg;
|
| - SECOidTag cipherAlg;
|
| -
|
| - if(algid == NULL)
|
| - return SEC_OID_UNKNOWN;
|
| -
|
| - pbeAlg = SECOID_GetAlgorithmTag(algid);
|
| - cipherAlg = sec_pkcs5GetCryptoFromAlgTag(pbeAlg);
|
| - if ((cipherAlg == SEC_OID_PKCS5_PBKDF2) &&
|
| - (pbeAlg != SEC_OID_PKCS5_PBKDF2)) {
|
| - sec_pkcs5V2Parameter *pbeV2_param;
|
| - cipherAlg = SEC_OID_UNKNOWN;
|
| -
|
| - pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
|
| - if (pbeV2_param != NULL) {
|
| - cipherAlg = SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId);
|
| - sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
|
| - }
|
| - }
|
| -
|
| - return cipherAlg;
|
| -}
|
| -
|
| -/* check to see if an oid is a pbe algorithm
|
| - */
|
| -PRBool
|
| -SEC_PKCS5IsAlgorithmPBEAlg(SECAlgorithmID *algid)
|
| -{
|
| - return (PRBool)(SEC_PKCS5GetCryptoAlgorithm(algid) != SEC_OID_UNKNOWN);
|
| -}
|
| -
|
| -PRBool
|
| -SEC_PKCS5IsAlgorithmPBEAlgTag(SECOidTag algtag)
|
| -{
|
| - return (PRBool)(sec_pkcs5GetCryptoFromAlgTag(algtag) != SEC_OID_UNKNOWN);
|
| -}
|
| -
|
| -/*
|
| - * find the most appropriate PKCS5v2 overall oid tag from a regular
|
| - * cipher/hash algorithm tag.
|
| - */
|
| -static SECOidTag
|
| -sec_pkcs5v2_get_pbe(SECOidTag algTag)
|
| -{
|
| - /* if it's a valid hash oid... */
|
| - if (HASH_GetHashOidTagByHMACOidTag(algTag) != SEC_OID_UNKNOWN) {
|
| - /* use the MAC tag */
|
| - return SEC_OID_PKCS5_PBMAC1;
|
| - }
|
| - if (HASH_GetHashTypeByOidTag(algTag) != HASH_AlgNULL) {
|
| - /* eliminate Hash algorithms */
|
| - return SEC_OID_UNKNOWN;
|
| - }
|
| - if (PK11_AlgtagToMechanism(algTag) != CKM_INVALID_MECHANISM) {
|
| - /* it's not a hash, if it has a PKCS #11 mechanism associated
|
| - * with it, assume it's a cipher. (NOTE this will generate
|
| - * some false positives). */
|
| - return SEC_OID_PKCS5_PBES2;
|
| - }
|
| - return SEC_OID_UNKNOWN;
|
| -}
|
| -
|
| -/*
|
| - * maps PBE algorithm from crypto algorithm, assumes SHA1 hashing.
|
| - * input keyLen in bits.
|
| - */
|
| -SECOidTag
|
| -SEC_PKCS5GetPBEAlgorithm(SECOidTag algTag, int keyLen)
|
| -{
|
| - switch(algTag)
|
| - {
|
| - case SEC_OID_DES_EDE3_CBC:
|
| - switch(keyLen) {
|
| - case 168:
|
| - case 192:
|
| - case 0:
|
| - return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC;
|
| - case 128:
|
| - case 92:
|
| - return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case SEC_OID_DES_CBC:
|
| - return SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC;
|
| - case SEC_OID_RC2_CBC:
|
| - switch(keyLen) {
|
| - case 40:
|
| - return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC;
|
| - case 128:
|
| - case 0:
|
| - return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case SEC_OID_RC4:
|
| - switch(keyLen) {
|
| - case 40:
|
| - return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4;
|
| - case 128:
|
| - case 0:
|
| - return SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - default:
|
| - return sec_pkcs5v2_get_pbe(algTag);
|
| - }
|
| -
|
| - return SEC_OID_UNKNOWN;
|
| -}
|
| -
|
| -/*
|
| - * get the key length in bytes from a PKCS5 PBE
|
| - */
|
| -int
|
| -sec_pkcs5v2_key_length(SECAlgorithmID *algid)
|
| -{
|
| - SECOidTag algorithm;
|
| - PRArenaPool *arena = NULL;
|
| - SEC_PKCS5PBEParameter p5_param;
|
| - SECStatus rv;
|
| - int length = -1;
|
| -
|
| - algorithm = SECOID_GetAlgorithmTag(algid);
|
| - /* sanity check, they should all be PBKDF2 here */
|
| - if (algorithm != SEC_OID_PKCS5_PBKDF2) {
|
| - return -1;
|
| - }
|
| -
|
| - arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
| - if (arena == NULL) {
|
| - goto loser;
|
| - }
|
| - PORT_Memset(&p5_param, 0, sizeof(p5_param));
|
| - rv = SEC_ASN1DecodeItem(arena,&p5_param,
|
| - SEC_PKCS5V2PBEParameterTemplate, &algid->parameters);
|
| - if (rv != SECSuccess) {
|
| - goto loser;
|
| - }
|
| -
|
| - if (p5_param.keyLength.data != NULL) {
|
| - length = DER_GetInteger(&p5_param.keyLength);
|
| - }
|
| -
|
| -loser:
|
| - if (arena) {
|
| - PORT_FreeArena(arena, PR_FALSE);
|
| - }
|
| - return length;
|
| -}
|
| -
|
| -/*
|
| - * get the key length in bytes needed for the PBE algorithm
|
| - */
|
| -int
|
| -SEC_PKCS5GetKeyLength(SECAlgorithmID *algid)
|
| -{
|
| -
|
| - SECOidTag algorithm;
|
| -
|
| - if(algid == NULL)
|
| - return SEC_OID_UNKNOWN;
|
| -
|
| - algorithm = SECOID_GetAlgorithmTag(algid);
|
| -
|
| - switch(algorithm)
|
| - {
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
|
| - return 24;
|
| - case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC:
|
| - case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC:
|
| - case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC:
|
| - return 8;
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
|
| - return 5;
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
|
| - return 16;
|
| - case SEC_OID_PKCS5_PBKDF2:
|
| - return sec_pkcs5v2_key_length(algid);
|
| - case SEC_OID_PKCS5_PBES2:
|
| - case SEC_OID_PKCS5_PBMAC1:
|
| - {
|
| - sec_pkcs5V2Parameter *pbeV2_param;
|
| - int length = -1;
|
| - pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
|
| - if (pbeV2_param != NULL) {
|
| - length = sec_pkcs5v2_key_length(&pbeV2_param->pbeAlgId);
|
| - sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
|
| - }
|
| - return length;
|
| - }
|
| -
|
| - default:
|
| - break;
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -
|
| -/* the PKCS12 V2 algorithms only encode the salt, there is no iteration
|
| - * count so we need a check for V2 algorithm parameters.
|
| - */
|
| -static PRBool
|
| -sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(SECOidTag algorithm)
|
| -{
|
| - switch(algorithm)
|
| - {
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC:
|
| - case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC:
|
| - return PR_TRUE;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - return PR_FALSE;
|
| -}
|
| -
|
| -static PRBool
|
| -sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(SECOidTag algorithm)
|
| -{
|
| - switch(algorithm)
|
| - {
|
| - case SEC_OID_PKCS5_PBES2:
|
| - case SEC_OID_PKCS5_PBMAC1:
|
| - case SEC_OID_PKCS5_PBKDF2:
|
| - return PR_TRUE;
|
| - default:
|
| - break;
|
| - }
|
| -
|
| - return PR_FALSE;
|
| -}
|
| -
|
| -/* destroy a pbe parameter. it assumes that the parameter was
|
| - * generated using the appropriate create function and therefor
|
| - * contains an arena pool.
|
| - */
|
| -static void
|
| -sec_pkcs5_destroy_pbe_param(SEC_PKCS5PBEParameter *pbe_param)
|
| -{
|
| - if(pbe_param != NULL)
|
| - PORT_FreeArena(pbe_param->poolp, PR_TRUE);
|
| -}
|
| -
|
| -/* creates a PBE parameter based on the PBE algorithm. the only required
|
| - * parameters are algorithm and interation. the return is a PBE parameter
|
| - * which conforms to PKCS 5 parameter unless an extended parameter is needed.
|
| - * this is primarily if keyLength and a variable key length algorithm are
|
| - * specified.
|
| - * salt - if null, a salt will be generated from random bytes.
|
| - * iteration - number of iterations to perform hashing.
|
| - * keyLength - only used in variable key length algorithms. if specified,
|
| - * should be in bytes.
|
| - * once a parameter is allocated, it should be destroyed calling
|
| - * sec_pkcs5_destroy_pbe_parameter or SEC_PKCS5DestroyPBEParameter.
|
| - */
|
| -#define DEFAULT_SALT_LENGTH 16
|
| -static SEC_PKCS5PBEParameter *
|
| -sec_pkcs5_create_pbe_parameter(SECOidTag algorithm,
|
| - SECItem *salt,
|
| - int iteration,
|
| - int keyLength,
|
| - SECOidTag prfAlg)
|
| -{
|
| - PRArenaPool *poolp = NULL;
|
| - SEC_PKCS5PBEParameter *pbe_param = NULL;
|
| - SECStatus rv= SECSuccess;
|
| - void *dummy = NULL;
|
| -
|
| - if(iteration < 0) {
|
| - return NULL;
|
| - }
|
| -
|
| - poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
| - if(poolp == NULL)
|
| - return NULL;
|
| -
|
| - pbe_param = (SEC_PKCS5PBEParameter *)PORT_ArenaZAlloc(poolp,
|
| - sizeof(SEC_PKCS5PBEParameter));
|
| - if(!pbe_param) {
|
| - PORT_FreeArena(poolp, PR_TRUE);
|
| - return NULL;
|
| - }
|
| -
|
| - pbe_param->poolp = poolp;
|
| -
|
| - rv = SECFailure;
|
| - if (salt && salt->data) {
|
| - rv = SECITEM_CopyItem(poolp, &pbe_param->salt, salt);
|
| - } else {
|
| - /* sigh, the old interface generated salt on the fly, so we have to
|
| - * preserve the semantics */
|
| - pbe_param->salt.len = DEFAULT_SALT_LENGTH;
|
| - pbe_param->salt.data = PORT_ArenaZAlloc(poolp,DEFAULT_SALT_LENGTH);
|
| - if (pbe_param->salt.data) {
|
| - rv = PK11_GenerateRandom(pbe_param->salt.data,DEFAULT_SALT_LENGTH);
|
| - }
|
| - }
|
| -
|
| - if(rv != SECSuccess) {
|
| - PORT_FreeArena(poolp, PR_TRUE);
|
| - return NULL;
|
| - }
|
| -
|
| - /* encode the integer */
|
| - dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->iteration,
|
| - iteration);
|
| - rv = (dummy) ? SECSuccess : SECFailure;
|
| -
|
| - if(rv != SECSuccess) {
|
| - PORT_FreeArena(poolp, PR_FALSE);
|
| - return NULL;
|
| - }
|
| -
|
| - /*
|
| - * for PKCS5 v2 Add the keylength and the prf
|
| - */
|
| - if (algorithm == SEC_OID_PKCS5_PBKDF2) {
|
| - dummy = SEC_ASN1EncodeInteger(poolp, &pbe_param->keyLength,
|
| - keyLength);
|
| - rv = (dummy) ? SECSuccess : SECFailure;
|
| - if (rv != SECSuccess) {
|
| - PORT_FreeArena(poolp, PR_FALSE);
|
| - return NULL;
|
| - }
|
| - rv = SECOID_SetAlgorithmID(poolp, &pbe_param->prfAlgId, prfAlg, NULL);
|
| - if (rv != SECSuccess) {
|
| - PORT_FreeArena(poolp, PR_FALSE);
|
| - return NULL;
|
| - }
|
| - pbe_param->pPrfAlgId = &pbe_param->prfAlgId;
|
| - }
|
| -
|
| - return pbe_param;
|
| -}
|
| -
|
| -/* creates a algorithm ID containing the PBE algorithm and appropriate
|
| - * parameters. the required parameter is the algorithm. if salt is
|
| - * not specified, it is generated randomly.
|
| - *
|
| - * the returned SECAlgorithmID should be destroyed using
|
| - * SECOID_DestroyAlgorithmID
|
| - */
|
| -SECAlgorithmID *
|
| -sec_pkcs5CreateAlgorithmID(SECOidTag algorithm,
|
| - SECOidTag cipherAlgorithm,
|
| - SECOidTag prfAlg,
|
| - SECOidTag *pPbeAlgorithm,
|
| - int keyLength,
|
| - SECItem *salt,
|
| - int iteration)
|
| -{
|
| - PRArenaPool *poolp = NULL;
|
| - SECAlgorithmID *algid, *ret_algid = NULL;
|
| - SECOidTag pbeAlgorithm = algorithm;
|
| - SECItem der_param;
|
| - void *dummy;
|
| - SECStatus rv = SECFailure;
|
| - SEC_PKCS5PBEParameter *pbe_param = NULL;
|
| - sec_pkcs5V2Parameter pbeV2_param;
|
| -
|
| - if(iteration <= 0) {
|
| - return NULL;
|
| - }
|
| -
|
| - poolp = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
| - if(!poolp) {
|
| - goto loser;
|
| - }
|
| -
|
| - if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm) ||
|
| - sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
|
| - /* use PKCS 5 v2 */
|
| - SECItem *cipherParams;
|
| -
|
| - /*
|
| - * if we ask for pkcs5 Algorithms directly, then the
|
| - * application needs to supply the cipher algorithm,
|
| - * otherwise we are implicitly using pkcs5 v2 and the
|
| - * passed in algorithm is the encryption algorithm.
|
| - */
|
| - if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
|
| - if (cipherAlgorithm == SEC_OID_UNKNOWN) {
|
| - goto loser;
|
| - }
|
| - } else {
|
| - cipherAlgorithm = algorithm;
|
| - /* force algorithm to be chosen below */
|
| - algorithm = SEC_OID_PKCS5_PBKDF2;
|
| - }
|
| -
|
| - pbeAlgorithm = SEC_OID_PKCS5_PBKDF2;
|
| - /*
|
| - * 'algorithm' is the overall algorithm oid tag used to wrap the
|
| - * entire algoithm ID block. For PKCS5v1 and PKCS12, this
|
| - * algorithm OID has encoded in it both the PBE KDF function
|
| - * and the encryption algorithm. For PKCS 5v2, PBE KDF and
|
| - * encryption/macing oids are encoded as parameters in
|
| - * the algorithm ID block.
|
| - *
|
| - * Thus in PKCS5 v1 and PKCS12, this algorithm maps to a pkcs #11
|
| - * mechanism, where as in PKCS 5v2, this alogithm tag does not map
|
| - * directly to a PKCS #11 mechanim, instead the 2 oids in the
|
| - * algorithm ID block map the the actual PKCS #11 mechanism.
|
| - * gorithm is). We use choose this algorithm oid based on the
|
| - * cipherAlgorithm to determine what this should be (MAC1 or PBES2).
|
| - */
|
| - if (algorithm == SEC_OID_PKCS5_PBKDF2) {
|
| - /* choose mac or pbes */
|
| - algorithm = sec_pkcs5v2_get_pbe(cipherAlgorithm);
|
| - }
|
| -
|
| - /* set the PKCS5v2 specific parameters */
|
| - if (keyLength == 0) {
|
| - SECOidTag hashAlg = HASH_GetHashOidTagByHMACOidTag(cipherAlgorithm);
|
| - if (hashAlg != SEC_OID_UNKNOWN) {
|
| - keyLength = HASH_ResultLenByOidTag(hashAlg);
|
| - } else {
|
| - CK_MECHANISM_TYPE cryptoMech;
|
| - cryptoMech = PK11_AlgtagToMechanism(cipherAlgorithm);
|
| - if (cryptoMech == CKM_INVALID_MECHANISM) {
|
| - goto loser;
|
| - }
|
| - keyLength = PK11_GetMaxKeyLength(cryptoMech);
|
| - }
|
| - if (keyLength == 0) {
|
| - goto loser;
|
| - }
|
| - }
|
| - /* currently only SEC_OID_HMAC_SHA1 is defined */
|
| - if (prfAlg == SEC_OID_UNKNOWN) {
|
| - prfAlg = SEC_OID_HMAC_SHA1;
|
| - }
|
| -
|
| - /* build the PKCS5v2 cipher algorithm id */
|
| - cipherParams = pk11_GenerateNewParamWithKeyLen(
|
| - PK11_AlgtagToMechanism(cipherAlgorithm), keyLength);
|
| - if (!cipherParams) {
|
| - goto loser;
|
| - }
|
| -
|
| - PORT_Memset(&pbeV2_param, 0, sizeof (pbeV2_param));
|
| -
|
| - rv = PK11_ParamToAlgid(cipherAlgorithm, cipherParams,
|
| - poolp, &pbeV2_param.cipherAlgId);
|
| - SECITEM_FreeItem(cipherParams, PR_TRUE);
|
| - if (rv != SECSuccess) {
|
| - goto loser;
|
| - }
|
| - }
|
| -
|
| -
|
| - /* generate the parameter */
|
| - pbe_param = sec_pkcs5_create_pbe_parameter(pbeAlgorithm, salt, iteration,
|
| - keyLength, prfAlg);
|
| - if(!pbe_param) {
|
| - goto loser;
|
| - }
|
| -
|
| - /* generate the algorithm id */
|
| - algid = (SECAlgorithmID *)PORT_ArenaZAlloc(poolp, sizeof(SECAlgorithmID));
|
| - if(algid == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| - der_param.data = NULL;
|
| - der_param.len = 0;
|
| - if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(algorithm)) {
|
| - /* first encode the PBE algorithm ID */
|
| - dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
|
| - SEC_PKCS5V2PBEParameterTemplate);
|
| - if (dummy == NULL) {
|
| - goto loser;
|
| - }
|
| - rv = SECOID_SetAlgorithmID(poolp, &pbeV2_param.pbeAlgId,
|
| - pbeAlgorithm, &der_param);
|
| - if (rv != SECSuccess) {
|
| - goto loser;
|
| - }
|
| -
|
| - /* now encode the Full PKCS 5 parameter */
|
| - der_param.data = NULL;
|
| - der_param.len = 0;
|
| - dummy = SEC_ASN1EncodeItem(poolp, &der_param, &pbeV2_param,
|
| - SEC_PKCS5V2ParameterTemplate);
|
| - } else if(!sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {
|
| - dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
|
| - SEC_PKCS5PBEParameterTemplate);
|
| - } else {
|
| - dummy = SEC_ASN1EncodeItem(poolp, &der_param, pbe_param,
|
| - SEC_V2PKCS12PBEParameterTemplate);
|
| - }
|
| - if (dummy == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| - rv = SECOID_SetAlgorithmID(poolp, algid, algorithm, &der_param);
|
| - if (rv != SECSuccess) {
|
| - goto loser;
|
| - }
|
| -
|
| - ret_algid = (SECAlgorithmID *)PORT_ZAlloc(sizeof(SECAlgorithmID));
|
| - if (ret_algid == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| - rv = SECOID_CopyAlgorithmID(NULL, ret_algid, algid);
|
| - if (rv != SECSuccess) {
|
| - SECOID_DestroyAlgorithmID(ret_algid, PR_TRUE);
|
| - ret_algid = NULL;
|
| - } else if (pPbeAlgorithm) {
|
| - *pPbeAlgorithm = pbeAlgorithm;
|
| - }
|
| -
|
| -loser:
|
| - if (poolp != NULL) {
|
| - PORT_FreeArena(poolp, PR_TRUE);
|
| - algid = NULL;
|
| - }
|
| -
|
| - if (pbe_param) {
|
| - sec_pkcs5_destroy_pbe_param(pbe_param);
|
| - }
|
| -
|
| - return ret_algid;
|
| -}
|
| -
|
| -SECStatus
|
| -pbe_PK11AlgidToParam(SECAlgorithmID *algid,SECItem *mech)
|
| -{
|
| - SEC_PKCS5PBEParameter p5_param;
|
| - SECItem *salt = NULL;
|
| - SECOidTag algorithm = SECOID_GetAlgorithmTag(algid);
|
| - PRArenaPool *arena = NULL;
|
| - SECStatus rv = SECFailure;
|
| - unsigned char *paramData = NULL;
|
| - unsigned char *pSalt = NULL;
|
| - CK_ULONG iterations;
|
| - int paramLen = 0;
|
| - int iv_len;
|
| -
|
| -
|
| - arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
|
| - if (arena == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| -
|
| - /*
|
| - * decode the algid based on the pbe type
|
| - */
|
| - PORT_Memset(&p5_param, 0, sizeof(p5_param));
|
| - if (sec_pkcs5_is_algorithm_v2_pkcs12_algorithm(algorithm)) {
|
| - iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm));
|
| - rv = SEC_ASN1DecodeItem(arena, &p5_param,
|
| - SEC_V2PKCS12PBEParameterTemplate, &algid->parameters);
|
| - } else if (algorithm == SEC_OID_PKCS5_PBKDF2) {
|
| - iv_len = 0;
|
| - rv = SEC_ASN1DecodeItem(arena,&p5_param,
|
| - SEC_PKCS5V2PBEParameterTemplate, &algid->parameters);
|
| - } else {
|
| - iv_len = PK11_GetIVLength(PK11_AlgtagToMechanism(algorithm));
|
| - rv = SEC_ASN1DecodeItem(arena,&p5_param,SEC_PKCS5PBEParameterTemplate,
|
| - &algid->parameters);
|
| - }
|
| -
|
| - if (iv_len < 0) {
|
| - goto loser;
|
| - }
|
| -
|
| - if (rv != SECSuccess) {
|
| - goto loser;
|
| - }
|
| -
|
| - /* get salt */
|
| - salt = &p5_param.salt;
|
| - iterations = (CK_ULONG) DER_GetInteger(&p5_param.iteration);
|
| -
|
| - /* allocate and fill in the PKCS #11 parameters
|
| - * based on the algorithm. */
|
| - if (algorithm == SEC_OID_PKCS5_PBKDF2) {
|
| - SECOidTag prfAlgTag;
|
| - CK_PKCS5_PBKD2_PARAMS *pbeV2_params =
|
| - (CK_PKCS5_PBKD2_PARAMS *)PORT_ZAlloc(
|
| - sizeof(CK_PKCS5_PBKD2_PARAMS)+ salt->len);
|
| -
|
| - if (pbeV2_params == NULL) {
|
| - goto loser;
|
| - }
|
| - paramData = (unsigned char *)pbeV2_params;
|
| - paramLen = sizeof(CK_PKCS5_PBKD2_PARAMS);
|
| -
|
| - /* set the prf */
|
| - prfAlgTag = SEC_OID_HMAC_SHA1;
|
| - if (p5_param.pPrfAlgId &&
|
| - p5_param.pPrfAlgId->algorithm.data != 0) {
|
| - prfAlgTag = SECOID_GetAlgorithmTag(p5_param.pPrfAlgId);
|
| - }
|
| - if (prfAlgTag == SEC_OID_HMAC_SHA1) {
|
| - pbeV2_params->prf = CKP_PKCS5_PBKD2_HMAC_SHA1;
|
| - } else {
|
| - /* only SHA1_HMAC is currently supported by PKCS #11 */
|
| - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
| - goto loser;
|
| - }
|
| -
|
| - /* probably should fetch these from the prfAlgid */
|
| - pbeV2_params->pPrfData = NULL;
|
| - pbeV2_params->ulPrfDataLen = 0;
|
| - pbeV2_params->saltSource = CKZ_SALT_SPECIFIED;
|
| - pSalt = ((CK_CHAR_PTR) pbeV2_params)+sizeof(CK_PKCS5_PBKD2_PARAMS);
|
| - PORT_Memcpy(pSalt, salt->data, salt->len);
|
| - pbeV2_params->pSaltSourceData = pSalt;
|
| - pbeV2_params->ulSaltSourceDataLen = salt->len;
|
| - pbeV2_params->iterations = iterations;
|
| - } else {
|
| - CK_PBE_PARAMS *pbe_params = NULL;
|
| - pbe_params = (CK_PBE_PARAMS *)PORT_ZAlloc(sizeof(CK_PBE_PARAMS)+
|
| - salt->len+iv_len);
|
| - if (pbe_params == NULL) {
|
| - goto loser;
|
| - }
|
| - paramData = (unsigned char *)pbe_params;
|
| - paramLen = sizeof(CK_PBE_PARAMS);
|
| -
|
| - pSalt = ((CK_CHAR_PTR) pbe_params)+sizeof(CK_PBE_PARAMS);
|
| - pbe_params->pSalt = pSalt;
|
| - PORT_Memcpy(pSalt, salt->data, salt->len);
|
| - pbe_params->ulSaltLen = salt->len;
|
| - if (iv_len) {
|
| - pbe_params->pInitVector =
|
| - ((CK_CHAR_PTR) pbe_params)+ sizeof(CK_PBE_PARAMS)+salt->len;
|
| - }
|
| - pbe_params->ulIteration = iterations;
|
| - }
|
| -
|
| - /* copy into the mechanism sec item */
|
| - mech->data = paramData;
|
| - mech->len = paramLen;
|
| - if (arena) {
|
| - PORT_FreeArena(arena,PR_TRUE);
|
| - }
|
| - return SECSuccess;
|
| -
|
| -loser:
|
| - if (paramData) {
|
| - PORT_Free(paramData);
|
| - }
|
| - if (arena) {
|
| - PORT_FreeArena(arena,PR_TRUE);
|
| - }
|
| - return SECFailure;
|
| -}
|
| -
|
| -/*
|
| - * public, deprecated, not valid for pkcs5 v2
|
| - *
|
| - * use PK11_CreatePBEV2AlgorithmID or PK11_CreatePBEAlgorithmID to create
|
| - * PBE algorithmID's directly.
|
| - */
|
| -SECStatus
|
| -PBE_PK11ParamToAlgid(SECOidTag algTag, SECItem *param, PRArenaPool *arena,
|
| - SECAlgorithmID *algId)
|
| -{
|
| - CK_PBE_PARAMS *pbe_param;
|
| - SECItem pbeSalt;
|
| - SECAlgorithmID *pbeAlgID = NULL;
|
| - SECStatus rv;
|
| -
|
| - if(!param || !algId) {
|
| - return SECFailure;
|
| - }
|
| -
|
| - pbe_param = (CK_PBE_PARAMS *)param->data;
|
| - pbeSalt.data = (unsigned char *)pbe_param->pSalt;
|
| - pbeSalt.len = pbe_param->ulSaltLen;
|
| - pbeAlgID = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN,
|
| - SEC_OID_UNKNOWN, NULL, 0, &pbeSalt, (int)pbe_param->ulIteration);
|
| - if(!pbeAlgID) {
|
| - return SECFailure;
|
| - }
|
| -
|
| - rv = SECOID_CopyAlgorithmID(arena, algId, pbeAlgID);
|
| - SECOID_DestroyAlgorithmID(pbeAlgID, PR_TRUE);
|
| - return rv;
|
| -}
|
| -
|
| -/*
|
| - * public, Deprecated, This function is only for binary compatibility with
|
| - * older applications. Does not support PKCS5v2.
|
| - *
|
| - * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for
|
| - * iv values rather than generating PBE bits directly.
|
| - */
|
| -PBEBitGenContext *
|
| -PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
|
| - SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
|
| - unsigned int iterations)
|
| -{
|
| - SECItem *context = NULL;
|
| - SECItem mechItem;
|
| - CK_PBE_PARAMS pbe_params;
|
| - CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM;
|
| - PK11SlotInfo *slot;
|
| - PK11SymKey *symKey = NULL;
|
| - unsigned char ivData[8];
|
| -
|
| -
|
| - /* use the purpose to select the low level keygen algorithm */
|
| - switch (bitGenPurpose) {
|
| - case pbeBitGenIntegrityKey:
|
| - switch (hashAlgorithm) {
|
| - case SEC_OID_SHA1:
|
| - mechanism = CKM_PBA_SHA1_WITH_SHA1_HMAC;
|
| - break;
|
| - case SEC_OID_MD2:
|
| - mechanism = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN;
|
| - break;
|
| - case SEC_OID_MD5:
|
| - mechanism = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN;
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - break;
|
| - case pbeBitGenCipherIV:
|
| - if (bitsNeeded > 64) {
|
| - break;
|
| - }
|
| - if (hashAlgorithm != SEC_OID_SHA1) {
|
| - break;
|
| - }
|
| - mechanism = CKM_PBE_SHA1_DES3_EDE_CBC;
|
| - break;
|
| - case pbeBitGenCipherKey:
|
| - if (hashAlgorithm != SEC_OID_SHA1) {
|
| - break;
|
| - }
|
| - switch (bitsNeeded) {
|
| - case 40:
|
| - mechanism = CKM_PBE_SHA1_RC4_40;
|
| - break;
|
| - case 128:
|
| - mechanism = CKM_PBE_SHA1_RC4_128;
|
| - break;
|
| - default:
|
| - break;
|
| - }
|
| - case pbeBitGenIDNull:
|
| - break;
|
| - }
|
| -
|
| - if (mechanism == CKM_INVALID_MECHANISM) {
|
| - /* we should set an error, but this is a deprecated function, and
|
| - * we are keeping bug for bug compatibility;)... */
|
| - return NULL;
|
| - }
|
| -
|
| - pbe_params.pInitVector = ivData;
|
| - pbe_params.pPassword = pwitem->data;
|
| - pbe_params.ulPasswordLen = pwitem->len;
|
| - pbe_params.pSalt = salt->data;
|
| - pbe_params.ulSaltLen = salt->len;
|
| - pbe_params.ulIteration = iterations;
|
| - mechItem.data = (unsigned char *) &pbe_params;
|
| - mechItem.len = sizeof(pbe_params);
|
| -
|
| -
|
| - slot = PK11_GetInternalSlot();
|
| - symKey = PK11_RawPBEKeyGen(slot,mechanism,
|
| - &mechItem, pwitem, PR_FALSE, NULL);
|
| - PK11_FreeSlot(slot);
|
| - if (symKey != NULL) {
|
| - if (bitGenPurpose == pbeBitGenCipherIV) {
|
| - /* NOTE: this assumes that bitsNeeded is a multiple of 8! */
|
| - SECItem ivItem;
|
| -
|
| - ivItem.data = ivData;
|
| - ivItem.len = bitsNeeded/8;
|
| - context = SECITEM_DupItem(&ivItem);
|
| - } else {
|
| - SECItem *keyData;
|
| - PK11_ExtractKeyValue(symKey);
|
| - keyData = PK11_GetKeyData(symKey);
|
| -
|
| - /* assert bitsNeeded with length? */
|
| - if (keyData) {
|
| - context = SECITEM_DupItem(keyData);
|
| - }
|
| - }
|
| - PK11_FreeSymKey(symKey);
|
| - }
|
| -
|
| - return (PBEBitGenContext *)context;
|
| -}
|
| -
|
| -/*
|
| - * public, Deprecated, This function is only for binary compatibility with
|
| - * older applications. Does not support PKCS5v2.
|
| - *
|
| - * Applications should use PK11_PBEKeyGen() for keys and PK11_GetIV() for
|
| - * iv values rather than generating PBE bits directly.
|
| - */
|
| -SECItem *
|
| -PBE_GenerateBits(PBEBitGenContext *context)
|
| -{
|
| - return (SECItem *)context;
|
| -}
|
| -
|
| -/*
|
| - * public, Deprecated, This function is only for binary compatibility with
|
| - * older applications. Does not support PKCS5v2.
|
| - *
|
| - * Applications should use PK11_PBEKeyGen() for keys and PK11_GetPBEIV() for
|
| - * iv values rather than generating PBE bits directly.
|
| - */
|
| -void
|
| -PBE_DestroyContext(PBEBitGenContext *context)
|
| -{
|
| - SECITEM_FreeItem((SECItem *)context,PR_TRUE);
|
| -}
|
| -
|
| -/*
|
| - * public, deprecated. Replaced with PK11_GetPBEIV().
|
| - */
|
| -SECItem *
|
| -SEC_PKCS5GetIV(SECAlgorithmID *algid, SECItem *pwitem, PRBool faulty3DES)
|
| -{
|
| - /* pbe stuff */
|
| - CK_MECHANISM_TYPE type;
|
| - SECItem *param = NULL;
|
| - SECItem *iv = NULL;
|
| - SECItem src;
|
| - int iv_len = 0;
|
| - PK11SymKey *symKey;
|
| - PK11SlotInfo *slot;
|
| - CK_PBE_PARAMS_PTR pPBEparams;
|
| - SECOidTag pbeAlg;
|
| -
|
| - pbeAlg = SECOID_GetAlgorithmTag(algid);
|
| - if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) {
|
| - unsigned char *ivData;
|
| - sec_pkcs5V2Parameter *pbeV2_param = NULL;
|
| -
|
| - /* can only return the IV if the crypto Algorithm exists */
|
| - if (pbeAlg == SEC_OID_PKCS5_PBKDF2) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
| - goto loser;
|
| - }
|
| - pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
|
| - if (pbeV2_param == NULL) {
|
| - goto loser;
|
| - }
|
| - /* extract the IV from the cipher algid portion of our pkcs 5 v2
|
| - * algorithm id */
|
| - type = PK11_AlgtagToMechanism(
|
| - SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId));
|
| - param = PK11_ParamFromAlgid(&pbeV2_param->cipherAlgId);
|
| - sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
|
| - if (!param) {
|
| - goto loser;
|
| - }
|
| - /* NOTE: NULL is a permissible return here */
|
| - ivData = PK11_IVFromParam(type, param, &iv_len);
|
| - src.data = ivData;
|
| - src.len = iv_len;
|
| - goto done;
|
| - }
|
| -
|
| - type = PK11_AlgtagToMechanism(pbeAlg);
|
| - param = PK11_ParamFromAlgid(algid);
|
| - if (param == NULL) {
|
| - goto done;
|
| - }
|
| - slot = PK11_GetInternalSlot();
|
| - symKey = PK11_RawPBEKeyGen(slot, type, param, pwitem, faulty3DES, NULL);
|
| - PK11_FreeSlot(slot);
|
| - if (symKey == NULL) {
|
| - goto loser;
|
| - }
|
| - PK11_FreeSymKey(symKey);
|
| - pPBEparams = (CK_PBE_PARAMS_PTR)param->data;
|
| - iv_len = PK11_GetIVLength(type);
|
| -
|
| - src.data = (unsigned char *)pPBEparams->pInitVector;
|
| - src.len = iv_len;
|
| -
|
| -done:
|
| - iv = SECITEM_DupItem(&src);
|
| -
|
| -loser:
|
| - if (param) {
|
| - SECITEM_ZfreeItem(param, PR_TRUE);
|
| - }
|
| - return iv;
|
| -}
|
| -
|
| -/*
|
| - * Subs from nss 3.x that are deprecated
|
| - */
|
| -PBEBitGenContext *
|
| -__PBE_CreateContext(SECOidTag hashAlgorithm, PBEBitGenID bitGenPurpose,
|
| - SECItem *pwitem, SECItem *salt, unsigned int bitsNeeded,
|
| - unsigned int iterations)
|
| -{
|
| - PORT_Assert("__PBE_CreateContext is Deprecated" == NULL);
|
| - return NULL;
|
| -}
|
| -
|
| -SECItem *
|
| -__PBE_GenerateBits(PBEBitGenContext *context)
|
| -{
|
| - PORT_Assert("__PBE_GenerateBits is Deprecated" == NULL);
|
| - return NULL;
|
| -}
|
| -
|
| -void
|
| -__PBE_DestroyContext(PBEBitGenContext *context)
|
| -{
|
| - PORT_Assert("__PBE_DestroyContext is Deprecated" == NULL);
|
| -}
|
| -
|
| -SECStatus
|
| -RSA_FormatBlock(SECItem *result, unsigned modulusLen,
|
| - int blockType, SECItem *data)
|
| -{
|
| - PORT_Assert("RSA_FormatBlock is Deprecated" == NULL);
|
| - return SECFailure;
|
| -}
|
| -
|
| -/****************************************************************************
|
| - *
|
| - * Now Do The PBE Functions Here...
|
| - *
|
| - ****************************************************************************/
|
| -
|
| -static void
|
| -pk11_destroy_ck_pbe_params(CK_PBE_PARAMS *pbe_params)
|
| -{
|
| - if (pbe_params) {
|
| - if (pbe_params->pPassword)
|
| - PORT_ZFree(pbe_params->pPassword, pbe_params->ulPasswordLen);
|
| - if (pbe_params->pSalt)
|
| - PORT_ZFree(pbe_params->pSalt, pbe_params->ulSaltLen);
|
| - PORT_ZFree(pbe_params, sizeof(CK_PBE_PARAMS));
|
| - }
|
| -}
|
| -
|
| -/*
|
| - * public, deprecated. use PK11_CreatePBEAlgorithmID or
|
| - * PK11_CreatePBEV2AlgorithmID instead. If you needthe pkcs #11 parameters,
|
| - * use PK11_ParamFromAlgid from the algorithm id you created using
|
| - * PK11_CreatePBEAlgorithmID or PK11_CreatePBEV2AlgorithmID.
|
| - */
|
| -SECItem *
|
| -PK11_CreatePBEParams(SECItem *salt, SECItem *pwd, unsigned int iterations)
|
| -{
|
| - CK_PBE_PARAMS *pbe_params = NULL;
|
| - SECItem *paramRV = NULL;
|
| -
|
| - paramRV = SECITEM_AllocItem(NULL, NULL, sizeof(CK_PBE_PARAMS));
|
| - if (!paramRV ) {
|
| - goto loser;
|
| - }
|
| - /* init paramRV->data with zeros. SECITEM_AllocItem does not do it */
|
| - PORT_Memset(paramRV->data, 0, sizeof(CK_PBE_PARAMS));
|
| -
|
| - pbe_params = (CK_PBE_PARAMS *)paramRV->data;
|
| - pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwd->len);
|
| - if (!pbe_params->pPassword) {
|
| - goto loser;
|
| - }
|
| - PORT_Memcpy(pbe_params->pPassword, pwd->data, pwd->len);
|
| - pbe_params->ulPasswordLen = pwd->len;
|
| -
|
| - pbe_params->pSalt = (CK_CHAR_PTR)PORT_ZAlloc(salt->len);
|
| - if (!pbe_params->pSalt) {
|
| - goto loser;
|
| - }
|
| - PORT_Memcpy(pbe_params->pSalt, salt->data, salt->len);
|
| - pbe_params->ulSaltLen = salt->len;
|
| -
|
| - pbe_params->ulIteration = (CK_ULONG)iterations;
|
| - return paramRV;
|
| -
|
| -loser:
|
| - if (pbe_params)
|
| - pk11_destroy_ck_pbe_params(pbe_params);
|
| - if (paramRV)
|
| - PORT_ZFree(paramRV, sizeof(SECItem));
|
| - return NULL;
|
| -}
|
| -
|
| -/*
|
| - * public, deprecated.
|
| - */
|
| -void
|
| -PK11_DestroyPBEParams(SECItem *pItem)
|
| -{
|
| - if (pItem) {
|
| - CK_PBE_PARAMS * params = (CK_PBE_PARAMS *)(pItem->data);
|
| - if (params)
|
| - pk11_destroy_ck_pbe_params(params);
|
| - PORT_ZFree(pItem, sizeof(SECItem));
|
| - }
|
| -}
|
| -
|
| -/*
|
| - * public, Partially supports PKCS5 V2 (some parameters are not controllable
|
| - * through this interface). Use PK11_CreatePBEV2AlgorithmID() if you need
|
| - * finer control these.
|
| - */
|
| -SECAlgorithmID *
|
| -PK11_CreatePBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt)
|
| -{
|
| - SECAlgorithmID *algid = NULL;
|
| - algid = sec_pkcs5CreateAlgorithmID(algorithm,
|
| - SEC_OID_UNKNOWN, SEC_OID_UNKNOWN, NULL, 0, salt, iteration);
|
| - return algid;
|
| -}
|
| -
|
| -/*
|
| - * public, fully support pkcs5v2.
|
| - */
|
| -SECAlgorithmID *
|
| -PK11_CreatePBEV2AlgorithmID(SECOidTag pbeAlgTag, SECOidTag cipherAlgTag,
|
| - SECOidTag prfAlgTag, int keyLength, int iteration,
|
| - SECItem *salt)
|
| -{
|
| - SECAlgorithmID *algid = NULL;
|
| - algid = sec_pkcs5CreateAlgorithmID(pbeAlgTag, cipherAlgTag, prfAlgTag,
|
| - NULL, keyLength, salt, iteration);
|
| - return algid;
|
| -}
|
| -
|
| -/*
|
| - * private.
|
| - */
|
| -PK11SymKey *
|
| -pk11_RawPBEKeyGenWithKeyType(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
|
| - SECItem *params, CK_KEY_TYPE keyType, int keyLen,
|
| - SECItem *pwitem, void *wincx)
|
| -{
|
| - CK_ULONG pwLen;
|
| - /* do some sanity checks */
|
| - if ((params == NULL) || (params->data == NULL)) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return NULL;
|
| - }
|
| -
|
| - if (type == CKM_INVALID_MECHANISM) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
| - return NULL;
|
| - }
|
| -
|
| - /* set the password pointer in the parameters... */
|
| - if (type == CKM_PKCS5_PBKD2) {
|
| - CK_PKCS5_PBKD2_PARAMS *pbev2_params;
|
| - if (params->len < sizeof(CK_PKCS5_PBKD2_PARAMS)) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return NULL;
|
| - }
|
| - pbev2_params = (CK_PKCS5_PBKD2_PARAMS *)params->data;
|
| - pbev2_params->pPassword = pwitem->data;
|
| - pwLen = pwitem->len;
|
| - pbev2_params->ulPasswordLen = &pwLen;
|
| - } else {
|
| - CK_PBE_PARAMS *pbe_params;
|
| - if (params->len < sizeof(CK_PBE_PARAMS)) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
| - return NULL;
|
| - }
|
| - pbe_params = (CK_PBE_PARAMS *)params->data;
|
| - pbe_params->pPassword = pwitem->data;
|
| - pbe_params->ulPasswordLen = pwitem->len;
|
| - }
|
| -
|
| - /* generate the key (and sometimes the IV as a side effect...) */
|
| - return pk11_TokenKeyGenWithFlagsAndKeyType(slot, type, params, keyType,
|
| - keyLen, NULL, CKF_SIGN|CKF_ENCRYPT|CKF_DECRYPT|CKF_UNWRAP|CKF_WRAP,
|
| - 0, wincx);
|
| -}
|
| -
|
| -/*
|
| - * public, deprecated. use PK11_PBEKeyGen instead.
|
| - */
|
| -PK11SymKey *
|
| -PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech,
|
| - SECItem *pwitem, PRBool faulty3DES, void *wincx)
|
| -{
|
| - if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) {
|
| - type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC;
|
| - }
|
| - return pk11_RawPBEKeyGenWithKeyType(slot, type, mech, -1, 0, pwitem, wincx);
|
| -}
|
| -
|
| -/*
|
| - * pubic, supports pkcs5 v2.
|
| - *
|
| - * Create symkey from a PBE key. The algid can be created with
|
| - * PK11_CreatePBEV2AlgorithmID and PK11_CreatePBEAlgorithmID, or by
|
| - * extraction of der data.
|
| - */
|
| -PK11SymKey *
|
| -PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem,
|
| - PRBool faulty3DES, void *wincx)
|
| -{
|
| - CK_MECHANISM_TYPE type;
|
| - SECItem *param = NULL;
|
| - PK11SymKey *symKey = NULL;
|
| - SECOidTag pbeAlg;
|
| - CK_KEY_TYPE keyType = -1;
|
| - int keyLen = 0;
|
| -
|
| - pbeAlg = SECOID_GetAlgorithmTag(algid);
|
| - /* if we're using PKCS5v2, extract the additional information we need
|
| - * (key length, key type, and pbeAlg). */
|
| - if (sec_pkcs5_is_algorithm_v2_pkcs5_algorithm(pbeAlg)) {
|
| - CK_MECHANISM_TYPE cipherMech;
|
| - sec_pkcs5V2Parameter *pbeV2_param;
|
| -
|
| - pbeV2_param = sec_pkcs5_v2_get_v2_param(NULL, algid);
|
| - if (pbeV2_param == NULL) {
|
| - return NULL;
|
| - }
|
| - cipherMech = PK11_AlgtagToMechanism(
|
| - SECOID_GetAlgorithmTag(&pbeV2_param->cipherAlgId));
|
| - pbeAlg = SECOID_GetAlgorithmTag(&pbeV2_param->pbeAlgId);
|
| - param = PK11_ParamFromAlgid(&pbeV2_param->pbeAlgId);
|
| - sec_pkcs5_v2_destroy_v2_param(pbeV2_param);
|
| - keyLen = SEC_PKCS5GetKeyLength(algid);
|
| - if (keyLen == -1) {
|
| - keyLen = 0;
|
| - }
|
| - keyType = PK11_GetKeyType(cipherMech, keyLen);
|
| - } else {
|
| - param = PK11_ParamFromAlgid(algid);
|
| - }
|
| -
|
| - if(param == NULL) {
|
| - goto loser;
|
| - }
|
| -
|
| - type = PK11_AlgtagToMechanism(pbeAlg);
|
| - if (type == CKM_INVALID_MECHANISM) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
| - goto loser;
|
| - }
|
| - if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) {
|
| - type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC;
|
| - }
|
| - symKey = pk11_RawPBEKeyGenWithKeyType(slot, type, param, keyType, keyLen,
|
| - pwitem, wincx);
|
| -
|
| -loser:
|
| - if (param) {
|
| - SECITEM_ZfreeItem(param, PR_TRUE);
|
| - }
|
| - return symKey;
|
| -}
|
| -
|
| -/*
|
| - * public, supports pkcs5v2
|
| - */
|
| -SECItem *
|
| -PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem)
|
| -{
|
| - return SEC_PKCS5GetIV(algid, pwitem, PR_FALSE);
|
| -}
|
| -
|
| -CK_MECHANISM_TYPE
|
| -pk11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param,
|
| - SECItem *pbe_pwd, PRBool faulty3DES)
|
| -{
|
| - int keyLen = 0;
|
| - SECOidTag algTag = SEC_PKCS5GetCryptoAlgorithm(algid);
|
| - CK_MECHANISM_TYPE mech = PK11_AlgtagToMechanism(algTag);
|
| - CK_MECHANISM_TYPE returnedMechanism = CKM_INVALID_MECHANISM;
|
| - SECItem *iv = NULL;
|
| -
|
| - if (mech == CKM_INVALID_MECHANISM) {
|
| - PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
| - goto loser;
|
| - }
|
| - if (PK11_GetIVLength(mech)) {
|
| - iv = SEC_PKCS5GetIV(algid, pbe_pwd, faulty3DES);
|
| - if (iv == NULL) {
|
| - goto loser;
|
| - }
|
| - }
|
| -
|
| - keyLen = SEC_PKCS5GetKeyLength(algid);
|
| -
|
| - *param = pk11_ParamFromIVWithLen(mech, iv, keyLen);
|
| - if (*param == NULL) {
|
| - goto loser;
|
| - }
|
| - returnedMechanism = mech;
|
| -
|
| -loser:
|
| - if (iv) {
|
| - SECITEM_FreeItem(iv,PR_TRUE);
|
| - }
|
| - return returnedMechanism;
|
| -}
|
| -
|
| -/*
|
| - * Public, supports pkcs5 v2
|
| - *
|
| - * Get the crypto mechanism directly from the pbe algorithmid.
|
| - *
|
| - * It's important to go directly from the algorithm id so that we can
|
| - * handle both the PKCS #5 v1, PKCS #12, and PKCS #5 v2 cases.
|
| - *
|
| - * This function returns both the mechanism and the parameter for the mechanism.
|
| - * The caller is responsible for freeing the parameter.
|
| - */
|
| -CK_MECHANISM_TYPE
|
| -PK11_GetPBECryptoMechanism(SECAlgorithmID *algid, SECItem **param,
|
| - SECItem *pbe_pwd)
|
| -{
|
| - return pk11_GetPBECryptoMechanism(algid, param, pbe_pwd, PR_FALSE);
|
| -}
|
|
|