From 73f15b09635541380d7cbf3f4e3a28e93f16501e Mon Sep 17 00:00:00 2001 From: "relyea%netscape.com" Date: Mon, 19 Jul 2004 22:12:38 +0000 Subject: [PATCH] refactor pk11util, splitting large single files down to a managable size. bug 246130. The new factor is: pk11akey.c - asymetric keys constructed from pk11cert.c and pk11skey.c pk11auth.c - authentication/password management factored from pk11slot.c pk11cert.c - cert code with private key, crls and trust factored out. pk11ctx.c -- pkcs11 context code, factored out of pk11skey.c new pk11func.h -- for backward compatibility. pk11mech.c - mechanism mapping code, factored mostly from pk11slot.c pk11nobj.c - netscape objects (crls and trust), factored mostly from pk11cert.c pk11obj.c - generic object support, factored from pk11skey.c pk11slot.c and pk11cert.c pk11priv.h -- private functions factored from pk11func.h pk11pub.h -- public functions factored from pk11func.h pk11skey.c - now only symetric key ops; private, public key ops, generic ops and crypto contexs have been factored out. pk11slot.c - still slot operations. Authentication, generic object ops, mechanism mapping has been factored out. This patch should only have refactoring, no new functions or other changes. --- security/nss/lib/pk11wrap/manifest.mn | 27 +- security/nss/lib/pk11wrap/pk11akey.c | 2267 ++++++++++++++ security/nss/lib/pk11wrap/pk11auth.c | 702 +++++ security/nss/lib/pk11wrap/pk11cert.c | 1496 +-------- security/nss/lib/pk11wrap/pk11cxt.c | 1051 +++++++ security/nss/lib/pk11wrap/pk11func.h | 672 +--- security/nss/lib/pk11wrap/pk11kea.c | 7 +- security/nss/lib/pk11wrap/pk11list.c | 3 +- security/nss/lib/pk11wrap/pk11load.c | 1 + security/nss/lib/pk11wrap/pk11mech.c | 1787 +++++++++++ security/nss/lib/pk11wrap/pk11nobj.c | 796 +++++ security/nss/lib/pk11wrap/pk11obj.c | 1579 ++++++++++ security/nss/lib/pk11wrap/pk11pars.c | 1 + security/nss/lib/pk11wrap/pk11pbe.c | 155 + security/nss/lib/pk11wrap/pk11pqg.c | 1 + security/nss/lib/pk11wrap/pk11priv.h | 217 ++ security/nss/lib/pk11wrap/pk11pub.h | 583 ++++ security/nss/lib/pk11wrap/pk11skey.c | 4120 +------------------------ security/nss/lib/pk11wrap/pk11slot.c | 2618 +--------------- security/nss/lib/pk11wrap/pk11util.c | 1 + security/nss/lib/pk11wrap/secmod.h | 9 - security/nss/lib/pk11wrap/secmodi.h | 43 +- security/nss/lib/pk11wrap/secmodt.h | 6 + security/nss/lib/pk11wrap/secmodti.h | 16 + 24 files changed, 9322 insertions(+), 8836 deletions(-) create mode 100644 security/nss/lib/pk11wrap/pk11akey.c create mode 100644 security/nss/lib/pk11wrap/pk11auth.c create mode 100644 security/nss/lib/pk11wrap/pk11cxt.c create mode 100644 security/nss/lib/pk11wrap/pk11mech.c create mode 100644 security/nss/lib/pk11wrap/pk11nobj.c create mode 100644 security/nss/lib/pk11wrap/pk11obj.c create mode 100644 security/nss/lib/pk11wrap/pk11priv.h create mode 100644 security/nss/lib/pk11wrap/pk11pub.h diff --git a/security/nss/lib/pk11wrap/manifest.mn b/security/nss/lib/pk11wrap/manifest.mn index a611d973563..fca5fb7b2d8 100644 --- a/security/nss/lib/pk11wrap/manifest.mn +++ b/security/nss/lib/pk11wrap/manifest.mn @@ -41,13 +41,14 @@ EXPORTS = \ secmodt.h \ secpkcs5.h \ pk11func.h \ + pk11pub.h \ + pk11priv.h \ pk11sdr.h \ pk11pqg.h \ $(NULL) PRIVATE_EXPORTS = \ secmodi.h \ - secmodti.h \ pk11init.h \ dev3hack.h \ $(NULL) @@ -56,19 +57,25 @@ MODULE = nss CSRCS = \ dev3hack.c \ + pk11akey.c \ + pk11auth.c \ pk11cert.c \ + pk11cxt.c \ pk11err.c \ - pk11load.c \ - pk11pars.c \ - pk11slot.c \ - pk11list.c \ - pk11skey.c \ pk11kea.c \ - pk11util.c \ - pk11sdr.c \ - pk11pqg.c \ - pk11pk12.c \ + pk11list.c \ + pk11load.c \ + pk11mech.c \ + pk11nobj.c \ + pk11obj.c \ + pk11pars.c \ pk11pbe.c \ + pk11pk12.c \ + pk11pqg.c \ + pk11sdr.c \ + pk11skey.c \ + pk11slot.c \ + pk11util.c \ $(NULL) REQUIRES = dbm diff --git a/security/nss/lib/pk11wrap/pk11akey.c b/security/nss/lib/pk11wrap/pk11akey.c new file mode 100644 index 00000000000..4e1745adc8a --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11akey.c @@ -0,0 +1,2267 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Stephen Henson + * Dr Vipul Gupta , and + * Douglas Stebila , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file contains functions to manage asymetric keys, (public and + * private keys). + */ +#include "seccomon.h" +#include "secmod.h" +#include "secmodi.h" +#include "secmodti.h" +#include "pkcs11.h" +#include "pkcs11t.h" +#include "pk11func.h" +#include "cert.h" +#include "key.h" +#include "secitem.h" +#include "secasn1.h" +#include "secoid.h" +#include "secerr.h" +#include "sslerr.h" +#include "sechash.h" + +#include "secpkcs5.h" +#include "ec.h" + +#define PAIRWISE_SECITEM_TYPE siBuffer +#define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */ +#define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ + +/* + * import a public key into the desired slot + */ +CK_OBJECT_HANDLE +PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey, + PRBool isToken) +{ + CK_BBOOL cktrue = CK_TRUE; + CK_BBOOL ckfalse = CK_FALSE; + CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_OBJECT_HANDLE objectID; + CK_ATTRIBUTE theTemplate[10]; + CK_ATTRIBUTE *signedattr = NULL; + CK_ATTRIBUTE *attrs = theTemplate; + int signedcount = 0; + int templateCount = 0; + SECStatus rv; + + /* if we already have an object in the desired slot, use it */ + if (!isToken && pubKey->pkcs11Slot == slot) { + return pubKey->pkcs11ID; + } + + /* free the existing key */ + if (pubKey->pkcs11Slot != NULL) { + PK11SlotInfo *oSlot = pubKey->pkcs11Slot; + PK11_EnterSlotMonitor(oSlot); + (void) PK11_GETTAB(oSlot)->C_DestroyObject(oSlot->session, + pubKey->pkcs11ID); + PK11_ExitSlotMonitor(oSlot); + PK11_FreeSlot(oSlot); + pubKey->pkcs11Slot = NULL; + } + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++; + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, isToken ? &cktrue : &ckfalse, + sizeof(CK_BBOOL) ); attrs++; + + /* now import the key */ + { + switch (pubKey->keyType) { + case rsaKey: + keyType = CKK_RSA; + PK11_SETATTRS(attrs, CKA_WRAP, &cktrue, sizeof(CK_BBOOL) ); attrs++; + PK11_SETATTRS(attrs, CKA_ENCRYPT, &cktrue, + sizeof(CK_BBOOL) ); attrs++; + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); attrs++; + signedattr = attrs; + PK11_SETATTRS(attrs, CKA_MODULUS, pubKey->u.rsa.modulus.data, + pubKey->u.rsa.modulus.len); attrs++; + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, + pubKey->u.rsa.publicExponent.data, + pubKey->u.rsa.publicExponent.len); attrs++; + break; + case dsaKey: + keyType = CKK_DSA; + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; + signedattr = attrs; + PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dsa.params.prime.data, + pubKey->u.dsa.params.prime.len); attrs++; + PK11_SETATTRS(attrs,CKA_SUBPRIME,pubKey->u.dsa.params.subPrime.data, + pubKey->u.dsa.params.subPrime.len); attrs++; + PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dsa.params.base.data, + pubKey->u.dsa.params.base.len); attrs++; + PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dsa.publicValue.data, + pubKey->u.dsa.publicValue.len); attrs++; + break; + case fortezzaKey: + keyType = CKK_DSA; + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; + signedattr = attrs; + PK11_SETATTRS(attrs, CKA_PRIME,pubKey->u.fortezza.params.prime.data, + pubKey->u.fortezza.params.prime.len); attrs++; + PK11_SETATTRS(attrs,CKA_SUBPRIME, + pubKey->u.fortezza.params.subPrime.data, + pubKey->u.fortezza.params.subPrime.len);attrs++; + PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.fortezza.params.base.data, + pubKey->u.fortezza.params.base.len); attrs++; + PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.fortezza.DSSKey.data, + pubKey->u.fortezza.DSSKey.len); attrs++; + break; + case dhKey: + keyType = CKK_DH; + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; + signedattr = attrs; + PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dh.prime.data, + pubKey->u.dh.prime.len); attrs++; + PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dh.base.data, + pubKey->u.dh.base.len); attrs++; + PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dh.publicValue.data, + pubKey->u.dh.publicValue.len); attrs++; + break; +#ifdef NSS_ENABLE_ECC + case ecKey: + keyType = CKK_EC; + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; + signedattr = attrs; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, + pubKey->u.ec.DEREncodedParams.data, + pubKey->u.ec.DEREncodedParams.len); attrs++; + PK11_SETATTRS(attrs, CKA_EC_POINT, pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len); attrs++; + break; +#endif /* NSS_ENABLE_ECC */ + default: + PORT_SetError( SEC_ERROR_BAD_KEY ); + return CK_INVALID_HANDLE; + } + + templateCount = attrs - theTemplate; + signedcount = attrs - signedattr; + PORT_Assert(templateCount <= (sizeof(theTemplate)/sizeof(CK_ATTRIBUTE))); + for (attrs=signedattr; signedcount; attrs++, signedcount--) { + pk11_SignedToUnsigned(attrs); + } + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate, + templateCount, isToken, &objectID); + if ( rv != SECSuccess) { + return CK_INVALID_HANDLE; + } + } + + pubKey->pkcs11ID = objectID; + pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); + + return objectID; +} + +/* + * take an attribute and copy it into a secitem + */ +static CK_RV +pk11_Attr2SecItem(PRArenaPool *arena, CK_ATTRIBUTE *attr, SECItem *item) +{ + item->data = NULL; + + (void)SECITEM_AllocItem(arena, item, attr->ulValueLen); + if (item->data == NULL) { + return CKR_HOST_MEMORY; + } + PORT_Memcpy(item->data, attr->pValue, item->len); + return CKR_OK; +} + +/* + * extract a public key from a slot and id + */ +SECKEYPublicKey * +PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) +{ + CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; + PRArenaPool *arena; + PRArenaPool *tmp_arena; + SECKEYPublicKey *pubKey; + int templateCount = 0; + CK_KEY_TYPE pk11KeyType; + CK_RV crv; + CK_ATTRIBUTE template[8]; + CK_ATTRIBUTE *attrs= template; + CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE *ecparams; +#endif /* NSS_ENABLE_ECC */ + + /* if we didn't know the key type, get it */ + if (keyType== nullKey) { + + pk11KeyType = PK11_ReadULongAttribute(slot,id,CKA_KEY_TYPE); + if (pk11KeyType == CK_UNAVAILABLE_INFORMATION) { + return NULL; + } + switch (pk11KeyType) { + case CKK_RSA: + keyType = rsaKey; + break; + case CKK_DSA: + keyType = dsaKey; + break; + case CKK_DH: + keyType = dhKey; + break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: + keyType = ecKey; + break; +#endif /* NSS_ENABLE_ECC */ + default: + PORT_SetError( SEC_ERROR_BAD_KEY ); + return NULL; + } + } + + + /* now we need to create space for the public key */ + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) return NULL; + tmp_arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); + if (tmp_arena == NULL) { + PORT_FreeArena (arena, PR_FALSE); + return NULL; + } + + + pubKey = (SECKEYPublicKey *) + PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); + if (pubKey == NULL) { + PORT_FreeArena (arena, PR_FALSE); + PORT_FreeArena (tmp_arena, PR_FALSE); + return NULL; + } + + pubKey->arena = arena; + pubKey->keyType = keyType; + pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); + pubKey->pkcs11ID = id; + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, + sizeof(keyClass)); attrs++; + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &pk11KeyType, + sizeof(pk11KeyType) ); attrs++; + switch (pubKey->keyType) { + case rsaKey: + modulus = attrs; + PK11_SETATTRS(attrs, CKA_MODULUS, NULL, 0); attrs++; + exponent = attrs; + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, NULL, 0); attrs++; + + templateCount = attrs - template; + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); + if (crv != CKR_OK) break; + + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_RSA)) { + crv = CKR_OBJECT_HANDLE_INVALID; + break; + } + crv = pk11_Attr2SecItem(arena,modulus,&pubKey->u.rsa.modulus); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,exponent,&pubKey->u.rsa.publicExponent); + if (crv != CKR_OK) break; + break; + case dsaKey: + prime = attrs; + PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; + subprime = attrs; + PK11_SETATTRS(attrs, CKA_SUBPRIME, NULL, 0); attrs++; + base = attrs; + PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; + value = attrs; + PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; + templateCount = attrs - template; + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); + if (crv != CKR_OK) break; + + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DSA)) { + crv = CKR_OBJECT_HANDLE_INVALID; + break; + } + crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dsa.params.prime); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,subprime,&pubKey->u.dsa.params.subPrime); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dsa.params.base); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dsa.publicValue); + if (crv != CKR_OK) break; + break; + case dhKey: + prime = attrs; + PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; + base = attrs; + PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; + value =attrs; + PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; + templateCount = attrs - template; + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); + if (crv != CKR_OK) break; + + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DH)) { + crv = CKR_OBJECT_HANDLE_INVALID; + break; + } + crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dh.prime); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dh.base); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue); + if (crv != CKR_OK) break; + break; +#ifdef NSS_ENABLE_ECC + case ecKey: + pubKey->u.ec.size = 0; + ecparams = attrs; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++; + value =attrs; + PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++; + templateCount = attrs - template; + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); + if (crv != CKR_OK) break; + + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) { + crv = CKR_OBJECT_HANDLE_INVALID; + break; + } + + crv = pk11_Attr2SecItem(arena,ecparams, + &pubKey->u.ec.DEREncodedParams); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,value,&pubKey->u.ec.publicValue); + if (crv != CKR_OK) break; + break; +#endif /* NSS_ENABLE_ECC */ + case fortezzaKey: + case nullKey: + default: + crv = CKR_OBJECT_HANDLE_INVALID; + break; + } + + PORT_FreeArena(tmp_arena,PR_FALSE); + + if (crv != CKR_OK) { + PORT_FreeArena(arena,PR_FALSE); + PK11_FreeSlot(slot); + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + + return pubKey; +} + +/* + * Build a Private Key structure from raw PKCS #11 information. + */ +SECKEYPrivateKey * +PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, + PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx) +{ + PRArenaPool *arena; + SECKEYPrivateKey *privKey; + PRBool isPrivate; + SECStatus rv; + + /* don't know? look it up */ + if (keyType == nullKey) { + CK_KEY_TYPE pk11Type = CKK_RSA; + + pk11Type = PK11_ReadULongAttribute(slot,privID,CKA_KEY_TYPE); + isTemp = (PRBool)!PK11_HasAttributeSet(slot,privID,CKA_TOKEN); + switch (pk11Type) { + case CKK_RSA: keyType = rsaKey; break; + case CKK_DSA: keyType = dsaKey; break; + case CKK_DH: keyType = dhKey; break; + case CKK_KEA: keyType = fortezzaKey; break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: keyType = ecKey; break; +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + } + + /* if the key is private, make sure we are authenticated to the + * token before we try to use it */ + isPrivate = (PRBool)PK11_HasAttributeSet(slot,privID,CKA_PRIVATE); + if (isPrivate) { + rv = PK11_Authenticate(slot, PR_TRUE, wincx); + if (rv != SECSuccess) { + return NULL; + } + } + + /* now we need to create space for the private key */ + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) return NULL; + + privKey = (SECKEYPrivateKey *) + PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey)); + if (privKey == NULL) { + PORT_FreeArena(arena, PR_FALSE); + return NULL; + } + + privKey->arena = arena; + privKey->keyType = keyType; + privKey->pkcs11Slot = PK11_ReferenceSlot(slot); + privKey->pkcs11ID = privID; + privKey->pkcs11IsTemp = isTemp; + privKey->wincx = wincx; + + return privKey; +} + + +PK11SlotInfo * +PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key) +{ + PK11SlotInfo *slot = key->pkcs11Slot; + slot = PK11_ReferenceSlot(slot); + return slot; +} + +/* + * Get the modulus length for raw parsing + */ +int +PK11_GetPrivateModulusLen(SECKEYPrivateKey *key) +{ + CK_ATTRIBUTE theTemplate = { CKA_MODULUS, NULL, 0 }; + PK11SlotInfo *slot = key->pkcs11Slot; + CK_RV crv; + int length; + + switch (key->keyType) { + case rsaKey: + crv = PK11_GetAttributes(NULL, slot, key->pkcs11ID, &theTemplate, 1); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return -1; + } + length = theTemplate.ulValueLen; + if ( *(unsigned char *)theTemplate.pValue == 0) { + length--; + } + if (theTemplate.pValue != NULL) + PORT_Free(theTemplate.pValue); + return (int) length; + + case fortezzaKey: + case dsaKey: + case dhKey: + default: + break; + } + if (theTemplate.pValue != NULL) + PORT_Free(theTemplate.pValue); + PORT_SetError( SEC_ERROR_INVALID_KEY ); + return -1; +} + +/* + * PKCS #11 pairwise consistency check utilized to validate key pair. + */ +static SECStatus +pk11_PairwiseConsistencyCheck(SECKEYPublicKey *pubKey, + SECKEYPrivateKey *privKey, CK_MECHANISM *mech, void* wincx ) +{ + /* Variables used for Encrypt/Decrypt functions. */ + unsigned char *known_message = (unsigned char *)"Known Crypto Message"; + CK_BBOOL isEncryptable = CK_FALSE; + CK_BBOOL canSignVerify = CK_FALSE; + CK_BBOOL isDerivable = CK_FALSE; + unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH]; + CK_ULONG bytes_decrypted; + PK11SlotInfo *slot; + CK_OBJECT_HANDLE id; + unsigned char *ciphertext; + unsigned char *text_compared; + CK_ULONG max_bytes_encrypted; + CK_ULONG bytes_encrypted; + CK_ULONG bytes_compared; + CK_RV crv; + + /* Variables used for Signature/Verification functions. */ + unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!"; + SECItem signature; + SECItem digest; /* always uses SHA-1 digest */ + int signature_length; + SECStatus rv; + + /**************************************************/ + /* Pairwise Consistency Check of Encrypt/Decrypt. */ + /**************************************************/ + + isEncryptable = PK11_HasAttributeSet( privKey->pkcs11Slot, + privKey->pkcs11ID, CKA_DECRYPT ); + + /* If the encryption attribute is set; attempt to encrypt */ + /* with the public key and decrypt with the private key. */ + if( isEncryptable ) { + /* Find a module to encrypt against */ + slot = PK11_GetBestSlot(pk11_mapWrapKeyType(privKey->keyType),wincx); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return SECFailure; + } + + id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE); + if (id == CK_INVALID_HANDLE) { + PK11_FreeSlot(slot); + return SECFailure; + } + + /* Compute max bytes encrypted from modulus length of private key. */ + max_bytes_encrypted = PK11_GetPrivateModulusLen( privKey ); + + + /* Prepare for encryption using the public key. */ + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB( slot )->C_EncryptInit( slot->session, + mech, id ); + if( crv != CKR_OK ) { + PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError( crv ) ); + PK11_FreeSlot(slot); + return SECFailure; + } + + /* Allocate space for ciphertext. */ + ciphertext = (unsigned char *) PORT_Alloc( max_bytes_encrypted ); + if( ciphertext == NULL ) { + PK11_ExitSlotMonitor(slot); + PORT_SetError( SEC_ERROR_NO_MEMORY ); + PK11_FreeSlot(slot); + return SECFailure; + } + + /* Initialize bytes encrypted to max bytes encrypted. */ + bytes_encrypted = max_bytes_encrypted; + + /* Encrypt using the public key. */ + crv = PK11_GETTAB( slot )->C_Encrypt( slot->session, + known_message, + PAIRWISE_MESSAGE_LENGTH, + ciphertext, + &bytes_encrypted ); + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + if( crv != CKR_OK ) { + PORT_SetError( PK11_MapError( crv ) ); + PORT_Free( ciphertext ); + return SECFailure; + } + + /* Always use the smaller of these two values . . . */ + bytes_compared = ( bytes_encrypted > PAIRWISE_MESSAGE_LENGTH ) + ? PAIRWISE_MESSAGE_LENGTH + : bytes_encrypted; + + /* If there was a failure, the plaintext */ + /* goes at the end, therefore . . . */ + text_compared = ( bytes_encrypted > PAIRWISE_MESSAGE_LENGTH ) + ? (ciphertext + bytes_encrypted - + PAIRWISE_MESSAGE_LENGTH ) + : ciphertext; + + /* Check to ensure that ciphertext does */ + /* NOT EQUAL known input message text */ + /* per FIPS PUB 140-1 directive. */ + if( ( bytes_encrypted != max_bytes_encrypted ) || + ( PORT_Memcmp( text_compared, known_message, + bytes_compared ) == 0 ) ) { + /* Set error to Invalid PRIVATE Key. */ + PORT_SetError( SEC_ERROR_INVALID_KEY ); + PORT_Free( ciphertext ); + return SECFailure; + } + + slot = privKey->pkcs11Slot; + /* Prepare for decryption using the private key. */ + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB( slot )->C_DecryptInit( slot->session, + mech, + privKey->pkcs11ID ); + if( crv != CKR_OK ) { + PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError(crv) ); + PORT_Free( ciphertext ); + return SECFailure; + } + + /* Initialize bytes decrypted to be the */ + /* expected PAIRWISE_MESSAGE_LENGTH. */ + bytes_decrypted = PAIRWISE_MESSAGE_LENGTH; + + /* Decrypt using the private key. */ + /* NOTE: No need to reset the */ + /* value of bytes_encrypted. */ + crv = PK11_GETTAB( slot )->C_Decrypt( slot->session, + ciphertext, + bytes_encrypted, + plaintext, + &bytes_decrypted ); + PK11_ExitSlotMonitor(slot); + + /* Finished with ciphertext; free it. */ + PORT_Free( ciphertext ); + + if( crv != CKR_OK ) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + + /* Check to ensure that the output plaintext */ + /* does EQUAL known input message text. */ + if( ( bytes_decrypted != PAIRWISE_MESSAGE_LENGTH ) || + ( PORT_Memcmp( plaintext, known_message, + PAIRWISE_MESSAGE_LENGTH ) != 0 ) ) { + /* Set error to Bad PUBLIC Key. */ + PORT_SetError( SEC_ERROR_BAD_KEY ); + return SECFailure; + } + } + + /**********************************************/ + /* Pairwise Consistency Check of Sign/Verify. */ + /**********************************************/ + + canSignVerify = PK11_HasAttributeSet ( privKey->pkcs11Slot, + privKey->pkcs11ID, CKA_SIGN); + + if (canSignVerify) + { + /* Initialize signature and digest data. */ + signature.data = NULL; + digest.data = NULL; + + /* Determine length of signature. */ + signature_length = PK11_SignatureLen( privKey ); + if( signature_length == 0 ) + goto failure; + + /* Allocate space for signature data. */ + signature.data = (unsigned char *) PORT_Alloc( signature_length ); + if( signature.data == NULL ) { + PORT_SetError( SEC_ERROR_NO_MEMORY ); + goto failure; + } + + /* Allocate space for known digest data. */ + digest.data = (unsigned char *) PORT_Alloc( PAIRWISE_DIGEST_LENGTH ); + if( digest.data == NULL ) { + PORT_SetError( SEC_ERROR_NO_MEMORY ); + goto failure; + } + + /* "Fill" signature type and length. */ + signature.type = PAIRWISE_SECITEM_TYPE; + signature.len = signature_length; + + /* "Fill" digest with known SHA-1 digest parameters. */ + digest.type = PAIRWISE_SECITEM_TYPE; + PORT_Memcpy( digest.data, known_digest, PAIRWISE_DIGEST_LENGTH ); + digest.len = PAIRWISE_DIGEST_LENGTH; + + /* Sign the known hash using the private key. */ + rv = PK11_Sign( privKey, &signature, &digest ); + if( rv != SECSuccess ) + goto failure; + + /* Verify the known hash using the public key. */ + rv = PK11_Verify( pubKey, &signature, &digest, wincx ); + if( rv != SECSuccess ) + goto failure; + + /* Free signature and digest data. */ + PORT_Free( signature.data ); + PORT_Free( digest.data ); + } + + + + /**********************************************/ + /* Pairwise Consistency Check for Derivation */ + /**********************************************/ + + isDerivable = PK11_HasAttributeSet ( privKey->pkcs11Slot, + privKey->pkcs11ID, CKA_DERIVE); + + if (isDerivable) + { + /* + * We are not doing consistency check for Diffie-Hellman Key - + * otherwise it would be here + * This is also true for Elliptic Curve Diffie-Hellman keys + * NOTE: EC keys are currently subjected to pairwise + * consistency check for signing/verification. + */ + + } + + return SECSuccess; + +failure: + if( signature.data != NULL ) + PORT_Free( signature.data ); + if( digest.data != NULL ) + PORT_Free( digest.data ); + + return SECFailure; +} + + + +/* + * take a private key in one pkcs11 module and load it into another: + * NOTE: the source private key is a rare animal... it can't be sensitive. + * This is used to do a key gen using one pkcs11 module and storing the + * result into another. + */ +SECKEYPrivateKey * +pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) +{ + CK_ATTRIBUTE privTemplate[] = { + /* class must be first */ + { CKA_CLASS, NULL, 0 }, + { CKA_KEY_TYPE, NULL, 0 }, + /* these three must be next */ + { CKA_TOKEN, NULL, 0 }, + { CKA_PRIVATE, NULL, 0 }, + { CKA_SENSITIVE, NULL, 0 }, + { CKA_ID, NULL, 0 }, +#ifdef notdef + { CKA_LABEL, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, +#endif + /* RSA */ + { CKA_MODULUS, NULL, 0 }, + { CKA_PRIVATE_EXPONENT, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 }, + { CKA_PRIME_1, NULL, 0 }, + { CKA_PRIME_2, NULL, 0 }, + { CKA_EXPONENT_1, NULL, 0 }, + { CKA_EXPONENT_2, NULL, 0 }, + { CKA_COEFFICIENT, NULL, 0 }, + }; + CK_ATTRIBUTE *attrs = NULL, *ap; + int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]); + PRArenaPool *arena; + CK_OBJECT_HANDLE objectID; + int i, count = 0; + int extra_count = 0; + CK_RV crv; + SECStatus rv; + + for (i=0; i < templateSize; i++) { + if (privTemplate[i].type == CKA_MODULUS) { + attrs= &privTemplate[i]; + count = i; + break; + } + } + PORT_Assert(attrs != NULL); + if (attrs == NULL) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + + ap = attrs; + + switch (privKey->keyType) { + case rsaKey: + count = templateSize; + extra_count = templateSize - (attrs - privTemplate); + break; + case dsaKey: + ap->type = CKA_PRIME; ap++; count++; extra_count++; + ap->type = CKA_SUBPRIME; ap++; count++; extra_count++; + ap->type = CKA_BASE; ap++; count++; extra_count++; + ap->type = CKA_VALUE; ap++; count++; extra_count++; + break; + case dhKey: + ap->type = CKA_PRIME; ap++; count++; extra_count++; + ap->type = CKA_BASE; ap++; count++; extra_count++; + ap->type = CKA_VALUE; ap++; count++; extra_count++; + break; +#ifdef NSS_ENABLE_ECC + case ecKey: + ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++; + ap->type = CKA_VALUE; ap++; count++; extra_count++; + break; +#endif /* NSS_ENABLE_ECC */ + default: + count = 0; + extra_count = 0; + break; + } + + if (count == 0) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) return NULL; + /* + * read out the old attributes. + */ + crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, + privTemplate,count); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + PORT_FreeArena(arena, PR_TRUE); + return NULL; + } + + /* Reset sensitive, token, and private */ + *(CK_BBOOL *)(privTemplate[2].pValue) = token ? CK_TRUE : CK_FALSE; + *(CK_BBOOL *)(privTemplate[3].pValue) = token ? CK_TRUE : CK_FALSE; + *(CK_BBOOL *)(privTemplate[4].pValue) = sensitive ? CK_TRUE : CK_FALSE; + + /* Not everyone can handle zero padded key values, give + * them the raw data as unsigned */ + for (ap=attrs; extra_count; ap++, extra_count--) { + pk11_SignedToUnsigned(ap); + } + + /* now Store the puppies */ + rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate, + count, token, &objectID); + PORT_FreeArena(arena, PR_TRUE); + if (rv != SECSuccess) { + return NULL; + } + + /* try loading the public key as a token object */ + if (pubKey) { + PK11_ImportPublicKey(slot, pubKey, PR_TRUE); + if (pubKey->pkcs11Slot) { + PK11_FreeSlot(pubKey->pkcs11Slot); + pubKey->pkcs11Slot = NULL; + pubKey->pkcs11ID = CK_INVALID_HANDLE; + } + } + + /* build new key structure */ + return PK11_MakePrivKey(slot, privKey->keyType, (PRBool)!token, + objectID, privKey->wincx); +} + +/* + * export this for PSM + */ +SECKEYPrivateKey * +PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) +{ + return pk11_loadPrivKey(slot,privKey,pubKey,token,sensitive); +} + + +/* + * Use the token to Generate a key. keySize must be 'zero' for fixed key + * length algorithms. NOTE: this means we can never generate a DES2 key + * from this interface! + */ +SECKEYPrivateKey * +PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, + void *param, SECKEYPublicKey **pubKey, PRBool token, + PRBool sensitive, void *wincx) +{ + /* we have to use these native types because when we call PKCS 11 modules + * we have to make sure that we are using the correct sizes for all the + * parameters. */ + CK_BBOOL ckfalse = CK_FALSE; + CK_BBOOL cktrue = CK_TRUE; + CK_ULONG modulusBits; + CK_BYTE publicExponent[4]; + CK_ATTRIBUTE privTemplate[] = { + { CKA_SENSITIVE, NULL, 0}, + { CKA_TOKEN, NULL, 0}, + { CKA_PRIVATE, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_UNWRAP, NULL, 0}, + { CKA_SIGN, NULL, 0}, + { CKA_DECRYPT, NULL, 0}, + }; + CK_ATTRIBUTE rsaPubTemplate[] = { + { CKA_MODULUS_BITS, NULL, 0}, + { CKA_PUBLIC_EXPONENT, NULL, 0}, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + }; + CK_ATTRIBUTE dsaPubTemplate[] = { + { CKA_PRIME, NULL, 0 }, + { CKA_SUBPRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + }; + CK_ATTRIBUTE dhPubTemplate[] = { + { CKA_PRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + }; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE ecPubTemplate[] = { + { CKA_EC_PARAMS, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + }; + int ecPubCount = sizeof(ecPubTemplate)/sizeof(ecPubTemplate[0]); + SECKEYECParams * ecParams; +#endif /* NSS_ENABLE_ECC */ + + int dsaPubCount = sizeof(dsaPubTemplate)/sizeof(dsaPubTemplate[0]); + /*CK_ULONG key_size = 0;*/ + CK_ATTRIBUTE *pubTemplate; + int privCount = sizeof(privTemplate)/sizeof(privTemplate[0]); + int rsaPubCount = sizeof(rsaPubTemplate)/sizeof(rsaPubTemplate[0]); + int dhPubCount = sizeof(dhPubTemplate)/sizeof(dhPubTemplate[0]); + int pubCount = 0; + PK11RSAGenParams *rsaParams; + SECKEYPQGParams *dsaParams; + SECKEYDHParams * dhParams; + CK_MECHANISM mechanism; + CK_MECHANISM test_mech; + CK_SESSION_HANDLE session_handle; + CK_RV crv; + CK_OBJECT_HANDLE privID,pubID; + SECKEYPrivateKey *privKey; + KeyType keyType; + PRBool restore; + int peCount,i; + CK_ATTRIBUTE *attrs; + CK_ATTRIBUTE *privattrs; + SECItem *pubKeyIndex; + CK_ATTRIBUTE setTemplate; + SECStatus rv; + CK_MECHANISM_INFO mechanism_info; + CK_OBJECT_CLASS keyClass; + SECItem *cka_id; + PRBool haslock = PR_FALSE; + PRBool pubIsToken = PR_FALSE; + + PORT_Assert(slot != NULL); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE); + return NULL; + } + + /* if our slot really doesn't do this mechanism, Generate the key + * in our internal token and write it out */ + if (!PK11_DoesMechanism(slot,type)) { + PK11SlotInfo *int_slot = PK11_GetInternalSlot(); + + /* don't loop forever looking for a slot */ + if (slot == int_slot) { + PK11_FreeSlot(int_slot); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + + /* if there isn't a suitable slot, then we can't do the keygen */ + if (int_slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return NULL; + } + + /* generate the temporary key to load */ + privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE, + PR_FALSE, wincx); + PK11_FreeSlot(int_slot); + + /* if successful, load the temp key into the new token */ + if (privKey != NULL) { + SECKEYPrivateKey *newPrivKey = pk11_loadPrivKey(slot,privKey, + *pubKey,token,sensitive); + SECKEY_DestroyPrivateKey(privKey); + if (newPrivKey == NULL) { + SECKEY_DestroyPublicKey(*pubKey); + *pubKey = NULL; + } + return newPrivKey; + } + return NULL; + } + + + mechanism.mechanism = type; + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + test_mech.pParameter = NULL; + test_mech.ulParameterLen = 0; + + /* set up the private key template */ + privattrs = privTemplate; + PK11_SETATTRS(privattrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_TOKEN, token ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + + /* set up the mechanism specific info */ + switch (type) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + rsaParams = (PK11RSAGenParams *)param; + modulusBits = rsaParams->keySizeInBits; + peCount = 0; + + /* convert pe to a PKCS #11 string */ + for (i=0; i < 4; i++) { + if (peCount || (rsaParams->pe & + ((unsigned long)0xff000000L >> (i*8)))) { + publicExponent[peCount] = + (CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff); + peCount++; + } + } + PORT_Assert(peCount != 0); + attrs = rsaPubTemplate; + PK11_SETATTRS(attrs, CKA_MODULUS_BITS, + &modulusBits, sizeof(modulusBits)); attrs++; + PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, + publicExponent, peCount);attrs++; + pubTemplate = rsaPubTemplate; + pubCount = rsaPubCount; + keyType = rsaKey; + test_mech.mechanism = CKM_RSA_PKCS; + break; + case CKM_DSA_KEY_PAIR_GEN: + dsaParams = (SECKEYPQGParams *)param; + attrs = dsaPubTemplate; + PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data, + dsaParams->prime.len); attrs++; + PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data, + dsaParams->subPrime.len); attrs++; + PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data, + dsaParams->base.len); attrs++; + pubTemplate = dsaPubTemplate; + pubCount = dsaPubCount; + keyType = dsaKey; + test_mech.mechanism = CKM_DSA; + break; + case CKM_DH_PKCS_KEY_PAIR_GEN: + dhParams = (SECKEYDHParams *)param; + attrs = dhPubTemplate; + PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data, + dhParams->prime.len); attrs++; + PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data, + dhParams->base.len); attrs++; + pubTemplate = dhPubTemplate; + pubCount = dhPubCount; + keyType = dhKey; + test_mech.mechanism = CKM_DH_PKCS_DERIVE; + break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + ecParams = (SECKEYECParams *)param; + attrs = ecPubTemplate; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, + ecParams->len); attrs++; + pubTemplate = ecPubTemplate; + pubCount = ecPubCount; + keyType = ecKey; + /* XXX An EC key can be used for other mechanisms too such + * as CKM_ECDSA and CKM_ECDSA_SHA1. How can we reflect + * that in test_mech.mechanism so the CKA_SIGN, CKA_VERIFY + * attributes are set correctly? + */ + test_mech.mechanism = CKM_ECDH1_DERIVE; + break; +#endif /* NSS_ENABLE_ECC */ + default: + PORT_SetError( SEC_ERROR_BAD_KEY ); + return NULL; + } + + /* now query the slot to find out how "good" a key we can generate */ + if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, + test_mech.mechanism,&mechanism_info); + if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); + if ((crv != CKR_OK) || (mechanism_info.flags == 0)) { + /* must be old module... guess what it should be... */ + switch (test_mech.mechanism) { + case CKM_RSA_PKCS: + mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT | + CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP);; + break; + case CKM_DSA: + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; + break; + case CKM_DH_PKCS_DERIVE: + mechanism_info.flags = CKF_DERIVE; + break; +#ifdef NSS_ENABLE_ECC + case CKM_ECDH1_DERIVE: + mechanism_info.flags = CKF_DERIVE; + break; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; + break; +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + } + /* set the public key objects */ + PK11_SETATTRS(attrs, CKA_TOKEN, token ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_DERIVE, + mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_WRAP, + mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_VERIFY, + mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER, + mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(attrs, CKA_ENCRYPT, + mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); attrs++; + PK11_SETATTRS(privattrs, CKA_DERIVE, + mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_UNWRAP, + mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_SIGN, + mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + PK11_SETATTRS(privattrs, CKA_DECRYPT, + mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse, + sizeof(CK_BBOOL)); privattrs++; + + if (token) { + session_handle = PK11_GetRWSession(slot); + haslock = PK11_RWSessionHasLock(slot,session_handle); + restore = PR_TRUE; + } else { + PK11_EnterSlotMonitor(slot); /* gross!! */ + session_handle = slot->session; + restore = PR_FALSE; + haslock = PR_TRUE; + } + + crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism, + pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID); + + if (crv != CKR_OK) { + if (restore) { + PK11_RestoreROSession(slot,session_handle); + } else PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + /* This locking code is dangerous and needs to be more thought + * out... the real problem is that we're holding the mutex open this long + */ + if (haslock) { PK11_ExitSlotMonitor(slot); } + + /* swap around the ID's for older PKCS #11 modules */ + keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS); + if (keyClass != CKO_PUBLIC_KEY) { + CK_OBJECT_HANDLE tmp = pubID; + pubID = privID; + privID = tmp; + } + + *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID); + if (*pubKey == NULL) { + if (restore) { + /* we may have to restore the mutex so it get's exited properly + * in RestoreROSession */ + if (haslock) PK11_EnterSlotMonitor(slot); + PK11_RestoreROSession(slot,session_handle); + } + PK11_DestroyObject(slot,pubID); + PK11_DestroyObject(slot,privID); + return NULL; + } + + /* set the ID to the public key so we can find it again */ + pubKeyIndex = NULL; + switch (type) { + case CKM_RSA_PKCS_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.rsa.modulus; + break; + case CKM_DSA_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.dsa.publicValue; + break; + case CKM_DH_PKCS_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.dh.publicValue; + break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.ec.publicValue; + break; +#endif /* NSS_ENABLE_ECC */ + } + PORT_Assert(pubKeyIndex != NULL); + + cka_id = PK11_MakeIDFromPubKey(pubKeyIndex); + pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN); + + PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len); + + if (haslock) { PK11_EnterSlotMonitor(slot); } + crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID, + &setTemplate, 1); + + if (crv == CKR_OK && pubIsToken) { + crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID, + &setTemplate, 1); + } + + + if (restore) { + PK11_RestoreROSession(slot,session_handle); + } else { + PK11_ExitSlotMonitor(slot); + } + SECITEM_FreeItem(cka_id,PR_TRUE); + + + if (crv != CKR_OK) { + PK11_DestroyObject(slot,pubID); + PK11_DestroyObject(slot,privID); + PORT_SetError( PK11_MapError(crv) ); + *pubKey = NULL; + return NULL; + } + + privKey = PK11_MakePrivKey(slot,keyType,(PRBool)!token,privID,wincx); + if (privKey == NULL) { + SECKEY_DestroyPublicKey(*pubKey); + PK11_DestroyObject(slot,privID); + *pubKey = NULL; + return NULL; /* due to pairwise consistency check */ + } + + /* Perform PKCS #11 pairwise consistency check. */ + rv = pk11_PairwiseConsistencyCheck( *pubKey, privKey, &test_mech, wincx ); + if( rv != SECSuccess ) { + SECKEY_DestroyPublicKey( *pubKey ); + SECKEY_DestroyPrivateKey( privKey ); + *pubKey = NULL; + privKey = NULL; + return NULL; + } + + return privKey; +} + +/* build a public KEA key from the public value */ +SECKEYPublicKey * +PK11_MakeKEAPubKey(unsigned char *keyData,int length) +{ + SECKEYPublicKey *pubk; + SECItem pkData; + SECStatus rv; + PRArenaPool *arena; + + pkData.data = keyData; + pkData.len = length; + + arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) + return NULL; + + pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); + if (pubk == NULL) { + PORT_FreeArena (arena, PR_FALSE); + return NULL; + } + + pubk->arena = arena; + pubk->pkcs11Slot = 0; + pubk->pkcs11ID = CK_INVALID_HANDLE; + pubk->keyType = fortezzaKey; + rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData); + if (rv != SECSuccess) { + PORT_FreeArena (arena, PR_FALSE); + return NULL; + } + return pubk; +} + +SECStatus +PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, + SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, + SECItem *nickname, SECItem *publicValue, PRBool isPerm, + PRBool isPrivate, KeyType keyType, + unsigned int keyUsage, void *wincx) +{ + CK_MECHANISM_TYPE mechanism; + SECItem *pbe_param, crypto_param; + PK11SymKey *key = NULL; + SECStatus rv = SECSuccess; + CK_MECHANISM cryptoMech, pbeMech; + CK_RV crv; + SECKEYPrivateKey *privKey = NULL; + PRBool faulty3DES = PR_FALSE; + int usageCount = 0; + CK_KEY_TYPE key_type; + CK_ATTRIBUTE_TYPE *usage = NULL; + CK_ATTRIBUTE_TYPE rsaUsage[] = { + CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER }; + CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN }; + CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE }; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE_TYPE ecUsage[] = { CKA_SIGN, CKA_DERIVE }; +#endif /* NSS_ENABLE_ECC */ + if((epki == NULL) || (pwitem == NULL)) + return SECFailure; + + crypto_param.data = NULL; + + mechanism = PK11_AlgtagToMechanism(SECOID_FindOIDTag( + &epki->algorithm.algorithm)); + + switch (keyType) { + default: + case rsaKey: + key_type = CKK_RSA; + switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) { + case KU_KEY_ENCIPHERMENT: + usage = rsaUsage; + usageCount = 2; + break; + case KU_DIGITAL_SIGNATURE: + usage = &rsaUsage[2]; + usageCount = 2; + break; + case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE: + case 0: /* default to everything */ + usage = rsaUsage; + usageCount = 4; + break; + } + break; + case dhKey: + key_type = CKK_DH; + usage = dhUsage; + usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]); + break; + case dsaKey: + key_type = CKK_DSA; + usage = dsaUsage; + usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]); + break; +#ifdef NSS_ENABLE_ECC + case ecKey: + key_type = CKK_EC; + switch (keyUsage & (KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) { + case KU_DIGITAL_SIGNATURE: + usage = ecUsage; + usageCount = 1; + break; + case KU_KEY_AGREEMENT: + usage = &ecUsage[1]; + usageCount = 1; + break; + case KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT: + default: /* default to everything */ + usage = ecUsage; + usageCount = 2; + break; + } + break; +#endif /* NSS_ENABLE_ECC */ + } + +try_faulty_3des: + pbe_param = PK11_ParamFromAlgid(&epki->algorithm); + + key = PK11_RawPBEKeyGen(slot, mechanism, pbe_param, pwitem, + faulty3DES, wincx); + if((key == NULL) || (pbe_param == NULL)) { + rv = SECFailure; + goto done; + } + + pbeMech.mechanism = mechanism; + pbeMech.pParameter = pbe_param->data; + pbeMech.ulParameterLen = pbe_param->len; + + crv = PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, + pwitem, faulty3DES); + if(crv != CKR_OK) { + rv = SECFailure; + goto done; + } + + cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMech.mechanism); + crypto_param.data = (unsigned char*)cryptoMech.pParameter; + crypto_param.len = cryptoMech.ulParameterLen; + + PORT_Assert(usage != NULL); + PORT_Assert(usageCount != 0); + privKey = PK11_UnwrapPrivKey(slot, key, cryptoMech.mechanism, + &crypto_param, &epki->encryptedData, + nickname, publicValue, isPerm, isPrivate, + key_type, usage, usageCount, wincx); + if(privKey) { + SECKEY_DestroyPrivateKey(privKey); + privKey = NULL; + rv = SECSuccess; + goto done; + } + + /* if we are unable to import the key and the mechanism is + * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that + * the encrypted blob was created with a buggy key generation method + * which is described in the PKCS 12 implementation notes. So we + * need to try importing via that method. + */ + if((mechanism == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC) && (!faulty3DES)) { + /* clean up after ourselves before redoing the key generation. */ + + PK11_FreeSymKey(key); + key = NULL; + + if(pbe_param) { + SECITEM_ZfreeItem(pbe_param, PR_TRUE); + pbe_param = NULL; + } + + if(crypto_param.data) { + SECITEM_ZfreeItem(&crypto_param, PR_FALSE); + crypto_param.data = NULL; + cryptoMech.pParameter = NULL; + crypto_param.len = cryptoMech.ulParameterLen = 0; + } + + faulty3DES = PR_TRUE; + goto try_faulty_3des; + } + + /* key import really did fail */ + rv = SECFailure; + +done: + if(pbe_param != NULL) { + SECITEM_ZfreeItem(pbe_param, PR_TRUE); + pbe_param = NULL; + } + + if(crypto_param.data != NULL) { + SECITEM_ZfreeItem(&crypto_param, PR_FALSE); + } + + if(key != NULL) { + PK11_FreeSymKey(key); + } + + return rv; +} + +SECKEYPrivateKeyInfo * +PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx) +{ + return NULL; +} + +static int +pk11_private_key_encrypt_buffer_length(SECKEYPrivateKey *key) + +{ + CK_ATTRIBUTE rsaTemplate = { CKA_MODULUS, NULL, 0 }; + CK_ATTRIBUTE dsaTemplate = { CKA_PRIME, NULL, 0 }; +#ifdef NSS_ENABLE_ECC + /* XXX We should normally choose an attribute such that + * factor times its size is enough to hold the private key. + * For EC keys, we have no choice but to use CKA_EC_PARAMS, + * CKA_VALUE is not available for token keys. But for named + * curves, the number of bytes needed to represent the params + * is quite small so we bump up factor from 10 to 15. + */ + CK_ATTRIBUTE ecTemplate = { CKA_EC_PARAMS, NULL, 0 }; +#endif /* NSS_ENABLE_ECC */ + CK_ATTRIBUTE_PTR pTemplate; + CK_RV crv; + int length; + int factor = 10; + + if(!key) { + return -1; + } + + switch (key->keyType) { + case rsaKey: + pTemplate = &rsaTemplate; + break; + case dsaKey: + case dhKey: + pTemplate = &dsaTemplate; + break; +#ifdef NSS_ENABLE_ECC + case ecKey: + pTemplate = &ecTemplate; + factor = 15; + break; +#endif /* NSS_ENABLE_ECC */ + case fortezzaKey: + default: + pTemplate = NULL; + } + + if(!pTemplate) { + return -1; + } + + crv = PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID, + pTemplate, 1); + if(crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return -1; + } + + length = pTemplate->ulValueLen; + length *= factor; + + + if(pTemplate->pValue != NULL) { + PORT_Free(pTemplate->pValue); + } + + return length; +} + +SECKEYEncryptedPrivateKeyInfo * +PK11_ExportEncryptedPrivKeyInfo( + PK11SlotInfo *slot, /* optional, encrypt key in this slot */ + SECOidTag algTag, /* encrypt key with this algorithm */ + SECItem *pwitem, /* password for PBE encryption */ + SECKEYPrivateKey *pk, /* encrypt this private key */ + int iteration, /* interations for PBE alg */ + void *wincx) /* context for password callback ? */ +{ + SECKEYEncryptedPrivateKeyInfo *epki = NULL; + PRArenaPool *arena = NULL; + SECAlgorithmID *algid; + SECItem *pbe_param = NULL; + PK11SymKey *key = NULL; + SECStatus rv = SECSuccess; + int encryptBufLen; + CK_RV crv; + CK_ULONG encBufLenPtr; + CK_MECHANISM_TYPE mechanism; + CK_MECHANISM pbeMech; + CK_MECHANISM cryptoMech; + SECItem crypto_param; + SECItem encryptedKey = {siBuffer, NULL, 0}; + + if (!pwitem || !pk) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + + algid = SEC_PKCS5CreateAlgorithmID(algTag, NULL, iteration); + if (algid == NULL) { + return NULL; + } + + crypto_param.data = NULL; + + arena = PORT_NewArena(2048); + if (arena) + epki = PORT_ArenaZNew(arena, SECKEYEncryptedPrivateKeyInfo); + if(epki == NULL) { + rv = SECFailure; + goto loser; + } + epki->arena = arena; + + mechanism = PK11_AlgtagToMechanism(algTag); + pbe_param = PK11_ParamFromAlgid(algid); + if (!pbe_param || mechanism == CKM_INVALID_MECHANISM) { + rv = SECFailure; + goto loser; + } + pbeMech.mechanism = mechanism; + pbeMech.pParameter = pbe_param->data; + pbeMech.ulParameterLen = pbe_param->len; + + /* if we didn't specify a slot, use the slot the private key was in */ + if (!slot) { + slot = pk->pkcs11Slot; + } + + /* if we specified a different slot, and the private key slot can do the + * pbe key gen, generate the key in the private key slot so we don't have + * to move it later */ + if (slot != pk->pkcs11Slot) { + if (PK11_DoesMechanism(pk->pkcs11Slot,mechanism)) { + slot = pk->pkcs11Slot; + } + } + key = PK11_RawPBEKeyGen(slot, mechanism, pbe_param, pwitem, + PR_FALSE, wincx); + + if((key == NULL) || (pbe_param == NULL)) { + rv = SECFailure; + goto loser; + } + + crv = PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, + pwitem, PR_FALSE); + if(crv != CKR_OK) { + rv = SECFailure; + goto loser; + } + cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMech.mechanism); + crypto_param.data = (unsigned char *)cryptoMech.pParameter; + crypto_param.len = cryptoMech.ulParameterLen; + + + encryptBufLen = pk11_private_key_encrypt_buffer_length(pk); + if(encryptBufLen == -1) { + rv = SECFailure; + goto loser; + } + encryptedKey.len = (unsigned int)encryptBufLen; + encBufLenPtr = (CK_ULONG) encryptBufLen; + encryptedKey.data = (unsigned char *)PORT_ZAlloc(encryptedKey.len); + if(!encryptedKey.data) { + rv = SECFailure; + goto loser; + } + + /* If the key isn't in the private key slot, move it */ + if (key->slot != pk->pkcs11Slot) { + PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot, + key->type, CKA_WRAP, key); + if (newkey == NULL) { + rv= SECFailure; + goto loser; + } + + /* free the old key and use the new key */ + PK11_FreeSymKey(key); + key = newkey; + } + + /* we are extracting an encrypted privateKey structure. + * which needs to be freed along with the buffer into which it is + * returned. eventually, we should retrieve an encrypted key using + * pkcs8/pkcs5. + */ + PK11_EnterSlotMonitor(pk->pkcs11Slot); + crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, + &cryptoMech, key->objectID, pk->pkcs11ID, encryptedKey.data, + &encBufLenPtr); + PK11_ExitSlotMonitor(pk->pkcs11Slot); + encryptedKey.len = (unsigned int) encBufLenPtr; + if(crv != CKR_OK) { + rv = SECFailure; + goto loser; + } + + if(!encryptedKey.len) { + rv = SECFailure; + goto loser; + } + + rv = SECITEM_CopyItem(arena, &epki->encryptedData, &encryptedKey); + if(rv != SECSuccess) { + goto loser; + } + + rv = SECOID_CopyAlgorithmID(arena, &epki->algorithm, algid); + +loser: + if(pbe_param != NULL) { + SECITEM_ZfreeItem(pbe_param, PR_TRUE); + pbe_param = NULL; + } + + if(crypto_param.data != NULL) { + SECITEM_ZfreeItem(&crypto_param, PR_FALSE); + crypto_param.data = NULL; + } + + if(key != NULL) { + PK11_FreeSymKey(key); + } + SECOID_DestroyAlgorithmID(algid, PR_TRUE); + + if(rv == SECFailure) { + if(arena != NULL) { + PORT_FreeArena(arena, PR_TRUE); + } + epki = NULL; + } + + return epki; +} + +SECKEYEncryptedPrivateKeyInfo * +PK11_ExportEncryptedPrivateKeyInfo( + PK11SlotInfo *slot, /* optional, encrypt key in this slot */ + SECOidTag algTag, /* encrypt key with this algorithm */ + SECItem *pwitem, /* password for PBE encryption */ + CERTCertificate *cert, /* wrap priv key for this user cert */ + int iteration, /* interations for PBE alg */ + void *wincx) /* context for password callback ? */ +{ + SECKEYEncryptedPrivateKeyInfo *epki = NULL; + SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx); + if (pk != NULL) { + epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk, + iteration, wincx); + SECKEY_DestroyPrivateKey(pk); + } + return epki; +} + +SECItem* +PK11_DEREncodePublicKey(SECKEYPublicKey *pubk) +{ + CERTSubjectPublicKeyInfo *spki=NULL; + SECItem *spkiDER = NULL; + + if( pubk == NULL ) { + return NULL; + } + + /* get the subjectpublickeyinfo */ + spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); + if( spki == NULL ) { + goto finish; + } + + /* DER-encode the subjectpublickeyinfo */ + spkiDER = SEC_ASN1EncodeItem(NULL /*arena*/, NULL/*dest*/, spki, + CERT_SubjectPublicKeyInfoTemplate); + +finish: + return spkiDER; +} + +char * +PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey) +{ + return PK11_GetObjectNickname(privKey->pkcs11Slot,privKey->pkcs11ID); +} + +char * +PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey) +{ + return PK11_GetObjectNickname(pubKey->pkcs11Slot,pubKey->pkcs11ID); +} + +SECStatus +PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, const char *nickname) +{ + return PK11_SetObjectNickname(privKey->pkcs11Slot, + privKey->pkcs11ID,nickname); +} + +SECStatus +PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, const char *nickname) +{ + return PK11_SetObjectNickname(pubKey->pkcs11Slot, + pubKey->pkcs11ID,nickname); +} + +SECKEYPQGParams * +PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey) +{ + CK_ATTRIBUTE pTemplate[] = { + { CKA_PRIME, NULL, 0 }, + { CKA_SUBPRIME, NULL, 0 }, + { CKA_BASE, NULL, 0 }, + }; + int pTemplateLen = sizeof(pTemplate)/sizeof(pTemplate[0]); + PRArenaPool *arena = NULL; + SECKEYPQGParams *params; + CK_RV crv; + + + arena = PORT_NewArena(2048); + if (arena == NULL) { + goto loser; + } + params=(SECKEYPQGParams *)PORT_ArenaZAlloc(arena,sizeof(SECKEYPQGParams)); + if (params == NULL) { + goto loser; + } + + crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, + pTemplate, pTemplateLen); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + goto loser; + } + + params->arena = arena; + params->prime.data = pTemplate[0].pValue; + params->prime.len = pTemplate[0].ulValueLen; + params->subPrime.data = pTemplate[1].pValue; + params->subPrime.len = pTemplate[1].ulValueLen; + params->base.data = pTemplate[2].pValue; + params->base.len = pTemplate[2].ulValueLen; + + return params; + +loser: + if (arena != NULL) { + PORT_FreeArena(arena,PR_FALSE); + } + return NULL; +} + +SECKEYPrivateKey* +PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void* wincx) +{ + PK11SlotInfo* slot = privk->pkcs11Slot; + CK_ATTRIBUTE template[1]; + CK_ATTRIBUTE *attrs = template; + CK_BBOOL cktrue = CK_TRUE; + CK_RV crv; + CK_OBJECT_HANDLE newKeyID; + CK_SESSION_HANDLE rwsession; + + PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; + + PK11_Authenticate(slot, PR_TRUE, wincx); + rwsession = PK11_GetRWSession(slot); + crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, privk->pkcs11ID, + template, 1, &newKeyID); + PK11_RestoreROSession(slot, rwsession); + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + + return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/, + newKeyID, NULL /*wincx*/); +} +/* + * destroy a private key if there are no matching certs. + * this function also frees the privKey structure. + */ +SECStatus +PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force) +{ + CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey); + + /* found a cert matching the private key?. */ + if (!force && cert != NULL) { + /* yes, don't delete the key */ + CERT_DestroyCertificate(cert); + SECKEY_DestroyPrivateKey(privKey); + return SECWouldBlock; + } + /* now, then it's safe for the key to go away */ + PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID); + SECKEY_DestroyPrivateKey(privKey); + return SECSuccess; +} + +/* + * destroy a private key if there are no matching certs. + * this function also frees the privKey structure. + */ +SECStatus +PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey) +{ + /* now, then it's safe for the key to go away */ + if (pubKey->pkcs11Slot == NULL) { + return SECFailure; + } + PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID); + SECKEY_DestroyPublicKey(pubKey); + return SECSuccess; +} + +/* + * key call back structure. + */ +typedef struct pk11KeyCallbackStr { + SECStatus (* callback)(SECKEYPrivateKey *,void *); + void *callbackArg; + void *wincx; +} pk11KeyCallback; + +/* + * callback to map Object Handles to Private Keys; + */ +SECStatus +pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg) +{ + SECStatus rv = SECSuccess; + SECKEYPrivateKey *privKey; + pk11KeyCallback *keycb = (pk11KeyCallback *) arg; + + privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx); + + if (privKey == NULL) { + return SECFailure; + } + + if (keycb && (keycb->callback)) { + rv = (*keycb->callback)(privKey,keycb->callbackArg); + } + + SECKEY_DestroyPrivateKey(privKey); + return rv; +} + +/*********************************************************************** + * PK11_TraversePrivateKeysInSlot + * + * Traverses all the private keys on a slot. + * + * INPUTS + * slot + * The PKCS #11 slot whose private keys you want to traverse. + * callback + * A callback function that will be called for each key. + * arg + * An argument that will be passed to the callback function. + */ +SECStatus +PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, + SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg) +{ + pk11KeyCallback perKeyCB; + pk11TraverseSlot perObjectCB; + CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY; + CK_BBOOL ckTrue = CK_TRUE; + CK_ATTRIBUTE theTemplate[2]; + int templateSize = 2; + + theTemplate[0].type = CKA_CLASS; + theTemplate[0].pValue = &privkClass; + theTemplate[0].ulValueLen = sizeof(privkClass); + theTemplate[1].type = CKA_TOKEN; + theTemplate[1].pValue = &ckTrue; + theTemplate[1].ulValueLen = sizeof(ckTrue); + + if(slot==NULL) { + return SECSuccess; + } + + perObjectCB.callback = pk11_DoKeys; + perObjectCB.callbackArg = &perKeyCB; + perObjectCB.findTemplate = theTemplate; + perObjectCB.templateCount = templateSize; + perKeyCB.callback = callback; + perKeyCB.callbackArg = arg; + perKeyCB.wincx = NULL; + + return PK11_TraverseSlot(slot, &perObjectCB); +} + +/* + * return the private key with the given ID + */ +CK_OBJECT_HANDLE +pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID) +{ + CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; + CK_ATTRIBUTE theTemplate[] = { + { CKA_ID, NULL, 0 }, + { CKA_CLASS, NULL, 0 }, + }; + /* if you change the array, change the variable below as well */ + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); + CK_ATTRIBUTE *attrs = theTemplate; + + PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++; + PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey)); + + return pk11_FindObjectByTemplate(slot,theTemplate,tsize); +} + + +SECKEYPrivateKey * +PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx) +{ + CK_OBJECT_HANDLE keyHandle; + SECKEYPrivateKey *privKey; + + keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID); + if (keyHandle == CK_INVALID_HANDLE) { + return NULL; + } + privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); + return privKey; +} + +/* + * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated + * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make + * smart cards happy. + */ +SECItem * +PK11_MakeIDFromPubKey(SECItem *pubKeyData) +{ + PK11Context *context; + SECItem *certCKA_ID; + SECStatus rv; + + context = PK11_CreateDigestContext(SEC_OID_SHA1); + if (context == NULL) { + return NULL; + } + + rv = PK11_DigestBegin(context); + if (rv == SECSuccess) { + rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len); + } + if (rv != SECSuccess) { + PK11_DestroyContext(context,PR_TRUE); + return NULL; + } + + certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem)); + if (certCKA_ID == NULL) { + PK11_DestroyContext(context,PR_TRUE); + return NULL; + } + + certCKA_ID->len = SHA1_LENGTH; + certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len); + if (certCKA_ID->data == NULL) { + PORT_Free(certCKA_ID); + PK11_DestroyContext(context,PR_TRUE); + return NULL; + } + + rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len, + SHA1_LENGTH); + PK11_DestroyContext(context,PR_TRUE); + if (rv != SECSuccess) { + SECITEM_FreeItem(certCKA_ID,PR_TRUE); + return NULL; + } + + return certCKA_ID; +} + +SECItem * +PK11_GetKeyIDFromPrivateKey(SECKEYPrivateKey *key, void *wincx) +{ + CK_ATTRIBUTE theTemplate[] = { + { CKA_ID, NULL, 0 }, + }; + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); + SECItem *item = NULL; + CK_RV crv; + + crv = PK11_GetAttributes(NULL,key->pkcs11Slot,key->pkcs11ID, + theTemplate,tsize); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + goto loser; + } + + item = PORT_ZNew(SECItem); + if (item) { + item->data = (unsigned char*) theTemplate[0].pValue; + item->len = theTemplate[0].ulValueLen; + } + +loser: + return item; +} + +SECItem * +PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey) +{ + return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID); +} + +static SECStatus +privateKeyListCallback(SECKEYPrivateKey *key, void *arg) +{ + SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg; + return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key)); +} + +SECKEYPrivateKeyList* +PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot) +{ + SECStatus status; + SECKEYPrivateKeyList *keys; + + keys = SECKEY_NewPrivateKeyList(); + if(keys == NULL) return NULL; + + status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback, + (void*)keys); + + if( status != SECSuccess ) { + SECKEY_DestroyPrivateKeyList(keys); + keys = NULL; + } + + return keys; +} + +SECKEYPublicKeyList* +PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname) +{ + CK_ATTRIBUTE findTemp[4]; + CK_ATTRIBUTE *attrs; + CK_BBOOL ckTrue = CK_TRUE; + CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY; + int tsize = 0; + int objCount = 0; + CK_OBJECT_HANDLE *key_ids; + SECKEYPublicKeyList *keys; + int i,len; + + + attrs = findTemp; + PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; + if (nickname) { + len = PORT_Strlen(nickname)-1; + PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; + } + tsize = attrs - findTemp; + PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); + + key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); + if (key_ids == NULL) { + return NULL; + } + keys = SECKEY_NewPublicKeyList(); + if (keys == NULL) { + PORT_Free(key_ids); + } + + for (i=0; i < objCount ; i++) { + SECKEYPublicKey *pubKey = + PK11_ExtractPublicKey(slot,nullKey,key_ids[i]); + if (pubKey) { + SECKEY_AddPublicKeyToListTail(keys, pubKey); + } + } + + PORT_Free(key_ids); + return keys; +} + +SECKEYPrivateKeyList* +PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx) +{ + CK_ATTRIBUTE findTemp[4]; + CK_ATTRIBUTE *attrs; + CK_BBOOL ckTrue = CK_TRUE; + CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; + int tsize = 0; + int objCount = 0; + CK_OBJECT_HANDLE *key_ids; + SECKEYPrivateKeyList *keys; + int i,len; + + + attrs = findTemp; + PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; + if (nickname) { + len = PORT_Strlen(nickname)-1; + PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; + } + tsize = attrs - findTemp; + PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); + + key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); + if (key_ids == NULL) { + return NULL; + } + keys = SECKEY_NewPrivateKeyList(); + if (keys == NULL) { + PORT_Free(key_ids); + } + + for (i=0; i < objCount ; i++) { + SECKEYPrivateKey *privKey = + PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx); + SECKEY_AddPrivateKeyToListTail(keys, privKey); + } + + PORT_Free(key_ids); + return keys; +} + diff --git a/security/nss/lib/pk11wrap/pk11auth.c b/security/nss/lib/pk11wrap/pk11auth.c new file mode 100644 index 00000000000..a3448f45c78 --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11auth.c @@ -0,0 +1,702 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file deals with PKCS #11 passwords and authentication. + */ +#include "seccomon.h" +#include "secmod.h" +#include "secmodi.h" +#include "secmodti.h" +#include "pkcs11t.h" +#include "pk11func.h" +#include "secitem.h" +#include "secerr.h" + +#include "pkim.h" + + +/************************************************************* + * local static and global data + *************************************************************/ +/* + * This structure keeps track of status that spans all the Slots. + * NOTE: This is a global data structure. It semantics expect thread crosstalk + * be very careful when you see it used. + * It's major purpose in life is to allow the user to log in one PER + * Tranaction, even if a transaction spans threads. The problem is the user + * may have to enter a password one just to be able to look at the + * personalities/certificates (s)he can use. Then if Auth every is one, they + * may have to enter the password again to use the card. See PK11_StartTransac + * and PK11_EndTransaction. + */ +static struct PK11GlobalStruct { + int transaction; + PRBool inTransaction; + char *(PR_CALLBACK *getPass)(PK11SlotInfo *,PRBool,void *); + PRBool (PR_CALLBACK *verifyPass)(PK11SlotInfo *,void *); + PRBool (PR_CALLBACK *isLoggedIn)(PK11SlotInfo *,void *); +} PK11_Global = { 1, PR_FALSE, NULL, NULL, NULL }; + +/*********************************************************** + * Password Utilities + ***********************************************************/ +/* + * Check the user's password. Log into the card if it's correct. + * succeed if the user is already logged in. + */ +SECStatus +pk11_CheckPassword(PK11SlotInfo *slot,char *pw) +{ + int len = PORT_Strlen(pw); + CK_RV crv; + SECStatus rv; + int64 currtime = PR_Now(); + + if (slot->protectedAuthPath) { + len = 0; + pw = NULL; + } + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, + (unsigned char *)pw,len); + slot->lastLoginCheck = 0; + PK11_ExitSlotMonitor(slot); + switch (crv) { + /* if we're already logged in, we're good to go */ + case CKR_OK: + slot->authTransact = PK11_Global.transaction; + case CKR_USER_ALREADY_LOGGED_IN: + slot->authTime = currtime; + rv = SECSuccess; + break; + case CKR_PIN_INCORRECT: + PORT_SetError(SEC_ERROR_BAD_PASSWORD); + rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ + break; + default: + PORT_SetError(PK11_MapError(crv)); + rv = SECFailure; /* some failure we can't fix by retrying */ + } + return rv; +} + +/* + * Check the user's password. Logout before hand to make sure that + * we are really checking the password. + */ +SECStatus +PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw) +{ + int len = PORT_Strlen(pw); + CK_RV crv; + SECStatus rv; + int64 currtime = PR_Now(); + + if (slot->protectedAuthPath) { + len = 0; + pw = NULL; + } + + /* force a logout */ + PK11_EnterSlotMonitor(slot); + PK11_GETTAB(slot)->C_Logout(slot->session); + + crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, + (unsigned char *)pw,len); + slot->lastLoginCheck = 0; + PK11_ExitSlotMonitor(slot); + switch (crv) { + /* if we're already logged in, we're good to go */ + case CKR_OK: + slot->authTransact = PK11_Global.transaction; + slot->authTime = currtime; + rv = SECSuccess; + break; + case CKR_PIN_INCORRECT: + PORT_SetError(SEC_ERROR_BAD_PASSWORD); + rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ + break; + default: + PORT_SetError(PK11_MapError(crv)); + rv = SECFailure; /* some failure we can't fix by retrying */ + } + return rv; +} + +SECStatus +PK11_Logout(PK11SlotInfo *slot) +{ + CK_RV crv; + + /* force a logout */ + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_Logout(slot->session); + slot->lastLoginCheck = 0; + PK11_ExitSlotMonitor(slot); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + return SECFailure; + } + return SECSuccess; +} + +/* + * transaction stuff is for when we test for the need to do every + * time auth to see if we already did it for this slot/transaction + */ +void PK11_StartAuthTransaction(void) +{ +PK11_Global.transaction++; +PK11_Global.inTransaction = PR_TRUE; +} + +void PK11_EndAuthTransaction(void) +{ +PK11_Global.transaction++; +PK11_Global.inTransaction = PR_FALSE; +} + +/* + * before we do a private key op, we check to see if we + * need to reauthenticate. + */ +void +PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx) +{ + int askpw = slot->askpw; + PRBool NeedAuth = PR_FALSE; + + if (!slot->needLogin) return; + + if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { + PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); + + if (def_slot) { + askpw = def_slot->askpw; + PK11_FreeSlot(def_slot); + } + } + + /* timeouts are handled by isLoggedIn */ + if (!PK11_IsLoggedIn(slot,wincx)) { + NeedAuth = PR_TRUE; + } else if (askpw == -1) { + if (!PK11_Global.inTransaction || + (PK11_Global.transaction != slot->authTransact)) { + PK11_EnterSlotMonitor(slot); + PK11_GETTAB(slot)->C_Logout(slot->session); + slot->lastLoginCheck = 0; + PK11_ExitSlotMonitor(slot); + NeedAuth = PR_TRUE; + } + } + if (NeedAuth) PK11_DoPassword(slot,PR_TRUE,wincx); +} + +void +PK11_SlotDBUpdate(PK11SlotInfo *slot) +{ + SECMOD_UpdateModule(slot->module); +} + +/* + * set new askpw and timeout values + */ +void +PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout) +{ + slot->askpw = askpw; + slot->timeout = timeout; + slot->defaultFlags |= PK11_OWN_PW_DEFAULTS; + PK11_SlotDBUpdate(slot); +} + +/* + * Get the askpw and timeout values for this slot + */ +void +PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout) +{ + *askpw = slot->askpw; + *timeout = slot->timeout; + + if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { + PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); + + if (def_slot) { + *askpw = def_slot->askpw; + *timeout = def_slot->timeout; + PK11_FreeSlot(def_slot); + } + } +} + +/* + * Returns true if the token is needLogin and isn't logged in. + * This function is used to determine if authentication is needed + * before attempting a potentially privelleged operation. + */ +PRBool +pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx) +{ + return slot->needLogin && !PK11_IsLoggedIn(slot,wincx); +} + +/* + * make sure a slot is authenticated... + * This function only does the authentication if it is needed. + */ +SECStatus +PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) { + if (pk11_LoginStillRequired(slot,wincx)) { + return PK11_DoPassword(slot,loadCerts,wincx); + } + return SECSuccess; +} + +/* + * Authenticate to "unfriendly" tokens (tokens which need to be logged + * in to find the certs. + */ +SECStatus +pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) +{ + SECStatus rv = SECSuccess; + if (!PK11_IsFriendly(slot)) { + rv = PK11_Authenticate(slot, loadCerts, wincx); + } + return rv; +} + + +/* + * NOTE: this assumes that we are logged out of the card before hand + */ +SECStatus +PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw) +{ + CK_SESSION_HANDLE rwsession; + CK_RV crv; + SECStatus rv = SECFailure; + int len = PORT_Strlen(ssopw); + + /* get a rwsession */ + rwsession = PK11_GetRWSession(slot); + if (rwsession == CK_INVALID_SESSION) return rv; + + if (slot->protectedAuthPath) { + len = 0; + ssopw = NULL; + } + + /* check the password */ + crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, + (unsigned char *)ssopw,len); + slot->lastLoginCheck = 0; + switch (crv) { + /* if we're already logged in, we're good to go */ + case CKR_OK: + rv = SECSuccess; + break; + case CKR_PIN_INCORRECT: + PORT_SetError(SEC_ERROR_BAD_PASSWORD); + rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ + break; + default: + PORT_SetError(PK11_MapError(crv)); + rv = SECFailure; /* some failure we can't fix by retrying */ + } + PK11_GETTAB(slot)->C_Logout(rwsession); + slot->lastLoginCheck = 0; + + /* release rwsession */ + PK11_RestoreROSession(slot,rwsession); + return rv; +} + +/* + * make sure the password conforms to your token's requirements. + */ +SECStatus +PK11_VerifyPW(PK11SlotInfo *slot,char *pw) +{ + int len = PORT_Strlen(pw); + + if ((slot->minPassword > len) || (slot->maxPassword < len)) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + return SECSuccess; +} + +/* + * initialize a user PIN Value + */ +SECStatus +PK11_InitPin(PK11SlotInfo *slot,char *ssopw, char *userpw) +{ + CK_SESSION_HANDLE rwsession = CK_INVALID_SESSION; + CK_RV crv; + SECStatus rv = SECFailure; + int len; + int ssolen; + + if (userpw == NULL) userpw = ""; + if (ssopw == NULL) ssopw = ""; + + len = PORT_Strlen(userpw); + ssolen = PORT_Strlen(ssopw); + + /* get a rwsession */ + rwsession = PK11_GetRWSession(slot); + if (rwsession == CK_INVALID_SESSION) goto done; + + if (slot->protectedAuthPath) { + len = 0; + ssolen = 0; + ssopw = NULL; + userpw = NULL; + } + + /* check the password */ + crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, + (unsigned char *)ssopw,ssolen); + slot->lastLoginCheck = 0; + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + goto done; + } + + crv = PK11_GETTAB(slot)->C_InitPIN(rwsession,(unsigned char *)userpw,len); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + } else { + rv = SECSuccess; + } + +done: + PK11_GETTAB(slot)->C_Logout(rwsession); + slot->lastLoginCheck = 0; + PK11_RestoreROSession(slot,rwsession); + if (rv == SECSuccess) { + /* update our view of the world */ + PK11_InitToken(slot,PR_TRUE); + PK11_EnterSlotMonitor(slot); + PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, + (unsigned char *)userpw,len); + slot->lastLoginCheck = 0; + PK11_ExitSlotMonitor(slot); + } + return rv; +} + +/* + * Change an existing user password + */ +SECStatus +PK11_ChangePW(PK11SlotInfo *slot,char *oldpw, char *newpw) +{ + CK_RV crv; + SECStatus rv = SECFailure; + int newLen; + int oldLen; + CK_SESSION_HANDLE rwsession; + + if (newpw == NULL) newpw = ""; + if (oldpw == NULL) oldpw = ""; + newLen = PORT_Strlen(newpw); + oldLen = PORT_Strlen(oldpw); + + /* get a rwsession */ + rwsession = PK11_GetRWSession(slot); + + crv = PK11_GETTAB(slot)->C_SetPIN(rwsession, + (unsigned char *)oldpw,oldLen,(unsigned char *)newpw,newLen); + if (crv == CKR_OK) { + rv = SECSuccess; + } else { + PORT_SetError(PK11_MapError(crv)); + } + + PK11_RestoreROSession(slot,rwsession); + + /* update our view of the world */ + PK11_InitToken(slot,PR_TRUE); + return rv; +} + +static char * +pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void * wincx) +{ + if (PK11_Global.getPass == NULL) return NULL; + return (*PK11_Global.getPass)(slot, retry, wincx); +} + +void +PK11_SetPasswordFunc(PK11PasswordFunc func) +{ + PK11_Global.getPass = func; +} + +void +PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func) +{ + PK11_Global.verifyPass = func; +} + +void +PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func) +{ + PK11_Global.isLoggedIn = func; +} + + +/* + * authenticate to a slot. This loops until we can't recover, the user + * gives up, or we succeed. If we're already logged in and this function + * is called we will still prompt for a password, but we will probably + * succeed no matter what the password was (depending on the implementation + * of the PKCS 11 module. + */ +SECStatus +PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) +{ + SECStatus rv = SECFailure; + char * password; + PRBool attempt = PR_FALSE; + + if (PK11_NeedUserInit(slot)) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + + /* + * Central server type applications which control access to multiple + * slave applications to single crypto devices need to virtuallize the + * login state. This is done by a callback out of PK11_IsLoggedIn and + * here. If we are actually logged in, then we got here because the + * higher level code told us that the particular client application may + * still need to be logged in. If that is the case, we simply tell the + * server code that it should now verify the clients password and tell us + * the results. + */ + if (PK11_IsLoggedIn(slot,NULL) && + (PK11_Global.verifyPass != NULL)) { + if (!PK11_Global.verifyPass(slot,wincx)) { + PORT_SetError(SEC_ERROR_BAD_PASSWORD); + return SECFailure; + } + return SECSuccess; + } + + /* get the password. This can drop out of the while loop + * for the following reasons: + * (1) the user refused to enter a password. + * (return error to caller) + * (2) the token user password is disabled [usually due to + * too many failed authentication attempts]. + * (return error to caller) + * (3) the password was successful. + */ + while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) { + attempt = PR_TRUE; + rv = pk11_CheckPassword(slot,password); + PORT_Memset(password, 0, PORT_Strlen(password)); + PORT_Free(password); + if (rv != SECWouldBlock) break; + } + if (rv == SECSuccess) { + rv = pk11_CheckVerifyTest(slot); + if (!PK11_IsFriendly(slot)) { + nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain, + slot->nssToken); + } + } else if (!attempt) PORT_SetError(SEC_ERROR_BAD_PASSWORD); + return rv; +} + +void PK11_LogoutAll(void) +{ + SECMODListLock *lock = SECMOD_GetDefaultModuleListLock(); + SECMODModuleList *modList = SECMOD_GetDefaultModuleList(); + SECMODModuleList *mlp = NULL; + int i; + + SECMOD_GetReadLock(lock); + /* find the number of entries */ + for (mlp = modList; mlp != NULL; mlp = mlp->next) { + for (i=0; i < mlp->module->slotCount; i++) { + PK11_Logout(mlp->module->slots[i]); + } + } + + SECMOD_ReleaseReadLock(lock); +} + +int +PK11_GetMinimumPwdLength(PK11SlotInfo *slot) +{ + return ((int)slot->minPassword); +} + +/* Does this slot have a protected pin path? */ +PRBool +PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot) +{ + return slot->protectedAuthPath; +} + +/* + * we can initialize the password if 1) The toke is not inited + * (need login == true and see need UserInit) or 2) the token has + * a NULL password. (slot->needLogin = false & need user Init = false). + */ +PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot) +{ + if (slot->needLogin && PK11_NeedUserInit(slot)) { + return PR_TRUE; + } + if (!slot->needLogin && !PK11_NeedUserInit(slot)) { + return PR_TRUE; + } + return PR_FALSE; +} + +PRBool PK11_NeedPWInit() +{ + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PRBool ret = PK11_NeedPWInitForSlot(slot); + + PK11_FreeSlot(slot); + return ret; +} + +PRBool +pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime, + PRIntervalTime *retTime) +{ + PRIntervalTime time; + + *retTime = time = PR_IntervalNow(); + return (PRBool) (lastTime) && ((time-lastTime) < delayTime); +} + +/* + * Determine if the token is logged in. We have to actually query the token, + * because it's state can change without intervention from us. + */ +PRBool +PK11_IsLoggedIn(PK11SlotInfo *slot,void *wincx) +{ + CK_SESSION_INFO sessionInfo; + int askpw = slot->askpw; + int timeout = slot->timeout; + CK_RV crv; + PRIntervalTime curTime; + static PRIntervalTime login_delay_time = 0; + + if (login_delay_time == 0) { + login_delay_time = PR_SecondsToInterval(1); + } + + /* If we don't have our own password default values, use the system + * ones */ + if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { + PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); + + if (def_slot) { + askpw = def_slot->askpw; + timeout = def_slot->timeout; + PK11_FreeSlot(def_slot); + } + } + + if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) && + (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) { return PR_FALSE; } + + + /* forget the password if we've been inactive too long */ + if (askpw == 1) { + int64 currtime = PR_Now(); + int64 result; + int64 mult; + + LL_I2L(result, timeout); + LL_I2L(mult, 60*1000*1000); + LL_MUL(result,result,mult); + LL_ADD(result, result, slot->authTime); + if (LL_CMP(result, <, currtime) ) { + PK11_EnterSlotMonitor(slot); + PK11_GETTAB(slot)->C_Logout(slot->session); + slot->lastLoginCheck = 0; + PK11_ExitSlotMonitor(slot); + } else { + slot->authTime = currtime; + } + } + + PK11_EnterSlotMonitor(slot); + if (pk11_InDelayPeriod(slot->lastLoginCheck,login_delay_time, &curTime)) { + sessionInfo.state = slot->lastState; + crv = CKR_OK; + } else { + crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo); + if (crv == CKR_OK) { + slot->lastState = sessionInfo.state; + slot->lastLoginCheck = curTime; + } + } + PK11_ExitSlotMonitor(slot); + /* if we can't get session info, something is really wrong */ + if (crv != CKR_OK) { + slot->session = CK_INVALID_SESSION; + return PR_FALSE; + } + + switch (sessionInfo.state) { + case CKS_RW_PUBLIC_SESSION: + case CKS_RO_PUBLIC_SESSION: + default: + break; /* fail */ + case CKS_RW_USER_FUNCTIONS: + case CKS_RW_SO_FUNCTIONS: + case CKS_RO_USER_FUNCTIONS: + return PR_TRUE; + } + return PR_FALSE; +} diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c index 1d120ac4582..d5eaebba809 100644 --- a/security/nss/lib/pk11wrap/pk11cert.c +++ b/security/nss/lib/pk11wrap/pk11cert.c @@ -35,22 +35,20 @@ * * ***** END LICENSE BLOCK ***** */ /* - * This file implements the Symkey wrapper and the PKCS context - * Interfaces. + * This file manages PKCS #11 instances of certificates. */ #include "secport.h" #include "seccomon.h" #include "secmod.h" -#include "nssilock.h" #include "secmodi.h" +#include "secmodti.h" #include "pkcs11.h" #include "pk11func.h" #include "cert.h" #include "certi.h" #include "secitem.h" -#include "key.h" -#include "hasht.h" +#include "key.h" #include "secoid.h" #include "pkcs7t.h" #include "cmsreclist.h" @@ -73,12 +71,8 @@ #include "pkistore.h" /* to remove temp cert */ #include "devt.h" -#define PK11_SEARCH_CHUNKSIZE 10 - extern const NSSError NSS_ERROR_NOT_FOUND; - -CK_OBJECT_HANDLE -pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx); +extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; struct nss3_cert_cbstr { SECStatus(* callback)(CERTCertificate*, void *); @@ -100,18 +94,6 @@ static PRStatus convert_cert(NSSCertificate *c, void *arg) return (secrv) ? PR_FAILURE : PR_SUCCESS; } -void -PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst) -{ - sl->nssToken = nsst; -} - -NSSToken * -PK11Slot_GetNSSToken(PK11SlotInfo *sl) -{ - return sl->nssToken; -} - /* * build a cert nickname based on the token name and the label of the * certificate If the label in NULL, build a label based on the ID. @@ -168,155 +150,6 @@ pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label, return nickname; } -/* - * return the object handle that matches the template - */ -CK_OBJECT_HANDLE -pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize) -{ - CK_OBJECT_HANDLE object; - CK_RV crv; - CK_ULONG objectCount; - - /* - * issue the find - */ - PK11_EnterSlotMonitor(slot); - crv=PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, theTemplate, tsize); - if (crv != CKR_OK) { - PK11_ExitSlotMonitor(slot); - PORT_SetError( PK11_MapError(crv) ); - return CK_INVALID_HANDLE; - } - - crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount); - PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); - PK11_ExitSlotMonitor(slot); - if ((crv != CKR_OK) || (objectCount < 1)) { - /* shouldn't use SSL_ERROR... here */ - PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) : - SSL_ERROR_NO_CERTIFICATE); - return CK_INVALID_HANDLE; - } - - /* blow up if the PKCS #11 module returns us and invalid object handle */ - PORT_Assert(object != CK_INVALID_HANDLE); - return object; -} - -/* - * return all the object handles that matches the template - */ -CK_OBJECT_HANDLE * -pk11_FindObjectsByTemplate(PK11SlotInfo *slot, - CK_ATTRIBUTE *findTemplate,int findCount,int *object_count) { - CK_OBJECT_HANDLE *objID = NULL; - CK_ULONG returned_count = 0; - CK_RV crv; - - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, findTemplate, - findCount); - if (crv != CKR_OK) { - PK11_ExitSlotMonitor(slot); - PORT_SetError( PK11_MapError(crv) ); - *object_count = -1; - return NULL; - } - - - /* - * collect all the Matching Objects - */ - do { - CK_OBJECT_HANDLE *oldObjID = objID; - - if (objID == NULL) { - objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)* - (*object_count+ PK11_SEARCH_CHUNKSIZE)); - } else { - objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID, - sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE)); - } - - if (objID == NULL) { - if (oldObjID) PORT_Free(oldObjID); - break; - } - crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, - &objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - PORT_Free(objID); - objID = NULL; - break; - } - *object_count += returned_count; - } while (returned_count == PK11_SEARCH_CHUNKSIZE); - - PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); - PK11_ExitSlotMonitor(slot); - - if (objID && (*object_count == 0)) { - PORT_Free(objID); - return NULL; - } - if (objID == NULL) *object_count = -1; - return objID; -} -/* - * given a PKCS #11 object, match it's peer based on the KeyID. searchID - * is typically a privateKey or a certificate while the peer is the opposite - */ -CK_OBJECT_HANDLE -PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID, - CK_OBJECT_CLASS matchclass) -{ - CK_ATTRIBUTE theTemplate[] = { - { CKA_ID, NULL, 0 }, - { CKA_CLASS, NULL, 0 } - }; - /* if you change the array, change the variable below as well */ - CK_ATTRIBUTE *keyclass = &theTemplate[1]; - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); - /* if you change the array, change the variable below as well */ - CK_OBJECT_HANDLE peerID; - CK_OBJECT_HANDLE parent; - PRArenaPool *arena; - CK_RV crv; - - /* now we need to create space for the public key */ - arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) return CK_INVALID_HANDLE; - - crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize); - if (crv != CKR_OK) { - PORT_FreeArena(arena,PR_FALSE); - PORT_SetError( PK11_MapError(crv) ); - return CK_INVALID_HANDLE; - } - - if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) { - PORT_FreeArena(arena,PR_FALSE); - PORT_SetError(SEC_ERROR_BAD_KEY); - return CK_INVALID_HANDLE; - } - - - - /* - * issue the find - */ - parent = *(CK_OBJECT_CLASS *)(keyclass->pValue); - *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass; - - peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize); - PORT_FreeArena(arena,PR_FALSE); - - return peerID; -} - PRBool PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert, CK_OBJECT_HANDLE certID) @@ -470,115 +303,6 @@ static CERTCertificate return STAN_GetCERTCertificate(c); } -CK_TRUST -pk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena, - CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type) -{ - CK_TRUST rv = 0; - SECItem item; - - item.data = NULL; - item.len = 0; - - if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) { - PORT_Assert(item.len == sizeof(CK_TRUST)); - PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST)); - /* Damn, is there an endian problem here? */ - return rv; - } - - return 0; -} - -PRBool -pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust) -{ - PRArenaPool *arena; - - CK_ATTRIBUTE tobjTemplate[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_CERT_SHA1_HASH, NULL, 0 }, - }; - - CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; - CK_OBJECT_HANDLE tobjID; - unsigned char sha1_hash[SHA1_LENGTH]; - - CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth; - - PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len); - - PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc)); - PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, - SHA1_LENGTH); - - tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, - sizeof(tobjTemplate)/sizeof(tobjTemplate[0])); - if( CK_INVALID_HANDLE == tobjID ) { - return PR_FALSE; - } - - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if( NULL == arena ) return PR_FALSE; - - /* Unfortunately, it seems that PK11_GetAttributes doesn't deal - * well with nonexistant attributes. I guess we have to check - * the trust info fields one at a time. - */ - - /* We could verify CKA_CERT_HASH here */ - - /* We could verify CKA_EXPIRES here */ - - - /* "Purpose" trust information */ - serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH); - clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH); - codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING); - emailProtection = pk11_GetTrustField(slot, arena, tobjID, - CKA_TRUST_EMAIL_PROTECTION); - /* Here's where the fun logic happens. We have to map back from the - * key usage, extended key usage, purpose, and possibly other trust values - * into the old trust-flags bits. */ - - /* First implementation: keep it simple for testing. We can study what other - * mappings would be appropriate and add them later.. fgmr 20000724 */ - - if ( serverAuth == CKT_NETSCAPE_TRUSTED ) { - trust->sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; - } - - if ( serverAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { - trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | - CERTDB_NS_TRUSTED_CA; - } - if ( clientAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { - trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA ; - } - - if ( emailProtection == CKT_NETSCAPE_TRUSTED ) { - trust->emailFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; - } - - if ( emailProtection == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { - trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; - } - - if( codeSigning == CKT_NETSCAPE_TRUSTED ) { - trust->objectSigningFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; - } - - if( codeSigning == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { - trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; - } - - /* There's certainly a lot more logic that can go here.. */ - - PORT_FreeArena(arena, PR_FALSE); - - return PR_TRUE; -} - /* * Build an CERTCertificate structure from a PKCS#11 object ID.... certID * Must be a CertObject. This code does not explicitly checks that. @@ -694,45 +418,6 @@ PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey) } -/* - * destroy a private key if there are no matching certs. - * this function also frees the privKey structure. - */ -SECStatus -PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force) -{ - CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey); - - /* found a cert matching the private key?. */ - if (!force && cert != NULL) { - /* yes, don't delete the key */ - CERT_DestroyCertificate(cert); - SECKEY_DestroyPrivateKey(privKey); - return SECWouldBlock; - } - /* now, then it's safe for the key to go away */ - PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID); - SECKEY_DestroyPrivateKey(privKey); - return SECSuccess; -} - -/* - * destroy a private key if there are no matching certs. - * this function also frees the privKey structure. - */ -SECStatus -PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey) -{ - /* now, then it's safe for the key to go away */ - if (pubKey->pkcs11Slot == NULL) { - return SECFailure; - } - PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID); - SECKEY_DestroyPublicKey(pubKey); - return SECSuccess; -} - - /* * delete a cert and it's private key (if no other certs are pointing to the * private key. @@ -761,45 +446,6 @@ PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx) return SECSuccess; } -/* - * count the number of objects that match the template. - */ -int -PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, - int templateCount) -{ - CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE]; - int object_count = 0; - CK_ULONG returned_count = 0; - CK_RV crv; - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, - findTemplate, templateCount); - if (crv != CKR_OK) { - PK11_ExitSlotMonitor(slot); - PORT_SetError( PK11_MapError(crv) ); - return 0; - } - - /* - * collect all the Matching Objects - */ - do { - crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, - objID,PK11_SEARCH_CHUNKSIZE,&returned_count); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - break; - } - object_count += returned_count; - } while (returned_count == PK11_SEARCH_CHUNKSIZE); - - PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); - PK11_ExitSlotMonitor(slot); - return object_count; -} - /* * cert callback structure */ @@ -844,198 +490,11 @@ pk11_DoCerts(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, void *arg) } #endif -static SECStatus -pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg) -{ - SECItem derCrl; - CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg; - CERTCrlNode *new_node = NULL; - CK_ATTRIBUTE fetchCrl[3] = { - { CKA_VALUE, NULL, 0}, - { CKA_NETSCAPE_KRL, NULL, 0}, - { CKA_NETSCAPE_URL, NULL, 0}, - }; - const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); - CK_RV crv; - SECStatus rv = SECFailure; - - crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize); - if (CKR_OK != crv) { - PORT_SetError(PK11_MapError(crv)); - goto loser; - } - - if (!fetchCrl[1].pValue) { - PORT_SetError(SEC_ERROR_CRL_INVALID); - goto loser; - } - - new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode)); - if (new_node == NULL) { - goto loser; - } - - if (*((CK_BBOOL *)fetchCrl[1].pValue)) - new_node->type = SEC_KRL_TYPE; - else - new_node->type = SEC_CRL_TYPE; - - derCrl.type = siBuffer; - derCrl.data = (unsigned char *)fetchCrl[0].pValue; - derCrl.len = fetchCrl[0].ulValueLen; - new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type); - if (new_node->crl == NULL) { - goto loser; - } - - if (fetchCrl[2].pValue) { - int nnlen = fetchCrl[2].ulValueLen; - new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen+1); - if ( !new_node->crl->url ) { - goto loser; - } - PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); - new_node->crl->url[nnlen] = 0; - } else { - new_node->crl->url = NULL; - } - - - new_node->next = NULL; - if (head->last) { - head->last->next = new_node; - head->last = new_node; - } else { - head->first = head->last = new_node; - } - rv = SECSuccess; - -loser: - return(rv); -} - - -/* - * key call back structure. - */ -typedef struct pk11KeyCallbackStr { - SECStatus (* callback)(SECKEYPrivateKey *,void *); - void *callbackArg; - void *wincx; -} pk11KeyCallback; - -/* - * callback to map Object Handles to Private Keys; - */ -SECStatus -pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg) -{ - SECStatus rv = SECSuccess; - SECKEYPrivateKey *privKey; - pk11KeyCallback *keycb = (pk11KeyCallback *) arg; - - privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx); - - if (privKey == NULL) { - return SECFailure; - } - - if (keycb && (keycb->callback)) { - rv = (*keycb->callback)(privKey,keycb->callbackArg); - } - - SECKEY_DestroyPrivateKey(privKey); - return rv; -} - -/* Traverse slots callback */ -typedef struct pk11TraverseSlotStr { - SECStatus (*callback)(PK11SlotInfo *,CK_OBJECT_HANDLE, void *); - void *callbackArg; - CK_ATTRIBUTE *findTemplate; - int templateCount; -} pk11TraverseSlot; - -/* - * Extract all the certs on a card from a slot. - */ -SECStatus -PK11_TraverseSlot(PK11SlotInfo *slot, void *arg) -{ - int i; - CK_OBJECT_HANDLE *objID = NULL; - int object_count = 0; - pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg; - - objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate, - slotcb->templateCount,&object_count); - - /*Actually this isn't a failure... there just were no objs to be found*/ - if (object_count == 0) { - return SECSuccess; - } - - if (objID == NULL) { - return SECFailure; - } - - for (i=0; i < object_count; i++) { - (*slotcb->callback)(slot,objID[i],slotcb->callbackArg); - } - PORT_Free(objID); - return SECSuccess; -} - typedef struct pk11CertCallbackStr { SECStatus(* callback)(CERTCertificate*,SECItem *,void *); void *callbackArg; } pk11CertCallback; - -/* - * Authenticate to "unfriendly" tokens (tokens which need to be logged - * in to find the certs. - */ -static SECStatus -pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) -{ - SECStatus rv = SECSuccess; - if (!PK11_IsFriendly(slot)) { - rv = PK11_Authenticate(slot, loadCerts, wincx); - } - return rv; -} - -/* - * Extract all the certs on a card from a slot. - */ -SECStatus -pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), - void *arg,void *wincx) { - PK11SlotList *list; - PK11SlotListElement *le; - SECStatus rv; - - /* get them all! */ - list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx); - if (list == NULL) return SECFailure; - - /* look at each slot and authenticate as necessary */ - for (le = list->head ; le; le = le->next) { - rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx); - if (rv != SECSuccess) { - continue; - } - if (callback) { - (*callback)(le->slot,arg); - } - } - - PK11_FreeSlotList(list); - - return SECSuccess; -} - struct fake_der_cb_argstr { SECStatus(* callback)(CERTCertificate*, SECItem *, void *); @@ -1089,147 +548,6 @@ PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *), #endif } -/* - * Extract all the certs on a card from a slot. - */ -SECStatus -PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) { - pk11TraverseSlot creater; - CK_ATTRIBUTE theTemplate[2]; - CK_ATTRIBUTE *attrs; - CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL; - - attrs = theTemplate; - PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++; - if (type != -1) { - CK_BBOOL isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); - PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++; - } - - creater.callback = pk11_CollectCrls; - creater.callbackArg = (void *) nodes; - creater.findTemplate = theTemplate; - creater.templateCount = (attrs - theTemplate); - - return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, wincx); -} - -/*********************************************************************** - * PK11_TraversePrivateKeysInSlot - * - * Traverses all the private keys on a slot. - * - * INPUTS - * slot - * The PKCS #11 slot whose private keys you want to traverse. - * callback - * A callback function that will be called for each key. - * arg - * An argument that will be passed to the callback function. - */ -SECStatus -PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, - SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg) -{ - pk11KeyCallback perKeyCB; - pk11TraverseSlot perObjectCB; - CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY; - CK_BBOOL ckTrue = CK_TRUE; - CK_ATTRIBUTE theTemplate[2]; - int templateSize = 2; - - theTemplate[0].type = CKA_CLASS; - theTemplate[0].pValue = &privkClass; - theTemplate[0].ulValueLen = sizeof(privkClass); - theTemplate[1].type = CKA_TOKEN; - theTemplate[1].pValue = &ckTrue; - theTemplate[1].ulValueLen = sizeof(ckTrue); - - if(slot==NULL) { - return SECSuccess; - } - - perObjectCB.callback = pk11_DoKeys; - perObjectCB.callbackArg = &perKeyCB; - perObjectCB.findTemplate = theTemplate; - perObjectCB.templateCount = templateSize; - perKeyCB.callback = callback; - perKeyCB.callbackArg = arg; - perKeyCB.wincx = NULL; - - return PK11_TraverseSlot(slot, &perObjectCB); -} - -CK_OBJECT_HANDLE * -PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr, - CK_OBJECT_CLASS objclass, int *returnCount, void *wincx) -{ - char *tokenName; - char *delimit; - PK11SlotInfo *slot; - CK_OBJECT_HANDLE *objID; - CK_ATTRIBUTE findTemplate[] = { - { CKA_LABEL, NULL, 0}, - { CKA_CLASS, NULL, 0}, - }; - int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]); - SECStatus rv; - PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass)); - - *slotptr = slot = NULL; - *returnCount = 0; - /* first find the slot associated with this nickname */ - if ((delimit = PORT_Strchr(nickname,':')) != NULL) { - int len = delimit - nickname; - tokenName = (char*)PORT_Alloc(len+1); - PORT_Memcpy(tokenName,nickname,len); - tokenName[len] = 0; - - slot = *slotptr = PK11_FindSlotByName(tokenName); - PORT_Free(tokenName); - /* if we couldn't find a slot, assume the nickname is an internal cert - * with no proceding slot name */ - if (slot == NULL) { - slot = *slotptr = PK11_GetInternalKeySlot(); - } else { - nickname = delimit+1; - } - } else { - *slotptr = slot = PK11_GetInternalKeySlot(); - } - if (slot == NULL) { - return CK_INVALID_HANDLE; - } - - rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); - if (rv != SECSuccess) { - PK11_FreeSlot(slot); - *slotptr = NULL; - return CK_INVALID_HANDLE; - } - - findTemplate[0].pValue = nickname; - findTemplate[0].ulValueLen = PORT_Strlen(nickname); - objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount); - if (objID == NULL) { - /* PKCS #11 isn't clear on whether or not the NULL is - * stored in the template.... try the find again with the - * full null terminated string. */ - findTemplate[0].ulValueLen += 1; - objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount, - returnCount); - if (objID == NULL) { - /* Well that's the best we can do. It's just not here */ - /* what about faked nicknames? */ - PK11_FreeSlot(slot); - *slotptr = NULL; - *returnCount = 0; - } - } - - return objID; -} - static void transfer_token_certs_to_collection(nssList *certList, NSSToken *token, nssPKIObjectCollection *collection) @@ -1562,59 +880,6 @@ pk11_mkcertKeyID(CERTCertificate *cert) { return certCKA_ID; } - -/* - * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated - * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make - * smart cards happy. - */ -SECItem * -PK11_MakeIDFromPubKey(SECItem *pubKeyData) { - PK11Context *context; - SECItem *certCKA_ID; - SECStatus rv; - - context = PK11_CreateDigestContext(SEC_OID_SHA1); - if (context == NULL) { - return NULL; - } - - rv = PK11_DigestBegin(context); - if (rv == SECSuccess) { - rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len); - } - if (rv != SECSuccess) { - PK11_DestroyContext(context,PR_TRUE); - return NULL; - } - - certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem)); - if (certCKA_ID == NULL) { - PK11_DestroyContext(context,PR_TRUE); - return NULL; - } - - certCKA_ID->len = SHA1_LENGTH; - certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len); - if (certCKA_ID->data == NULL) { - PORT_Free(certCKA_ID); - PK11_DestroyContext(context,PR_TRUE); - return NULL; - } - - rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len, - SHA1_LENGTH); - PK11_DestroyContext(context,PR_TRUE); - if (rv != SECSuccess) { - SECITEM_FreeItem(certCKA_ID,PR_TRUE); - return NULL; - } - - return certCKA_ID; -} - -extern const NSSError NSS_ERROR_INVALID_CERTIFICATE; - /* * Write the cert into the token. */ @@ -1951,27 +1216,6 @@ PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert, return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx); } - -/* - * return the private key with the given ID - */ -static CK_OBJECT_HANDLE -pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID) { - CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; - CK_ATTRIBUTE theTemplate[] = { - { CKA_ID, NULL, 0 }, - { CKA_CLASS, NULL, 0 }, - }; - /* if you change the array, change the variable below as well */ - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); - CK_ATTRIBUTE *attrs = theTemplate; - - PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++; - PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey)); - - return pk11_FindObjectByTemplate(slot,theTemplate,tsize); -} - /* * import a cert for a private key we have already generated. Set the label * on both to be the nickname. This is for the Key Gen, orphaned key case. @@ -2362,7 +1606,6 @@ PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr, SECKEYPrivateKey**privKey, void *wincx) { CERTCertificate *cert = NULL; - SECStatus rv; *privKey = NULL; *slotPtr = NULL; @@ -2620,20 +1863,6 @@ pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx return keyHandle; } -SECKEYPrivateKey * -PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx) -{ - CK_OBJECT_HANDLE keyHandle; - SECKEYPrivateKey *privKey; - - keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID); - if (keyHandle == CK_INVALID_HANDLE) { - return NULL; - } - privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); - return privKey; -} - /* * find the number of certs in the slot with the same subject name */ @@ -3239,22 +2468,6 @@ PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2, return SECFailure; } -SECOidTag -PK11_FortezzaMapSig(SECOidTag algTag) -{ - switch (algTag) { - case SEC_OID_MISSI_KEA_DSS: - case SEC_OID_MISSI_DSS: - case SEC_OID_MISSI_DSS_OLD: - case SEC_OID_MISSI_KEA_DSS_OLD: - case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: - return SEC_OID_ANSIX9_DSA_SIGNATURE; - default: - break; - } - return algTag; -} - /* * return the private key From a given Cert */ @@ -3320,33 +2533,6 @@ loser: return item; } -SECItem * -PK11_GetKeyIDFromPrivateKey(SECKEYPrivateKey *key, void *wincx) -{ - CK_ATTRIBUTE theTemplate[] = { - { CKA_ID, NULL, 0 }, - }; - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); - SECItem *item = NULL; - CK_RV crv; - - crv = PK11_GetAttributes(NULL,key->pkcs11Slot,key->pkcs11ID, - theTemplate,tsize); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - goto loser; - } - - item = PORT_ZNew(SECItem); - if (item) { - item->data = (unsigned char*) theTemplate[0].pValue; - item->len = theTemplate[0].ulValueLen; - } - -loser: - return item; -} - struct listCertsStr { PK11CertListType type; CERTCertList *certList; @@ -3471,34 +2657,6 @@ PK11_ListCerts(PK11CertListType type, void *pwarg) return certList; #endif } - -static SECItem * -pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) { - CK_ATTRIBUTE theTemplate[] = { - { CKA_ID, NULL, 0 }, - }; - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); - CK_RV crv; - SECItem *item; - - item = SECITEM_AllocItem(NULL, NULL, 0); - - if (item == NULL) { - return NULL; - } - - crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize); - if (crv != CKR_OK) { - SECITEM_FreeItem(item,PR_TRUE); - PORT_SetError( PK11_MapError(crv) ); - return NULL; - } - - item->data = (unsigned char*) theTemplate[0].pValue; - item->len =theTemplate[0].ulValueLen; - - return item; -} SECItem * PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot, @@ -3542,12 +2700,6 @@ PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot, return item; } -SECItem * -PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey) -{ - return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID); -} - /* argument type for listCertsCallback */ typedef struct { CERTCertList *list; @@ -3608,643 +2760,3 @@ PK11_ListCertsInSlot(PK11SlotInfo *slot) return certs; } -static SECStatus -privateKeyListCallback(SECKEYPrivateKey *key, void *arg) -{ - SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg; - return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key)); -} - -SECKEYPrivateKeyList* -PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot) -{ - SECStatus status; - SECKEYPrivateKeyList *keys; - - keys = SECKEY_NewPrivateKeyList(); - if(keys == NULL) return NULL; - - status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback, - (void*)keys); - - if( status != SECSuccess ) { - SECKEY_DestroyPrivateKeyList(keys); - keys = NULL; - } - - return keys; -} - -SECKEYPublicKeyList* -PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname) -{ - CK_ATTRIBUTE findTemp[4]; - CK_ATTRIBUTE *attrs; - CK_BBOOL ckTrue = CK_TRUE; - CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY; - int tsize = 0; - int objCount = 0; - CK_OBJECT_HANDLE *key_ids; - SECKEYPublicKeyList *keys; - int i,len; - - - attrs = findTemp; - PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; - PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; - if (nickname) { - len = PORT_Strlen(nickname)-1; - PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; - } - tsize = attrs - findTemp; - PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); - - key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); - if (key_ids == NULL) { - return NULL; - } - keys = SECKEY_NewPublicKeyList(); - if (keys == NULL) { - PORT_Free(key_ids); - } - - for (i=0; i < objCount ; i++) { - SECKEYPublicKey *pubKey = - PK11_ExtractPublicKey(slot,nullKey,key_ids[i]); - if (pubKey) { - SECKEY_AddPublicKeyToListTail(keys, pubKey); - } - } - - PORT_Free(key_ids); - return keys; -} - -SECKEYPrivateKeyList* -PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx) -{ - CK_ATTRIBUTE findTemp[4]; - CK_ATTRIBUTE *attrs; - CK_BBOOL ckTrue = CK_TRUE; - CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; - int tsize = 0; - int objCount = 0; - CK_OBJECT_HANDLE *key_ids; - SECKEYPrivateKeyList *keys; - int i,len; - - - attrs = findTemp; - PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; - PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; - if (nickname) { - len = PORT_Strlen(nickname)-1; - PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; - } - tsize = attrs - findTemp; - PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); - - key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); - if (key_ids == NULL) { - return NULL; - } - keys = SECKEY_NewPrivateKeyList(); - if (keys == NULL) { - PORT_Free(key_ids); - } - - for (i=0; i < objCount ; i++) { - SECKEYPrivateKey *privKey = - PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx); - SECKEY_AddPrivateKeyToListTail(keys, privKey); - } - - PORT_Free(key_ids); - return keys; -} - -/* - * return the certificate associated with a derCert - */ -SECItem * -PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle, - SECItem *name, int type, char **url) -{ -#ifdef NSS_CLASSIC - CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; - CK_ATTRIBUTE theTemplate[] = { - { CKA_SUBJECT, NULL, 0 }, - { CKA_CLASS, NULL, 0 }, - { CKA_NETSCAPE_KRL, NULL, 0 }, - }; - CK_ATTRIBUTE crlData[] = { - { CKA_VALUE, NULL, 0 }, - { CKA_NETSCAPE_URL, NULL, 0 }, - }; - /* if you change the array, change the variable below as well */ - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); - CK_BBOOL ck_true = CK_TRUE; - CK_BBOOL ck_false = CK_FALSE; - CK_OBJECT_HANDLE crlh = CK_INVALID_HANDLE; - CK_ATTRIBUTE *attrs = theTemplate; - CK_RV crv; - SECItem *derCrl = NULL; - - PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; - PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; - PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, (type == SEC_CRL_TYPE) ? - &ck_false : &ck_true, sizeof (CK_BBOOL)); attrs++; - - if (*slot) { - crlh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); - } else { - PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, - PR_FALSE,PR_TRUE,NULL); - PK11SlotListElement *le; - - /* loop through all the fortezza tokens */ - for (le = list->head; le; le = le->next) { - crlh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); - if (crlh != CK_INVALID_HANDLE) { - *slot = PK11_ReferenceSlot(le->slot); - break; - } - } - PK11_FreeSlotList(list); - } - - if (crlh == CK_INVALID_HANDLE) { - PORT_SetError(SEC_ERROR_NO_KRL); - return NULL; - } - crv = PK11_GetAttributes(NULL,*slot,crlh,crlData,2); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError (crv)); - goto loser; - } - - derCrl = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if (derCrl == NULL) { - goto loser; - } - - derCrl->data = crlData[0].pValue; - derCrl->len = crlData[0].ulValueLen; - - if (crlHandle) { - *crlHandle = crlh; - } - - if ((url) && crlData[1].ulValueLen != 0) { - /* make sure it's a null terminated string */ - *url = PORT_ZAlloc (crlData[1].ulValueLen+1); - if (*url) { - PORT_Memcpy(*url,crlData[1].pValue,crlData[1].ulValueLen); - } - } - - -loser: - if (!derCrl) { - if (crlData[0].pValue) PORT_Free(crlData[0].pValue); - } - if (crlData[1].pValue) PORT_Free(crlData[1].pValue); - return derCrl; -#else - NSSCRL **crls, **crlp, *crl; - NSSDER subject; - SECItem *rvItem; - NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); - NSSITEM_FROM_SECITEM(&subject, name); - if (*slot) { - nssCryptokiObject **instances; - nssPKIObjectCollection *collection; - nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; - NSSToken *token = PK11Slot_GetNSSToken(*slot); - collection = nssCRLCollection_Create(td, NULL); - if (!collection) { - return NULL; - } - instances = nssToken_FindCRLsBySubject(token, NULL, &subject, - tokenOnly, 0, NULL); - nssPKIObjectCollection_AddInstances(collection, instances, 0); - nss_ZFreeIf(instances); - crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL); - nssPKIObjectCollection_Destroy(collection); - } else { - crls = nssTrustDomain_FindCRLsBySubject(td, &subject); - } - if ((!crls) || (*crls == NULL)) { - if (crls) { - nssCRLArray_Destroy(crls); - } - if (NSS_GetError() == NSS_ERROR_NOT_FOUND) { - PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); - } - return NULL; - } - crl = NULL; - for (crlp = crls; *crlp; crlp++) { - if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) || - ((*crlp)->isKRL && type != SEC_CRL_TYPE)) - { - crl = nssCRL_AddRef(*crlp); - break; - } - } - nssCRLArray_Destroy(crls); - if (!crl) { - /* CRL collection was found, but no interesting CRL's were on it. - * Not an error */ - PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); - return NULL; - } - if (crl->url) { - *url = PORT_Strdup(crl->url); - if (!*url) { - nssCRL_Destroy(crl); - return NULL; - } - } else { - *url = NULL; - } - rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size); - if (!rvItem) { - PORT_Free(*url); - nssCRL_Destroy(crl); - return NULL; - } - memcpy(rvItem->data, crl->encoding.data, crl->encoding.size); - *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot); - *crlHandle = crl->object.instances[0]->handle; - nssCRL_Destroy(crl); - return rvItem; -#endif -} - -CK_OBJECT_HANDLE -PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name, - char *url, int type) -{ -#ifdef NSS_CLASSIC - CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; - CK_ATTRIBUTE theTemplate[] = { - { CKA_SUBJECT, NULL, 0 }, - { CKA_CLASS, NULL, 0 }, - { CKA_NETSCAPE_KRL, NULL, 0 }, - { CKA_NETSCAPE_URL, NULL, 0 }, - { CKA_VALUE, NULL, 0 }, - { CKA_TOKEN, NULL, 0 } - }; - /* if you change the array, change the variable below as well */ - int tsize; - CK_BBOOL ck_true = CK_TRUE; - CK_BBOOL ck_false = CK_FALSE; - CK_OBJECT_HANDLE crlh = CK_INVALID_HANDLE; - CK_ATTRIBUTE *attrs = theTemplate; - CK_SESSION_HANDLE rwsession; - CK_RV crv; - - PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; - PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; - PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, (type == SEC_CRL_TYPE) ? - &ck_false : &ck_true, sizeof (CK_BBOOL)); attrs++; - if (url) { - PK11_SETATTRS(attrs, CKA_NETSCAPE_URL, url, PORT_Strlen(url)+1); attrs++; - } - PK11_SETATTRS(attrs, CKA_VALUE,crl->data,crl->len); attrs++; - PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true,sizeof(CK_BBOOL)); attrs++; - - tsize = attrs - &theTemplate[0]; - PORT_Assert(tsize <= sizeof(theTemplate)/sizeof(theTemplate[0])); - - rwsession = PK11_GetRWSession(slot); - if (rwsession == CK_INVALID_SESSION) { - PORT_SetError(SEC_ERROR_READ_ONLY); - return crlh; - } - - crv = PK11_GETTAB(slot)-> - C_CreateObject(rwsession,theTemplate,tsize,&crlh); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - } - - PK11_RestoreROSession(slot,rwsession); - - return crlh; -#else - NSSItem derCRL, derSubject; - NSSToken *token = PK11Slot_GetNSSToken(slot); - nssCryptokiObject *object; - PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE; - CK_OBJECT_HANDLE rvH; - - NSSITEM_FROM_SECITEM(&derSubject, name); - NSSITEM_FROM_SECITEM(&derCRL, crl); - - object = nssToken_ImportCRL(token, NULL, - &derSubject, &derCRL, isKRL, url, PR_TRUE); - - if (object) { - rvH = object->handle; - nssCryptokiObject_Destroy(object); - } else { - rvH = CK_INVALID_HANDLE; - } - return rvH; -#endif -} - - -/* - * delete a crl. - */ -SECStatus -SEC_DeletePermCRL(CERTSignedCrl *crl) -{ -#ifdef NSS_CLASSIC - PK11SlotInfo *slot = crl->slot; - CK_RV crv; - - if (slot == NULL) { - /* shouldn't happen */ - PORT_SetError( SEC_ERROR_CRL_INVALID); - return SECFailure; - } - - crv = PK11_DestroyTokenObject(slot,crl->pkcs11ID); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - crl->slot = NULL; - PK11_FreeSlot(slot); - return SECSuccess; -#else - PRStatus status; - NSSToken *token; - nssCryptokiObject *object; - PK11SlotInfo *slot = crl->slot; - - if (slot == NULL) { - PORT_Assert(slot); - /* shouldn't happen */ - PORT_SetError( SEC_ERROR_CRL_INVALID); - return SECFailure; - } - token = PK11Slot_GetNSSToken(slot); - - object = nss_ZNEW(NULL, nssCryptokiObject); - object->token = nssToken_AddRef(token); - object->handle = crl->pkcs11ID; - object->isTokenObject = PR_TRUE; - - status = nssToken_DeleteStoredObject(object); - - nssCryptokiObject_Destroy(object); - return (status == PR_SUCCESS) ? SECSuccess : SECFailure; -#endif -} - -/* - * return the certificate associated with a derCert - */ -SECItem * -PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr, - SECItem *name, SECItem **profileTime) -{ - CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; - CK_ATTRIBUTE theTemplate[] = { - { CKA_SUBJECT, NULL, 0 }, - { CKA_CLASS, NULL, 0 }, - { CKA_NETSCAPE_EMAIL, NULL, 0 }, - }; - CK_ATTRIBUTE smimeData[] = { - { CKA_SUBJECT, NULL, 0 }, - { CKA_VALUE, NULL, 0 }, - }; - /* if you change the array, change the variable below as well */ - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); - CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; - CK_ATTRIBUTE *attrs = theTemplate; - CK_RV crv; - SECItem *emailProfile = NULL; - - PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; - PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; - PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); - attrs++; - - if (*slot) { - smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); - } else { - PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, - PR_FALSE,PR_TRUE,NULL); - PK11SlotListElement *le; - - /* loop through all the fortezza tokens */ - for (le = list->head; le; le = le->next) { - smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); - if (smimeh != CK_INVALID_HANDLE) { - *slot = PK11_ReferenceSlot(le->slot); - break; - } - } - PK11_FreeSlotList(list); - } - - if (smimeh == CK_INVALID_HANDLE) { - PORT_SetError(SEC_ERROR_NO_KRL); - return NULL; - } - - if (profileTime) { - PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0); - } - - crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError (crv)); - goto loser; - } - - if (!profileTime) { - SECItem profileSubject; - - profileSubject.data = (unsigned char*) smimeData[0].pValue; - profileSubject.len = smimeData[0].ulValueLen; - if (!SECITEM_ItemsAreEqual(&profileSubject,name)) { - goto loser; - } - } - - emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if (emailProfile == NULL) { - goto loser; - } - - emailProfile->data = (unsigned char*) smimeData[1].pValue; - emailProfile->len = smimeData[1].ulValueLen; - - if (profileTime) { - *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); - if (*profileTime) { - (*profileTime)->data = (unsigned char*) smimeData[0].pValue; - (*profileTime)->len = smimeData[0].ulValueLen; - } - } - -loser: - if (emailProfile == NULL) { - if (smimeData[1].pValue) { - PORT_Free(smimeData[1].pValue); - } - } - if (profileTime == NULL || *profileTime == NULL) { - if (smimeData[0].pValue) { - PORT_Free(smimeData[0].pValue); - } - } - return emailProfile; -} - - -SECStatus -PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, - SECItem *emailProfile, SECItem *profileTime) -{ - CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; - CK_BBOOL ck_true = CK_TRUE; - CK_ATTRIBUTE theTemplate[] = { - { CKA_CLASS, NULL, 0 }, - { CKA_TOKEN, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 }, - { CKA_NETSCAPE_EMAIL, NULL, 0 }, - { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - /* if you change the array, change the variable below as well */ - int realSize = 0; - CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; - CK_ATTRIBUTE *attrs = theTemplate; - CK_SESSION_HANDLE rwsession; - PK11SlotInfo *free_slot = NULL; - CK_RV crv; -#ifdef DEBUG - int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); -#endif - - PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; - PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++; - PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++; - PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, - emailAddr, PORT_Strlen(emailAddr)+1); attrs++; - if (profileTime) { - PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data, - profileTime->len); attrs++; - PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data, - emailProfile->len); attrs++; - } - realSize = attrs - theTemplate; - PORT_Assert (realSize <= tsize); - - if (slot == NULL) { - free_slot = slot = PK11_GetInternalKeySlot(); - /* we need to free the key slot in the end!!! */ - } - - rwsession = PK11_GetRWSession(slot); - if (rwsession == CK_INVALID_SESSION) { - PORT_SetError(SEC_ERROR_READ_ONLY); - if (free_slot) { - PK11_FreeSlot(free_slot); - } - return SECFailure; - } - - crv = PK11_GETTAB(slot)-> - C_CreateObject(rwsession,theTemplate,realSize,&smimeh); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - } - - PK11_RestoreROSession(slot,rwsession); - - if (free_slot) { - PK11_FreeSlot(free_slot); - } - return SECSuccess; -} - - -CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url, - CERTSignedCrl *newCrl, SECItem *derCrl, int type); - -/* import the CRL into the token */ - -CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, - int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena, - PRInt32 decodeoptions) -{ - CERTSignedCrl *newCrl, *crl; - SECStatus rv; - CERTCertificate *caCert = NULL; - - newCrl = crl = NULL; - - do { - newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type, - decodeoptions); - if (newCrl == NULL) { - if (type == SEC_CRL_TYPE) { - /* only promote error when the error code is too generic */ - if (PORT_GetError () == SEC_ERROR_BAD_DER) - PORT_SetError(SEC_ERROR_CRL_INVALID); - } else { - PORT_SetError(SEC_ERROR_KRL_INVALID); - } - break; - } - - if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){ - CERTCertDBHandle* handle = CERT_GetDefaultCertDB(); - PR_ASSERT(handle != NULL); - caCert = CERT_FindCertByName (handle, - &newCrl->crl.derName); - if (caCert == NULL) { - PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); - break; - } - - /* If caCert is a v3 certificate, make sure that it can be used for - crl signing purpose */ - rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN); - if (rv != SECSuccess) { - break; - } - - rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert, - PR_Now(), wincx); - if (rv != SECSuccess) { - if (type == SEC_CRL_TYPE) { - PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE); - } else { - PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE); - } - break; - } - } - - crl = crl_storeCRL(slot, url, newCrl, derCRL, type); - - } while (0); - - if (crl == NULL) { - SEC_DestroyCrl (newCrl); - } - if (caCert) { - CERT_DestroyCertificate(caCert); - } - return (crl); -} diff --git a/security/nss/lib/pk11wrap/pk11cxt.c b/security/nss/lib/pk11wrap/pk11cxt.c new file mode 100644 index 00000000000..f0c41d052f0 --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11cxt.c @@ -0,0 +1,1051 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file PK11Contexts which are used in multipart hashing, + * encryption/decryption, and signing/verication operations. + */ + +#include "seccomon.h" +#include "secmod.h" +#include "nssilock.h" +#include "secmodi.h" +#include "secmodti.h" +#include "pkcs11.h" +#include "pk11func.h" +#include "secitem.h" +#include "secoid.h" +#include "sechash.h" +#include "secerr.h" + +static const SECItem pk11_null_params = { 0 }; + +/********************************************************************** + * + * Now Deal with Crypto Contexts + * + **********************************************************************/ + +/* + * the monitors... + */ +void +PK11_EnterContextMonitor(PK11Context *cx) { + /* if we own the session and our slot is ThreadSafe, only monitor + * the Context */ + if ((cx->ownSession) && (cx->slot->isThreadSafe)) { + /* Should this use monitors instead? */ + PZ_Lock(cx->sessionLock); + } else { + PK11_EnterSlotMonitor(cx->slot); + } +} + +void +PK11_ExitContextMonitor(PK11Context *cx) { + /* if we own the session and our slot is ThreadSafe, only monitor + * the Context */ + if ((cx->ownSession) && (cx->slot->isThreadSafe)) { + /* Should this use monitors instead? */ + PZ_Unlock(cx->sessionLock); + } else { + PK11_ExitSlotMonitor(cx->slot); + } +} + +/* + * Free up a Cipher Context + */ +void +PK11_DestroyContext(PK11Context *context, PRBool freeit) +{ + pk11_CloseSession(context->slot,context->session,context->ownSession); + /* initialize the critical fields of the context */ + if (context->savedData != NULL ) PORT_Free(context->savedData); + if (context->key) PK11_FreeSymKey(context->key); + if (context->param && context->param != &pk11_null_params) + SECITEM_FreeItem(context->param, PR_TRUE); + if (context->sessionLock) PZ_DestroyLock(context->sessionLock); + PK11_FreeSlot(context->slot); + if (freeit) PORT_Free(context); +} + +/* + * save the current context. Allocate Space if necessary. + */ +static unsigned char * +pk11_saveContextHelper(PK11Context *context, unsigned char *buffer, + unsigned long *savedLength) +{ + CK_RV crv; + + /* If buffer is NULL, this will get the length */ + crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session, + (CK_BYTE_PTR)buffer, + savedLength); + if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) { + /* the given buffer wasn't big enough (or was NULL), but we + * have the length, so try again with a new buffer and the + * correct length + */ + unsigned long bufLen = *savedLength; + buffer = PORT_Alloc(bufLen); + if (buffer == NULL) { + return (unsigned char *)NULL; + } + crv = PK11_GETTAB(context->slot)->C_GetOperationState( + context->session, + (CK_BYTE_PTR)buffer, + savedLength); + if (crv != CKR_OK) { + PORT_ZFree(buffer, bufLen); + } + } + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return (unsigned char *)NULL; + } + return buffer; +} + +void * +pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength) +{ + return pk11_saveContextHelper(context, + (unsigned char *)space, savedLength); +} + +/* + * restore the current context + */ +SECStatus +pk11_restoreContext(PK11Context *context,void *space, unsigned long savedLength) +{ + CK_RV crv; + CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID: + CK_INVALID_HANDLE; + + PORT_Assert(space != NULL); + if (space == NULL) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session, + (CK_BYTE_PTR)space, savedLength, objectID, 0); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv)); + return SECFailure; + } + return SECSuccess; +} + +SECStatus pk11_Finalize(PK11Context *context); + +/* + * Context initialization. Used by all flavors of CreateContext + */ +static SECStatus +pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) +{ + CK_RV crv; + PK11SymKey *symKey = context->key; + SECStatus rv = SECSuccess; + + switch (context->operation) { + case CKA_ENCRYPT: + crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, + mech_info, symKey->objectID); + break; + case CKA_DECRYPT: + if (context->fortezzaHack) { + CK_ULONG count = 0;; + /* generate the IV for fortezza */ + crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, + mech_info, symKey->objectID); + if (crv != CKR_OK) break; + PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, + NULL, &count); + } + crv=PK11_GETTAB(context->slot)->C_DecryptInit(context->session, + mech_info, symKey->objectID); + break; + case CKA_SIGN: + crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, + mech_info, symKey->objectID); + break; + case CKA_VERIFY: + crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, + mech_info, symKey->objectID); + break; + case CKA_DIGEST: + crv=PK11_GETTAB(context->slot)->C_DigestInit(context->session, + mech_info); + break; + default: + crv = CKR_OPERATION_NOT_INITIALIZED; + break; + } + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + + /* + * handle session starvation case.. use our last session to multiplex + */ + if (!context->ownSession) { + context->savedData = pk11_saveContext(context,context->savedData, + &context->savedLength); + if (context->savedData == NULL) rv = SECFailure; + /* clear out out session for others to use */ + pk11_Finalize(context); + } + return rv; +} + + +/* + * Common Helper Function do come up with a new context. + */ +static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type, + PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, + SECItem *param) +{ + CK_MECHANISM mech_info; + PK11Context *context; + SECStatus rv; + + PORT_Assert(slot != NULL); + if (!slot) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + context = (PK11Context *) PORT_Alloc(sizeof(PK11Context)); + if (context == NULL) { + return NULL; + } + + /* now deal with the fortezza hack... the fortezza hack is an attempt + * to get around the issue of the card not allowing you to do a FORTEZZA + * LoadIV/Encrypt, which was added because such a combination could be + * use to circumvent the key escrow system. Unfortunately SSL needs to + * do this kind of operation, so in SSL we do a loadIV (to verify it), + * Then GenerateIV, and through away the first 8 bytes on either side + * of the connection.*/ + context->fortezzaHack = PR_FALSE; + if (type == CKM_SKIPJACK_CBC64) { + if (symKey->origin == PK11_OriginFortezzaHack) { + context->fortezzaHack = PR_TRUE; + } + } + + /* initialize the critical fields of the context */ + context->operation = operation; + context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL; + context->slot = PK11_ReferenceSlot(slot); + context->session = pk11_GetNewSession(slot,&context->ownSession); + context->cx = symKey ? symKey->cx : NULL; + /* get our session */ + context->savedData = NULL; + + /* save the parameters so that some digesting stuff can do multiple + * begins on a single context */ + context->type = type; + if (param) { + if (param->len > 0) { + context->param = SECITEM_DupItem(param); + } else { + context->param = (SECItem *)&pk11_null_params; + } + } else { + context->param = NULL; + } + context->init = PR_FALSE; + context->sessionLock = PZ_NewLock(nssILockPK11cxt); + if ((context->param == NULL) || (context->sessionLock == NULL)) { + PK11_DestroyContext(context,PR_TRUE); + return NULL; + } + + mech_info.mechanism = type; + mech_info.pParameter = param->data; + mech_info.ulParameterLen = param->len; + PK11_EnterContextMonitor(context); + rv = pk11_context_init(context,&mech_info); + PK11_ExitContextMonitor(context); + + if (rv != SECSuccess) { + PK11_DestroyContext(context,PR_TRUE); + return NULL; + } + context->init = PR_TRUE; + return context; +} + + +/* + * put together the various PK11_Create_Context calls used by different + * parts of libsec. + */ +PK11Context * +__PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, + SECItem *param, void *wincx) +{ + PK11SymKey *symKey; + PK11Context *context; + + /* first get a slot */ + if (slot == NULL) { + slot = PK11_GetBestSlot(type,wincx); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return NULL; + } + } else { + PK11_ReferenceSlot(slot); + } + + /* now import the key */ + symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx); + if (symKey == NULL) return NULL; + + context = PK11_CreateContextBySymKey(type, operation, symKey, param); + + PK11_FreeSymKey(symKey); + PK11_FreeSlot(slot); + + return context; +} + +PK11Context * +PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, + SECItem *param, void *wincx) +{ + return __PK11_CreateContextByRawKey(slot, type, origin, operation, + key, param, wincx); +} + + +/* + * Create a context from a key. We really should make sure we aren't using + * the same key in multiple session! + */ +PK11Context * +PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation, + PK11SymKey *symKey, SECItem *param) +{ + PK11SymKey *newKey; + PK11Context *context; + + /* if this slot doesn't support the mechanism, go to a slot that does */ + newKey = pk11_ForceSlot(symKey,type,operation); + if (newKey == NULL) { + PK11_ReferenceSymKey(symKey); + } else { + symKey = newKey; + } + + + /* Context Adopts the symKey.... */ + context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey, + param); + PK11_FreeSymKey(symKey); + return context; +} + +/* + * Digest contexts don't need keys, but the do need to find a slot. + * Macing should use PK11_CreateContextBySymKey. + */ +PK11Context * +PK11_CreateDigestContext(SECOidTag hashAlg) +{ + /* digesting has to work without authentication to the slot */ + CK_MECHANISM_TYPE type; + PK11SlotInfo *slot; + PK11Context *context; + SECItem param; + + type = PK11_AlgtagToMechanism(hashAlg); + slot = PK11_GetBestSlot(type, NULL); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return NULL; + } + + /* maybe should really be PK11_GenerateNewParam?? */ + param.data = NULL; + param.len = 0; + param.type = 0; + + context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, ¶m); + PK11_FreeSlot(slot); + return context; +} + +/* + * create a new context which is the clone of the state of old context. + */ +PK11Context * PK11_CloneContext(PK11Context *old) +{ + PK11Context *newcx; + PRBool needFree = PR_FALSE; + SECStatus rv = SECSuccess; + void *data; + unsigned long len; + + newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation, + old->key, old->param); + if (newcx == NULL) return NULL; + + /* now clone the save state. First we need to find the save state + * of the old session. If the old context owns it's session, + * the state needs to be saved, otherwise the state is in saveData. */ + if (old->ownSession) { + PK11_EnterContextMonitor(old); + data=pk11_saveContext(old,NULL,&len); + PK11_ExitContextMonitor(old); + needFree = PR_TRUE; + } else { + data = old->savedData; + len = old->savedLength; + } + + if (data == NULL) { + PK11_DestroyContext(newcx,PR_TRUE); + return NULL; + } + + /* now copy that state into our new context. Again we have different + * work if the new context owns it's own session. If it does, we + * restore the state gathered above. If it doesn't, we copy the + * saveData pointer... */ + if (newcx->ownSession) { + PK11_EnterContextMonitor(newcx); + rv = pk11_restoreContext(newcx,data,len); + PK11_ExitContextMonitor(newcx); + } else { + PORT_Assert(newcx->savedData != NULL); + if ((newcx->savedData == NULL) || (newcx->savedLength < len)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } else { + PORT_Memcpy(newcx->savedData,data,len); + newcx->savedLength = len; + } + } + + if (needFree) PORT_Free(data); + + if (rv != SECSuccess) { + PK11_DestroyContext(newcx,PR_TRUE); + return NULL; + } + return newcx; +} + +/* + * save the current context state into a variable. Required to make FORTEZZA + * work. + */ +SECStatus +PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength) +{ + unsigned char * data = NULL; + CK_ULONG length = saveLength; + + if (cx->ownSession) { + PK11_EnterContextMonitor(cx); + data = pk11_saveContextHelper(cx, save, &length); + PK11_ExitContextMonitor(cx); + if (data) *len = length; + } else if ((unsigned) saveLength >= cx->savedLength) { + data = (unsigned char*)cx->savedData; + if (cx->savedData) { + PORT_Memcpy(save,cx->savedData,cx->savedLength); + } + *len = cx->savedLength; + } + if (data != NULL) { + if (cx->ownSession) { + PORT_ZFree(data, length); + } + return SECSuccess; + } else { + return SECFailure; + } +} + +/* same as above, but may allocate the return buffer. */ +unsigned char * +PK11_SaveContextAlloc(PK11Context *cx, + unsigned char *preAllocBuf, unsigned int pabLen, + unsigned int *stateLen) +{ + unsigned char *stateBuf = NULL; + unsigned long length = (unsigned long)pabLen; + + if (cx->ownSession) { + PK11_EnterContextMonitor(cx); + stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length); + PK11_ExitContextMonitor(cx); + *stateLen = (stateBuf != NULL) ? length : 0; + } else { + if (pabLen < cx->savedLength) { + stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength); + if (!stateBuf) { + return (unsigned char *)NULL; + } + } else { + stateBuf = preAllocBuf; + } + if (cx->savedData) { + PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength); + } + *stateLen = cx->savedLength; + } + return stateBuf; +} + +/* + * restore the context state into a new running context. Also required for + * FORTEZZA . + */ +SECStatus +PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len) +{ + SECStatus rv = SECSuccess; + if (cx->ownSession) { + PK11_EnterContextMonitor(cx); + pk11_Finalize(cx); + rv = pk11_restoreContext(cx,save,len); + PK11_ExitContextMonitor(cx); + } else { + PORT_Assert(cx->savedData != NULL); + if ((cx->savedData == NULL) || (cx->savedLength < (unsigned) len)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } else { + PORT_Memcpy(cx->savedData,save,len); + cx->savedLength = len; + } + } + return rv; +} + +/* + * This is to get FIPS compliance until we can convert + * libjar to use PK11_ hashing functions. It returns PR_FALSE + * if we can't get a PK11 Context. + */ +PRBool +PK11_HashOK(SECOidTag algID) { + PK11Context *cx; + + cx = PK11_CreateDigestContext(algID); + if (cx == NULL) return PR_FALSE; + PK11_DestroyContext(cx, PR_TRUE); + return PR_TRUE; +} + + + +/* + * start a new digesting or Mac'ing operation on this context + */ +SECStatus PK11_DigestBegin(PK11Context *cx) +{ + CK_MECHANISM mech_info; + SECStatus rv; + + if (cx->init == PR_TRUE) { + return SECSuccess; + } + + /* + * make sure the old context is clear first + */ + PK11_EnterContextMonitor(cx); + pk11_Finalize(cx); + + mech_info.mechanism = cx->type; + mech_info.pParameter = cx->param->data; + mech_info.ulParameterLen = cx->param->len; + rv = pk11_context_init(cx,&mech_info); + PK11_ExitContextMonitor(cx); + + if (rv != SECSuccess) { + return SECFailure; + } + cx->init = PR_TRUE; + return SECSuccess; +} + +SECStatus +PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in, + int32 len) { + PK11Context *context; + unsigned int max_length; + unsigned int out_length; + SECStatus rv; + + context = PK11_CreateDigestContext(hashAlg); + if (context == NULL) return SECFailure; + + rv = PK11_DigestBegin(context); + if (rv != SECSuccess) { + PK11_DestroyContext(context, PR_TRUE); + return rv; + } + + rv = PK11_DigestOp(context, in, len); + if (rv != SECSuccess) { + PK11_DestroyContext(context, PR_TRUE); + return rv; + } + + /* XXX This really should have been an argument to this function! */ + max_length = HASH_ResultLenByOidTag(hashAlg); + PORT_Assert(max_length); + if (!max_length) + max_length = HASH_LENGTH_MAX; + + rv = PK11_DigestFinal(context,out,&out_length,max_length); + PK11_DestroyContext(context, PR_TRUE); + return rv; +} + + +/* + * execute a bulk encryption operation + */ +SECStatus +PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, + int maxout, unsigned char *in, int inlen) +{ + CK_RV crv = CKR_OK; + CK_ULONG length = maxout; + CK_ULONG offset =0; + SECStatus rv = SECSuccess; + unsigned char *saveOut = out; + unsigned char *allocOut = NULL; + + /* if we ran out of session, we need to restore our previously stored + * state. + */ + PK11_EnterContextMonitor(context); + if (!context->ownSession) { + rv = pk11_restoreContext(context,context->savedData, + context->savedLength); + if (rv != SECSuccess) { + PK11_ExitContextMonitor(context); + return rv; + } + } + + /* + * The fortezza hack is to send 8 extra bytes on the first encrypted and + * loose them on the first decrypt. + */ + if (context->fortezzaHack) { + unsigned char random[8]; + if (context->operation == CKA_ENCRYPT) { + PK11_ExitContextMonitor(context); + rv = PK11_GenerateRandom(random,sizeof(random)); + PK11_EnterContextMonitor(context); + + /* since we are offseting the output, we can't encrypt back into + * the same buffer... allocate a temporary buffer just for this + * call. */ + allocOut = out = (unsigned char*)PORT_Alloc(maxout); + if (out == NULL) { + PK11_ExitContextMonitor(context); + return SECFailure; + } + crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, + random,sizeof(random),out,&length); + + out += length; + maxout -= length; + offset = length; + } else if (context->operation == CKA_DECRYPT) { + length = sizeof(random); + crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, + in,sizeof(random),random,&length); + inlen -= length; + in += length; + context->fortezzaHack = PR_FALSE; + } + } + + switch (context->operation) { + case CKA_ENCRYPT: + length = maxout; + crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, + in, inlen, out, &length); + length += offset; + break; + case CKA_DECRYPT: + length = maxout; + crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, + in, inlen, out, &length); + break; + default: + crv = CKR_OPERATION_NOT_INITIALIZED; + break; + } + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + *outlen = 0; + rv = SECFailure; + } else { + *outlen = length; + } + + if (context->fortezzaHack) { + if (context->operation == CKA_ENCRYPT) { + PORT_Assert(allocOut); + PORT_Memcpy(saveOut, allocOut, length); + PORT_Free(allocOut); + } + context->fortezzaHack = PR_FALSE; + } + + /* + * handle session starvation case.. use our last session to multiplex + */ + if (!context->ownSession) { + context->savedData = pk11_saveContext(context,context->savedData, + &context->savedLength); + if (context->savedData == NULL) rv = SECFailure; + + /* clear out out session for others to use */ + pk11_Finalize(context); + } + PK11_ExitContextMonitor(context); + return rv; +} + +/* + * execute a digest/signature operation + */ +SECStatus +PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen) +{ + CK_RV crv = CKR_OK; + SECStatus rv = SECSuccess; + + /* if we ran out of session, we need to restore our previously stored + * state. + */ + context->init = PR_FALSE; + PK11_EnterContextMonitor(context); + if (!context->ownSession) { + rv = pk11_restoreContext(context,context->savedData, + context->savedLength); + if (rv != SECSuccess) { + PK11_ExitContextMonitor(context); + return rv; + } + } + + switch (context->operation) { + /* also for MAC'ing */ + case CKA_SIGN: + crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session, + (unsigned char *)in, + inLen); + break; + case CKA_VERIFY: + crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session, + (unsigned char *)in, + inLen); + break; + case CKA_DIGEST: + crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, + (unsigned char *)in, + inLen); + break; + default: + crv = CKR_OPERATION_NOT_INITIALIZED; + break; + } + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + rv = SECFailure; + } + + /* + * handle session starvation case.. use our last session to multiplex + */ + if (!context->ownSession) { + context->savedData = pk11_saveContext(context,context->savedData, + &context->savedLength); + if (context->savedData == NULL) rv = SECFailure; + + /* clear out out session for others to use */ + pk11_Finalize(context); + } + PK11_ExitContextMonitor(context); + return rv; +} + +/* + * Digest a key if possible./ + */ +SECStatus +PK11_DigestKey(PK11Context *context, PK11SymKey *key) +{ + CK_RV crv = CKR_OK; + SECStatus rv = SECSuccess; + PK11SymKey *newKey = NULL; + + if (!context || !key) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + /* if we ran out of session, we need to restore our previously stored + * state. + */ + if (context->slot != key->slot) { + newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key); + } else { + newKey = PK11_ReferenceSymKey(key); + } + + context->init = PR_FALSE; + PK11_EnterContextMonitor(context); + if (!context->ownSession) { + rv = pk11_restoreContext(context,context->savedData, + context->savedLength); + if (rv != SECSuccess) { + PK11_ExitContextMonitor(context); + PK11_FreeSymKey(newKey); + return rv; + } + } + + + if (newKey == NULL) { + crv = CKR_KEY_TYPE_INCONSISTENT; + if (key->data.data) { + crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, + key->data.data,key->data.len); + } + } else { + crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session, + newKey->objectID); + } + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + rv = SECFailure; + } + + /* + * handle session starvation case.. use our last session to multiplex + */ + if (!context->ownSession) { + context->savedData = pk11_saveContext(context,context->savedData, + &context->savedLength); + if (context->savedData == NULL) rv = SECFailure; + + /* clear out out session for others to use */ + pk11_Finalize(context); + } + PK11_ExitContextMonitor(context); + if (newKey) PK11_FreeSymKey(newKey); + return rv; +} + +/* + * externally callable version of the lowercase pk11_finalize(). + */ +SECStatus +PK11_Finalize(PK11Context *context) { + SECStatus rv; + + PK11_EnterContextMonitor(context); + rv = pk11_Finalize(context); + PK11_ExitContextMonitor(context); + return rv; +} + +/* + * clean up a cipher operation, so the session can be used by + * someone new. + */ +SECStatus +pk11_Finalize(PK11Context *context) +{ + CK_ULONG count = 0; + CK_RV crv; + unsigned char stackBuf[256]; + unsigned char *buffer = NULL; + + if (!context->ownSession) { + return SECSuccess; + } + +finalize: + switch (context->operation) { + case CKA_ENCRYPT: + crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, + buffer, &count); + break; + case CKA_DECRYPT: + crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, + buffer, &count); + break; + case CKA_SIGN: + crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, + buffer, &count); + break; + case CKA_VERIFY: + crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, + buffer, count); + break; + case CKA_DIGEST: + crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, + buffer, &count); + break; + default: + crv = CKR_OPERATION_NOT_INITIALIZED; + break; + } + + if (crv != CKR_OK) { + if (buffer != stackBuf) { + PORT_Free(buffer); + } + if (crv == CKR_OPERATION_NOT_INITIALIZED) { + /* if there's no operation, it is finalized */ + return SECSuccess; + } + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + + /* try to finalize the session with a buffer */ + if (buffer == NULL) { + if (count <= sizeof stackBuf) { + buffer = stackBuf; + } else { + buffer = PORT_Alloc(count); + if (buffer == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + } + goto finalize; + } + if (buffer != stackBuf) { + PORT_Free(buffer); + } + return SECSuccess; +} + +/* + * Return the final digested or signed data... + * this routine can either take pre initialized data, or allocate data + * either out of an arena or out of the standard heap. + */ +SECStatus +PK11_DigestFinal(PK11Context *context,unsigned char *data, + unsigned int *outLen, unsigned int length) +{ + CK_ULONG len; + CK_RV crv; + SECStatus rv; + + + /* if we ran out of session, we need to restore our previously stored + * state. + */ + PK11_EnterContextMonitor(context); + if (!context->ownSession) { + rv = pk11_restoreContext(context,context->savedData, + context->savedLength); + if (rv != SECSuccess) { + PK11_ExitContextMonitor(context); + return rv; + } + } + + len = length; + switch (context->operation) { + case CKA_SIGN: + crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, + data,&len); + break; + case CKA_VERIFY: + crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, + data,len); + break; + case CKA_DIGEST: + crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, + data,&len); + break; + case CKA_ENCRYPT: + crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, + data, &len); + break; + case CKA_DECRYPT: + crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, + data, &len); + break; + default: + crv = CKR_OPERATION_NOT_INITIALIZED; + break; + } + PK11_ExitContextMonitor(context); + + *outLen = (unsigned int) len; + context->init = PR_FALSE; /* allow Begin to start up again */ + + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + return SECSuccess; +} + diff --git a/security/nss/lib/pk11wrap/pk11func.h b/security/nss/lib/pk11wrap/pk11func.h index beae905382e..087d094cfbb 100644 --- a/security/nss/lib/pk11wrap/pk11func.h +++ b/security/nss/lib/pk11wrap/pk11func.h @@ -19,7 +19,6 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Douglas Stebila , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -36,675 +35,12 @@ * ***** END LICENSE BLOCK ***** */ #ifndef _PK11FUNC_H_ #define _PK11FUNC_H_ -#include "plarena.h" -#include "seccomon.h" -#include "secoidt.h" -#include "secdert.h" -#include "keyt.h" -#include "certt.h" -#include "pkcs11t.h" -#include "secmodt.h" -#include "seccomon.h" -#include "pkcs7t.h" -#include "cmsreclist.h" - -SEC_BEGIN_PROTOS - -/************************************************************ - * Generic Slot Lists Management - ************************************************************/ -PK11SlotList * PK11_NewSlotList(void); -void PK11_FreeSlotList(PK11SlotList *list); -SECStatus PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot); -SECStatus PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le); -PK11SlotListElement * PK11_GetFirstSafe(PK11SlotList *list); -PK11SlotListElement *PK11_GetNextSafe(PK11SlotList *list, - PK11SlotListElement *le, PRBool restart); -PK11SlotListElement *PK11_FindSlotElement(PK11SlotList *list, - PK11SlotInfo *slot); - -/************************************************************ - * Generic Slot Management - ************************************************************/ -PK11SlotInfo *PK11_ReferenceSlot(PK11SlotInfo *slot); -void PK11_FreeSlot(PK11SlotInfo *slot); -SECStatus PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object); -SECStatus PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object); -CK_OBJECT_HANDLE PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject); -SECStatus PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - CK_ATTRIBUTE_TYPE type, PRArenaPool *arena, SECItem *result); -CK_ULONG PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - CK_ATTRIBUTE_TYPE type); -PK11SlotInfo *PK11_GetInternalKeySlot(void); -PK11SlotInfo *PK11_GetInternalSlot(void); -char * PK11_MakeString(PRArenaPool *arena,char *space,char *staticSring, - int stringLen); -int PK11_MapError(CK_RV error); -CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot); -void PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession); -PRBool PK11_RWSessionHasLock(PK11SlotInfo *slot, - CK_SESSION_HANDLE session_handle); -PK11SlotInfo *PK11_NewSlotInfo(SECMODModule *mod); -SECStatus PK11_Logout(PK11SlotInfo *slot); -void PK11_LogoutAll(void); -void PK11_EnterSlotMonitor(PK11SlotInfo *); -void PK11_ExitSlotMonitor(PK11SlotInfo *); -void PK11_CleanKeyList(PK11SlotInfo *slot); - - -/************************************************************ - * Slot Password Management - ************************************************************/ -void PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout); -void PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout); -SECStatus PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw); -SECStatus PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw); -SECStatus PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx); -PRBool PK11_IsLoggedIn(PK11SlotInfo *slot, void *wincx); -SECStatus PK11_VerifyPW(PK11SlotInfo *slot,char *pw); -SECStatus PK11_InitPin(PK11SlotInfo *slot,char *ssopw, char *pk11_userpwd); -SECStatus PK11_ChangePW(PK11SlotInfo *slot,char *oldpw, char *newpw); -void PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx); -void PK11_SetPasswordFunc(PK11PasswordFunc func); -void PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func); -void PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func); -int PK11_GetMinimumPwdLength(PK11SlotInfo *slot); -SECStatus PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd); - -/************************************************************ - * Manage the built-In Slot Lists - ************************************************************/ -SECStatus PK11_InitSlotLists(void); -void PK11_DestroySlotLists(void); -PK11SlotList *PK11_GetSlotList(CK_MECHANISM_TYPE type); -void PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count); -void PK11_ClearSlotList(PK11SlotInfo *slot); - - -/****************************************************************** - * Slot initialization - ******************************************************************/ -PRBool PK11_VerifyMechanism(PK11SlotInfo *slot,PK11SlotInfo *intern, - CK_MECHANISM_TYPE mech, SECItem *data, SECItem *iv); -PRBool PK11_VerifySlotMechanisms(PK11SlotInfo *slot); -SECStatus pk11_CheckVerifyTest(PK11SlotInfo *slot); -SECStatus PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts); -SECStatus PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx); -void PK11_InitSlot(SECMODModule *mod,CK_SLOT_ID slotID,PK11SlotInfo *slot); -SECStatus PK11_TokenRefresh(PK11SlotInfo *slot); - - -/****************************************************************** - * Slot info functions - ******************************************************************/ -PK11SlotInfo *PK11_FindSlotByName(char *name); -PK11SlotInfo *PK11_FindSlotBySerial(char *serial); -/****************************************************************** - * PK11_FindSlotsByNames searches for a PK11SlotInfo using one or - * more criteria : dllName, slotName and tokenName . In addition, if - * presentOnly is set , only slots with a token inserted will be - * returned. - ******************************************************************/ -PK11SlotList *PK11_FindSlotsByNames(const char *dllName, - const char* slotName, const char* tokenName, PRBool presentOnly); -PRBool PK11_IsReadOnly(PK11SlotInfo *slot); -PRBool PK11_IsInternal(PK11SlotInfo *slot); -char * PK11_GetTokenName(PK11SlotInfo *slot); -char * PK11_GetSlotName(PK11SlotInfo *slot); -PRBool PK11_NeedLogin(PK11SlotInfo *slot); -PRBool PK11_IsFriendly(PK11SlotInfo *slot); -PRBool PK11_IsHW(PK11SlotInfo *slot); -PRBool PK11_NeedUserInit(PK11SlotInfo *slot); -PRBool PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot); -int PK11_GetSlotSeries(PK11SlotInfo *slot); -int PK11_GetCurrentWrapIndex(PK11SlotInfo *slot); -unsigned long PK11_GetDefaultFlags(PK11SlotInfo *slot); -CK_SLOT_ID PK11_GetSlotID(PK11SlotInfo *slot); -SECMODModuleID PK11_GetModuleID(PK11SlotInfo *slot); -SECStatus PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info); -SECStatus PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info); -PRBool PK11_IsDisabled(PK11SlotInfo *slot); -PRBool PK11_HasRootCerts(PK11SlotInfo *slot); -PK11DisableReasons PK11_GetDisabledReason(PK11SlotInfo *slot); -/* Prevents the slot from being used, and set disable reason to user-disable */ -/* NOTE: Mechanisms that were ON continue to stay ON */ -/* Therefore, when the slot is enabled, it will remember */ -/* what mechanisms needs to be turned on */ -PRBool PK11_UserDisableSlot(PK11SlotInfo *slot); -/* Allow all mechanisms that are ON before UserDisableSlot() */ -/* was called to be available again */ -PRBool PK11_UserEnableSlot(PK11SlotInfo *slot); -/* - * wait for a specific slot event. - * event is a specific event to wait for. Currently only - * PK11TokenChangeOrRemovalEvent and PK11TokenPresentEvents are defined. - * timeout can be an interval time to wait, PR_INTERVAL_NO_WAIT (meaning only - * poll once), or PR_INTERVAL_NO_TIMEOUT (meaning block until a change). - * pollInterval is a suggested pulling interval value. '0' means use the - * default. Future implementations that don't poll may ignore this value. - * series is the current series for the last slot. This should be the series - * value for the slot the last time you read persistant information from the - * slot. For instance, if you publish a cert from the slot, you should obtain - * the slot series at that time. Then PK11_WaitForTokenEvent can detect a - * a change in the slot between the time you publish and the time - * PK11_WaitForTokenEvent is called, elliminating potential race conditions. - * - * The current status that is returned is: - * PK11TokenNotRemovable - always returned for any non-removable token. - * PK11TokenPresent - returned when the token is present and we are waiting - * on a PK11TokenPresentEvent. Then next event to look for is a - * PK11TokenChangeOrRemovalEvent. - * PK11TokenChanged - returned when the old token has been removed and a new - * token ad been inserted, and we are waiting for a - * PK11TokenChangeOrRemovalEvent. The next event to look for is another - * PK11TokenChangeOrRemovalEvent. - * PK11TokenRemoved - returned when the token is not present and we are - * waiting for a PK11TokenChangeOrRemovalEvent. The next event to look for - * is a PK11TokenPresentEvent. - */ -PK11TokenStatus PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event, - PRIntervalTime timeout, PRIntervalTime pollInterval, int series); - -PRBool PK11_NeedPWInit(void); -PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot); -PRBool PK11_TokenExists(CK_MECHANISM_TYPE); -SECStatus PK11_GetModInfo(SECMODModule *mod, CK_INFO *info); -PRBool PK11_IsFIPS(void); -SECMODModule *PK11_GetModule(PK11SlotInfo *slot); - -/********************************************************************* - * Slot mapping utility functions. - *********************************************************************/ -PRBool PK11_IsPresent(PK11SlotInfo *slot); -PRBool PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type); -PK11SlotList * PK11_GetAllTokens(CK_MECHANISM_TYPE type,PRBool needRW, - PRBool loadCerts, void *wincx); -PK11SlotList * PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type, - PRBool needRW,void *wincx); -PK11SlotInfo *PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int count, - void *wincx); -PK11SlotInfo *PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx); -CK_MECHANISM_TYPE PK11_GetBestWrapMechanism(PK11SlotInfo *slot); -int PK11_GetBestKeyLength(PK11SlotInfo *slot, CK_MECHANISM_TYPE type); - -/********************************************************************* - * Mechanism Mapping functions - *********************************************************************/ -void PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key, - CK_MECHANISM_TYPE keygen, int ivLen, int blocksize); -CK_MECHANISM_TYPE PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len); -CK_MECHANISM_TYPE PK11_GetKeyMechanism(CK_KEY_TYPE type); -CK_MECHANISM_TYPE PK11_GetKeyGen(CK_MECHANISM_TYPE type); -CK_MECHANISM_TYPE PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size); -int PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params); -int PK11_GetIVLength(CK_MECHANISM_TYPE type); -SECItem *PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv); -unsigned char *PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len); -SECItem * PK11_BlockData(SECItem *data,unsigned long size); - -/* PKCS #11 to DER mapping functions */ -SECItem *PK11_ParamFromAlgid(SECAlgorithmID *algid); -SECItem *PK11_GenerateNewParam(CK_MECHANISM_TYPE, PK11SymKey *); -CK_MECHANISM_TYPE PK11_AlgtagToMechanism(SECOidTag algTag); -SECOidTag PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type); -SECOidTag PK11_FortezzaMapSig(SECOidTag algTag); -SECStatus PK11_ParamToAlgid(SECOidTag algtag, SECItem *param, - PRArenaPool *arena, SECAlgorithmID *algid); -SECStatus PK11_SeedRandom(PK11SlotInfo *,unsigned char *data,int len); -SECStatus PK11_RandomUpdate(void *data, size_t bytes); -SECStatus PK11_GenerateRandom(unsigned char *data,int len); -CK_RV PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, - CK_MECHANISM_PTR pCryptoMechanism, - SECItem *pbe_pwd, PRBool bad3DES); -CK_MECHANISM_TYPE PK11_GetPadMechanism(CK_MECHANISM_TYPE); - -/********************************************************************** - * Symetric, Public, and Private Keys - **********************************************************************/ -PK11SymKey *PK11_CreateSymKey(PK11SlotInfo *slot, - CK_MECHANISM_TYPE type, PRBool owner, void *wincx); -void PK11_FreeSymKey(PK11SymKey *key); -PK11SymKey *PK11_ReferenceSymKey(PK11SymKey *symKey); -PK11SymKey *PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, - PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx); -PK11SymKey *PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, - CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, - SECItem *key, CK_FLAGS flags, PRBool isPerm, void *wincx); -PK11SymKey *PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, - PK11Origin origin, CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, - PRBool owner, void *wincx); -PK11SymKey *PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, - CK_MECHANISM_TYPE type,int series, void *wincx); -/* - * This function is not thread-safe. It can only be called when only - * one thread has a reference to wrapKey. - */ -void PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey); -CK_MECHANISM_TYPE PK11_GetMechanism(PK11SymKey *symKey); -CK_OBJECT_HANDLE PK11_ImportPublicKey(PK11SlotInfo *slot, - SECKEYPublicKey *pubKey, PRBool isToken); -PK11SymKey *PK11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, - SECItem *param, int keySize,void *wincx); -PK11SymKey *PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, - SECItem *param, int keySize, SECItem *keyid, - PRBool isToken, void *wincx); -PK11SymKey * PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, - void *wincx); -PK11SymKey *PK11_GetNextSymKey(PK11SymKey *symKey); -CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *key); - -/* Key Generation specialized for SDR (fixed DES3 key) */ -PK11SymKey *PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx); - -SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey, - PK11SymKey *symKey, SECItem *wrappedKey); -SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params, - PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey); -/* move a key to 'slot' optionally set the key attributes according to either - * operation or the flags and making the key permanent at the same time. - * If the key is moved to the same slot, operation and flags values are - * currently ignored */ -PK11SymKey *PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, - CK_FLAGS flags, PRBool perm, PK11SymKey *symKey); -/* - * derive a new key from the base key. - * PK11_Derive returns a key which can do exactly one operation, and is - * ephemeral (session key). - * PK11_DeriveWithFlags is the same as PK11_Derive, except you can use - * CKF_ flags to enable more than one operation. - * PK11_DeriveWithFlagsPerm is the same as PK11_DeriveWithFlags except you can - * (optionally) make the key permanent (token key). - */ -PK11SymKey *PK11_Derive(PK11SymKey *baseKey, CK_MECHANISM_TYPE mechanism, - SECItem *param, CK_MECHANISM_TYPE target, - CK_ATTRIBUTE_TYPE operation, int keySize); -PK11SymKey *PK11_DeriveWithFlags( PK11SymKey *baseKey, - CK_MECHANISM_TYPE derive, SECItem *param, CK_MECHANISM_TYPE target, - CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags); -PK11SymKey * PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, - CK_MECHANISM_TYPE derive, - SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, - int keySize, CK_FLAGS flags, PRBool isPerm); - -PK11SymKey *PK11_PubDerive( SECKEYPrivateKey *privKey, - SECKEYPublicKey *pubKey, PRBool isSender, SECItem *randomA, SECItem *randomB, - CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target, - CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx) ; -PK11SymKey *PK11_PubDeriveWithKDF( SECKEYPrivateKey *privKey, - SECKEYPublicKey *pubKey, PRBool isSender, SECItem *randomA, SECItem *randomB, - CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target, - CK_ATTRIBUTE_TYPE operation, int keySize, - CK_ULONG kdf, SECItem *sharedData, void *wincx); /* - * unwrap a new key with a symetric key. - * PK11_Unwrap returns a key which can do exactly one operation, and is - * ephemeral (session key). - * PK11_UnwrapWithFlags is the same as PK11_Unwrap, except you can use - * CKF_ flags to enable more than one operation. - * PK11_UnwrapWithFlagsPerm is the same as PK11_UnwrapWithFlags except you can - * (optionally) make the key permanent (token key). + * the original pk11func.h had a mix of public and private functions. + * continue to provide those for backward compatibility. */ -PK11SymKey *PK11_UnwrapSymKey(PK11SymKey *key, - CK_MECHANISM_TYPE wraptype, SECItem *param, SECItem *wrapppedKey, - CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize); -PK11SymKey *PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, - CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey, - CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, - CK_FLAGS flags); -PK11SymKey * PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, - CK_MECHANISM_TYPE wrapType, - SECItem *param, SECItem *wrappedKey, - CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, - int keySize, CK_FLAGS flags, PRBool isPerm); - -/* - * unwrap a new key with a private key. - * PK11_PubUnwrap returns a key which can do exactly one operation, and is - * ephemeral (session key). - * PK11_PubUnwrapWithFlagsPerm is the same as PK11_PubUnwrap except you can - * use * CKF_ flags to enable more than one operation, and optionally make - * the key permanent (token key). - */ -PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey, - CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize); -PK11SymKey * PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, - SECItem *wrappedKey, CK_MECHANISM_TYPE target, - CK_ATTRIBUTE_TYPE operation, int keySize, - CK_FLAGS flags, PRBool isPerm); -PK11SymKey *PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, - SECItem *keyID, void *wincx); -SECStatus PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey,PRBool force); -SECStatus PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey); -SECStatus PK11_DeleteTokenSymKey(PK11SymKey *symKey); -SECStatus PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx); -SECKEYPrivateKey * PK11_LoadPrivKey(PK11SlotInfo *slot, - SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, - PRBool token, PRBool sensitive); -SECKEYPublicKey *PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, - CK_OBJECT_HANDLE id); -char * PK11_GetSymKeyNickname(PK11SymKey *symKey); -char * PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey); -char * PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey); -SECStatus PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname); -SECStatus PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, - const char *nickname); -SECStatus PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, - const char *nickname); - -/* size to hold key in bytes */ -unsigned int PK11_GetKeyLength(PK11SymKey *key); -/* size of actual secret parts of key in bits */ -/* algid is because RC4 strength is determined by the effective bits as well - * as the key bits */ -unsigned int PK11_GetKeyStrength(PK11SymKey *key,SECAlgorithmID *algid); -SECStatus PK11_ExtractKeyValue(PK11SymKey *symKey); -SECItem * PK11_GetKeyData(PK11SymKey *symKey); -PK11SlotInfo * PK11_GetSlotFromKey(PK11SymKey *symKey); -void *PK11_GetWindow(PK11SymKey *symKey); -SECKEYPrivateKey *PK11_GenerateKeyPair(PK11SlotInfo *slot, - CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk, - PRBool isPerm, PRBool isSensitive, void *wincx); -SECKEYPrivateKey *PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, - PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx); -SECKEYPrivateKey * PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, - CERTCertificate *cert, void *wincx); -SECKEYPrivateKey * PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx); -SECKEYPrivateKey * PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, - void *wincx); -CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate *cert, - void *wincx, PK11SlotInfo **pSlot); -int PK11_GetPrivateModulusLen(SECKEYPrivateKey *key); -SECStatus PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, - unsigned *outLen, unsigned int maxLen, unsigned char *enc, unsigned encLen); -/* The encrypt version of the above function */ -SECStatus PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc, - unsigned char *data, unsigned dataLen, void *wincx); -SECStatus PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, - SECKEYPrivateKeyInfo *pki, SECItem *nickname, - SECItem *publicValue, PRBool isPerm, PRBool isPrivate, - unsigned int usage, void *wincx); -SECStatus PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, - SECKEYPrivateKeyInfo *pki, SECItem *nickname, - SECItem *publicValue, PRBool isPerm, PRBool isPrivate, - unsigned int usage, SECKEYPrivateKey** privk, void *wincx); -SECStatus PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, - SECItem *derPKI, SECItem *nickname, - SECItem *publicValue, PRBool isPerm, PRBool isPrivate, - unsigned int usage, void *wincx); -SECStatus PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, - SECItem *derPKI, SECItem *nickname, - SECItem *publicValue, PRBool isPerm, PRBool isPrivate, - unsigned int usage, SECKEYPrivateKey** privk, void *wincx); -SECStatus PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, - SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, - SECItem *nickname, SECItem *publicValue, PRBool isPerm, - PRBool isPrivate, KeyType type, - unsigned int usage, void *wincx); -SECKEYPrivateKeyInfo *PK11_ExportPrivateKeyInfo( - CERTCertificate *cert, void *wincx); -SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivKeyInfo( - PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem, - SECKEYPrivateKey *pk, int iteration, void *wincx); -SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivateKeyInfo( - PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem, - CERTCertificate *cert, int iteration, void *wincx); -SECKEYPrivateKey *PK11_FindKeyByDERCert(PK11SlotInfo *slot, - CERTCertificate *cert, void *wincx); -SECKEYPublicKey *PK11_MakeKEAPubKey(unsigned char *data, int length); -SECStatus PK11_DigestKey(PK11Context *context, PK11SymKey *key); -PRBool PK11_VerifyKeyOK(PK11SymKey *key); -SECKEYPrivateKey *PK11_UnwrapPrivKey(PK11SlotInfo *slot, - PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType, - SECItem *param, SECItem *wrappedKey, SECItem *label, - SECItem *publicValue, PRBool token, PRBool sensitive, - CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, int usageCount, - void *wincx); -SECStatus PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, - SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, - SECItem *param, SECItem *wrappedKey, void *wincx); -PK11SymKey * pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, - CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey); -SECItem *PK11_GetKeyIDFromCert(CERTCertificate *cert, void *wincx); -SECItem * PK11_GetKeyIDFromPrivateKey(SECKEYPrivateKey *key, void *wincx); -SECItem* PK11_DEREncodePublicKey(SECKEYPublicKey *pubk); -PK11SymKey* PK11_CopySymKeyForSigning(PK11SymKey *originalKey, - CK_MECHANISM_TYPE mech); -SECKEYPrivateKeyList* PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, - char *nickname, void *wincx); -SECKEYPublicKeyList* PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, - char *nickname); -SECKEYPQGParams *PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey); -/* depricated */ -SECKEYPrivateKeyList* PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot); - -PK11SymKey *PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, - void *wincx); -SECKEYPrivateKey *PK11_ConvertSessionPrivKeyToTokenPrivKey( - SECKEYPrivateKey *privk, void* wincx); - -/********************************************************************** - * Certs - **********************************************************************/ -SECItem *PK11_MakeIDFromPubKey(SECItem *pubKeyData); -CERTCertificate *PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey); -SECStatus PK11_TraverseSlotCerts( - SECStatus(* callback)(CERTCertificate*,SECItem *,void *), - void *arg, void *wincx); -SECStatus PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, - SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg); -CERTCertificate * PK11_FindCertFromNickname(char *nickname, void *wincx); -CERTCertList * PK11_FindCertsFromNickname(char *nickname, void *wincx); -SECKEYPrivateKey * PK11_FindPrivateKeyFromNickname(char *nickname, void *wincx); -SECStatus PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, - CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust); -SECStatus PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert, - CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust); -PK11SlotInfo *PK11_ImportCertForKey(CERTCertificate *cert, char *nickname, - void *wincx); -PK11SlotInfo *PK11_ImportDERCertForKey(SECItem *derCert, char *nickname, - void *wincx); -CK_OBJECT_HANDLE * PK11_FindObjectsFromNickname(char *nickname, - PK11SlotInfo **slotptr, CK_OBJECT_CLASS objclass, int *returnCount, - void *wincx); -PK11SlotInfo *PK11_KeyForCertExists(CERTCertificate *cert, - CK_OBJECT_HANDLE *keyPtr, void *wincx); -PK11SlotInfo *PK11_KeyForDERCertExists(SECItem *derCert, - CK_OBJECT_HANDLE *keyPtr, void *wincx); -CK_OBJECT_HANDLE PK11_MatchItem(PK11SlotInfo *slot,CK_OBJECT_HANDLE peer, - CK_OBJECT_CLASS o_class); -CERTCertificate * PK11_FindCertByIssuerAndSN(PK11SlotInfo **slot, - CERTIssuerAndSN *sn, void *wincx); -CERTCertificate * PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slot, - SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip, - SECKEYPrivateKey**privKey, void *wincx); -int PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, - void *wincx); -CK_BBOOL PK11_HasAttributeSet( PK11SlotInfo *slot, - CK_OBJECT_HANDLE id, - CK_ATTRIBUTE_TYPE type ); -CK_RV PK11_GetAttributes(PRArenaPool *arena,PK11SlotInfo *slot, - CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count); -int PK11_NumberCertsForCertSubject(CERTCertificate *cert); -SECStatus PK11_TraverseCertsForSubject(CERTCertificate *cert, - SECStatus(*callback)(CERTCertificate *, void *), void *arg); -SECStatus PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, - PK11SlotInfo *slot, SECStatus(*callback)(CERTCertificate *, void *), - void *arg); -CERTCertificate *PK11_FindCertFromDERCert(PK11SlotInfo *slot, - CERTCertificate *cert, void *wincx); -CERTCertificate *PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, - SECItem *derCert, void *wincx); -CERTCertificate *PK11_FindCertFromDERSubjectAndNickname( - PK11SlotInfo *slot, - CERTCertificate *cert, char *nickname, - void *wincx); -SECStatus PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, - char *nickname, PRBool addUsage, - void *wincx); -CERTCertificate *PK11_FindBestKEAMatch(CERTCertificate *serverCert,void *wincx); -SECStatus PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, - PK11SlotInfo *slot2, CERTCertificate **cert1, CERTCertificate **cert2); -PRBool PK11_FortezzaHasKEA(CERTCertificate *cert); -CK_OBJECT_HANDLE PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, - void *wincx); -SECStatus PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, - PK11SlotInfo *slot, SECStatus(*callback)(CERTCertificate *, void *), - void *arg); -SECStatus PK11_TraverseCertsInSlot(PK11SlotInfo *slot, - SECStatus(* callback)(CERTCertificate*, void *), void *arg); -CERTCertList * PK11_ListCerts(PK11CertListType type, void *pwarg); -CERTCertList * PK11_ListCertsInSlot(PK11SlotInfo *slot); -SECStatus PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx); -CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, - int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena, PRInt32 decodeOptions); -/* import options */ -#define CRL_IMPORT_DEFAULT_OPTIONS 0x00000000 -#define CRL_IMPORT_BYPASS_CHECKS 0x00000001 - -/********************************************************************** - * Sign/Verify - **********************************************************************/ -int PK11_SignatureLen(SECKEYPrivateKey *key); -PK11SlotInfo * PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key); -SECStatus PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash); -SECStatus PK11_VerifyRecover(SECKEYPublicKey *key, SECItem *sig, - SECItem *dsig, void * wincx); -SECStatus PK11_Verify(SECKEYPublicKey *key, SECItem *sig, - SECItem *hash, void *wincx); - - - -/********************************************************************** - * Crypto Contexts - **********************************************************************/ -void PK11_DestroyContext(PK11Context *context, PRBool freeit); -PK11Context * PK11_CreateContextByRawKey(PK11SlotInfo *slot, - CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, - SECItem *key, SECItem *param, void *wincx); -PK11Context *PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, - CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, SECItem *param); -PK11Context *PK11_CreateDigestContext(SECOidTag hashAlg); -PK11Context *PK11_CloneContext(PK11Context *old); -SECStatus PK11_DigestBegin(PK11Context *cx); -SECStatus PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in, - int32 len); -SECStatus PK11_DigestOp(PK11Context *context, const unsigned char *in, - unsigned len); -SECStatus PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, - int maxout, unsigned char *in, int inlen); -SECStatus PK11_Finalize(PK11Context *context); -SECStatus PK11_DigestFinal(PK11Context *context, unsigned char *data, - unsigned int *outLen, unsigned int length); -PRBool PK11_HashOK(SECOidTag hashAlg); -SECStatus PK11_SaveContext(PK11Context *cx,unsigned char *save, - int *len, int saveLength); - -/* Save the context's state, with possible allocation. - * The caller may supply an already allocated buffer in preAllocBuf, - * with length pabLen. If the buffer is large enough for the context's - * state, it will receive the state. - * If the buffer is not large enough (or NULL), then a new buffer will - * be allocated with PORT_Alloc. - * In either case, the state will be returned as a buffer, and the length - * of the state will be given in *stateLen. - */ -unsigned char * -PK11_SaveContextAlloc(PK11Context *cx, - unsigned char *preAllocBuf, unsigned int pabLen, - unsigned int *stateLen); - -SECStatus PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len); -SECStatus PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len); -SECStatus PK11_ReadSlotCerts(PK11SlotInfo *slot); -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 * -PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem, - PRBool faulty3DES, void *wincx); -PK11SymKey * -PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *params, - SECItem *pwitem, PRBool faulty3DES, void *wincx); -SECItem * -PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem); - -/********************************************************************** - * Functions to manage secmod flags - **********************************************************************/ -PK11DefaultArrayEntry * PK11_GetDefaultArray(int *); -SECStatus PK11_UpdateSlotAttribute(PK11SlotInfo *, PK11DefaultArrayEntry *, - PRBool ); - -/********************************************************************** - * Functions to look at PKCS #11 dependent data - **********************************************************************/ -PK11GenericObject *PK11_FindGenericObjects(PK11SlotInfo *slot, - CK_OBJECT_CLASS objClass); -PK11GenericObject *PK11_GetNextGenericObject(PK11GenericObject *object); -PK11GenericObject *PK11_GetPrevtGenericObject(PK11GenericObject *object); -SECStatus PK11_UnlinkGenericObject(PK11GenericObject *object); -SECStatus PK11_LinkGenericObject(PK11GenericObject *list, - PK11GenericObject *object); -SECStatus PK11_DestroyGenericObjects(PK11GenericObject *object); -SECStatus PK11_DestroyGenericObject(PK11GenericObject *object); -SECStatus PK11_ReadRawAttribute(PK11ObjectType type, void *object, - CK_ATTRIBUTE_TYPE attr, SECItem *item); - - -/********************************************************************** - * New fucntions which are already depricated.... - **********************************************************************/ -SECItem * -PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot, - CERTCertificate *cert, void *pwarg); -SECItem * -PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *key); - -SECItem * -PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *handle, - SECItem *derName, int type, char **url); - -CK_OBJECT_HANDLE -PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, - SECItem *name, char *url, int type); - -SECItem * -PK11_FindSMimeProfile(PK11SlotInfo **slotp, char *emailAddr, SECItem *derSubj, - SECItem **profileTime); -SECStatus -PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, - SECItem *emailProfile, SECItem *profileTime); - -PRBool SECMOD_HasRootCerts(void); - -PRBool PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle); - -char * PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) ; -SECStatus PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - const char *nickname) ; - - -/* private */ -SECStatus pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), - void *cbArg, void *pwArg); - -SEC_END_PROTOS +#include "pk11pub.h" +#include "pk11priv.h" #endif diff --git a/security/nss/lib/pk11wrap/pk11kea.c b/security/nss/lib/pk11wrap/pk11kea.c index 1fcbee70bca..a0db40729f1 100644 --- a/security/nss/lib/pk11wrap/pk11kea.c +++ b/security/nss/lib/pk11wrap/pk11kea.c @@ -42,6 +42,7 @@ #include "secmod.h" #include "nssilock.h" #include "secmodi.h" +#include "secmodti.h" #include "pkcs11.h" #include "pk11func.h" #include "secitem.h" @@ -78,9 +79,9 @@ pk11_KeyExchange(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, { PK11SymKey *newSymKey = NULL; SECStatus rv; - /* performance improvement can go here --- use a generated key to as a - * per startup wrapping key. If it exists, use it, otherwise do a full - * key exchange. */ + /* performance improvement can go here --- use a generated key at startup + * to generate a per token wrapping key. If it exists, use it, otherwise + * do a full key exchange. */ /* find a common Key Exchange algorithm */ /* RSA */ diff --git a/security/nss/lib/pk11wrap/pk11list.c b/security/nss/lib/pk11wrap/pk11list.c index c5fa4973e87..36497654082 100644 --- a/security/nss/lib/pk11wrap/pk11list.c +++ b/security/nss/lib/pk11wrap/pk11list.c @@ -40,10 +40,9 @@ #include "seccomon.h" #include "nssilock.h" -#include "prmon.h" #include "secmod.h" #include "secmodi.h" -#include "prlong.h" +#include "secmodti.h" #define ISREADING 1 #define ISWRITING 2 diff --git a/security/nss/lib/pk11wrap/pk11load.c b/security/nss/lib/pk11wrap/pk11load.c index afe9bd14d2f..602047c4fed 100644 --- a/security/nss/lib/pk11wrap/pk11load.c +++ b/security/nss/lib/pk11wrap/pk11load.c @@ -43,6 +43,7 @@ #include "prlink.h" #include "pk11func.h" #include "secmodi.h" +#include "secmodti.h" #include "nssilock.h" extern void FC_GetFunctionList(void); diff --git a/security/nss/lib/pk11wrap/pk11mech.c b/security/nss/lib/pk11wrap/pk11mech.c new file mode 100644 index 00000000000..2b73ed3baae --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11mech.c @@ -0,0 +1,1787 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file maps various PKCS #11 Mechanisms to related mechanisms, key + * types, and ASN.1 encodings. + */ +#include "seccomon.h" +#include "secmod.h" +#include "secmodi.h" +#include "pkcs11t.h" +#include "pk11func.h" +#include "secitem.h" +#include "secder.h" +#include "secasn1.h" +#include "secoid.h" +#include "secerr.h" + +/************************************************************* + * local static and global data + *************************************************************/ + +/* + * Tables used for Extended mechanism mapping (currently not used) + */ +typedef struct { + CK_MECHANISM_TYPE keyGen; + CK_KEY_TYPE keyType; + CK_MECHANISM_TYPE type; + int blockSize; + int iv; +} pk11MechanismData; + +static pk11MechanismData pk11_default = + { CKM_GENERIC_SECRET_KEY_GEN, CKK_GENERIC_SECRET, CKM_FAKE_RANDOM, 8, 8 }; +static pk11MechanismData *pk11_MechanismTable = NULL; +static int pk11_MechTableSize = 0; +static int pk11_MechEntrySize = 0; + +/* + * list of mechanisms we're willing to wrap secret keys with. + * This list is ordered by preference. + */ +CK_MECHANISM_TYPE wrapMechanismList[] = { + CKM_DES3_ECB, + CKM_CAST5_ECB, + CKM_AES_ECB, + CKM_CAST5_ECB, + CKM_DES_ECB, + CKM_KEY_WRAP_LYNKS, + CKM_IDEA_ECB, + CKM_CAST3_ECB, + CKM_CAST_ECB, + CKM_RC5_ECB, + CKM_RC2_ECB, + CKM_CDMF_ECB, + CKM_SKIPJACK_WRAP, +}; + +int wrapMechanismCount = sizeof(wrapMechanismList)/sizeof(wrapMechanismList[0]); + +/********************************************************************* + * Mechanism Mapping functions + *********************************************************************/ + +/* + * lookup an entry in the mechanism table. If none found, return the + * default structure. + */ +static pk11MechanismData * +pk11_lookup(CK_MECHANISM_TYPE type) +{ + int i; + for (i=0; i < pk11_MechEntrySize; i++) { + if (pk11_MechanismTable[i].type == type) { + return (&pk11_MechanismTable[i]); + } + } + return &pk11_default; +} + +/* + * find the best key wrap mechanism for this slot. + */ +CK_MECHANISM_TYPE +PK11_GetBestWrapMechanism(PK11SlotInfo *slot) +{ + int i; + for (i=0; i < wrapMechanismCount; i++) { + if (PK11_DoesMechanism(slot,wrapMechanismList[i])) { + return wrapMechanismList[i]; + } + } + return CKM_INVALID_MECHANISM; +} + +/* + * NOTE: This is not thread safe. Called at init time, and when loading + * a new Entry. It is reasonably safe as long as it is not re-entered + * (readers will always see a consistant table) + * + * This routine is called to add entries to the mechanism table, once there, + * they can not be removed. + */ +void +PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key, + CK_MECHANISM_TYPE keyGen, int ivLen, int blockSize) +{ + int tableSize = pk11_MechTableSize; + int size = pk11_MechEntrySize; + int entry = size++; + pk11MechanismData *old = pk11_MechanismTable; + pk11MechanismData *newt = pk11_MechanismTable; + + + if (size > tableSize) { + int oldTableSize = tableSize; + tableSize += 10; + newt = PORT_NewArray(pk11MechanismData, tableSize); + if (newt == NULL) return; + + if (old) PORT_Memcpy(newt, old, oldTableSize*sizeof(*newt)); + } else old = NULL; + + newt[entry].type = type; + newt[entry].keyType = key; + newt[entry].keyGen = keyGen; + newt[entry].iv = ivLen; + newt[entry].blockSize = blockSize; + + pk11_MechanismTable = newt; + pk11_MechTableSize = tableSize; + pk11_MechEntrySize = size; + if (old) PORT_Free(old); +} + +/* + * Get the key type needed for the given mechanism + */ +CK_MECHANISM_TYPE +PK11_GetKeyMechanism(CK_KEY_TYPE type) +{ + switch (type) { + case CKK_AES: + return CKM_AES_CBC; + case CKK_DES: + return CKM_DES_CBC; + case CKK_DES3: + return CKM_DES3_KEY_GEN; + case CKK_DES2: + return CKM_DES2_KEY_GEN; + case CKK_CDMF: + return CKM_CDMF_CBC; + case CKK_RC2: + return CKM_RC2_CBC; + case CKK_RC4: + return CKM_RC4; + case CKK_RC5: + return CKM_RC5_CBC; + case CKK_SKIPJACK: + return CKM_SKIPJACK_CBC64; + case CKK_BATON: + return CKM_BATON_CBC128; + case CKK_JUNIPER: + return CKM_JUNIPER_CBC128; + case CKK_IDEA: + return CKM_IDEA_CBC; + case CKK_CAST: + return CKM_CAST_CBC; + case CKK_CAST3: + return CKM_CAST3_CBC; + case CKK_CAST5: + return CKM_CAST5_CBC; + case CKK_RSA: + return CKM_RSA_PKCS; + case CKK_DSA: + return CKM_DSA; + case CKK_DH: + return CKM_DH_PKCS_DERIVE; + case CKK_KEA: + return CKM_KEA_KEY_DERIVE; + case CKK_EC: /* CKK_ECDSA is deprecated */ + return CKM_ECDSA; + case CKK_GENERIC_SECRET: + default: + return CKM_SHA_1_HMAC; + } +} + +/* + * Get the key type needed for the given mechanism + */ +CK_MECHANISM_TYPE +PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len) +{ + switch (type) { + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + case CKM_AES_CBC_PAD: + case CKM_AES_KEY_GEN: + case CKM_NETSCAPE_AES_KEY_WRAP: + case CKM_NETSCAPE_AES_KEY_WRAP_PAD: + return CKK_AES; + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES_MAC: + case CKM_DES_MAC_GENERAL: + case CKM_DES_CBC_PAD: + case CKM_DES_KEY_GEN: + case CKM_KEY_WRAP_LYNKS: + case CKM_PBE_MD2_DES_CBC: + case CKM_PBE_MD5_DES_CBC: + return CKK_DES; + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + case CKM_DES3_CBC_PAD: + return (len == 16) ? CKK_DES2 : CKK_DES3; + case CKM_DES2_KEY_GEN: + case CKM_PBE_SHA1_DES2_EDE_CBC: + return CKK_DES2; + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_DES3_KEY_GEN: + return CKK_DES3; + case CKM_CDMF_ECB: + case CKM_CDMF_CBC: + case CKM_CDMF_MAC: + case CKM_CDMF_MAC_GENERAL: + case CKM_CDMF_CBC_PAD: + case CKM_CDMF_KEY_GEN: + return CKK_CDMF; + case CKM_RC2_ECB: + case CKM_RC2_CBC: + case CKM_RC2_MAC: + case CKM_RC2_MAC_GENERAL: + case CKM_RC2_CBC_PAD: + case CKM_RC2_KEY_GEN: + case CKM_PBE_SHA1_RC2_128_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + return CKK_RC2; + case CKM_RC4: + case CKM_RC4_KEY_GEN: + return CKK_RC4; + case CKM_RC5_ECB: + case CKM_RC5_CBC: + case CKM_RC5_MAC: + case CKM_RC5_MAC_GENERAL: + case CKM_RC5_CBC_PAD: + case CKM_RC5_KEY_GEN: + return CKK_RC5; + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_SKIPJACK_KEY_GEN: + case CKM_SKIPJACK_WRAP: + case CKM_SKIPJACK_PRIVATE_WRAP: + return CKK_SKIPJACK; + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_BATON_WRAP: + case CKM_BATON_KEY_GEN: + return CKK_BATON; + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + case CKM_JUNIPER_WRAP: + case CKM_JUNIPER_KEY_GEN: + return CKK_JUNIPER; + case CKM_IDEA_CBC: + case CKM_IDEA_ECB: + case CKM_IDEA_MAC: + case CKM_IDEA_MAC_GENERAL: + case CKM_IDEA_CBC_PAD: + case CKM_IDEA_KEY_GEN: + return CKK_IDEA; + case CKM_CAST_ECB: + case CKM_CAST_CBC: + case CKM_CAST_MAC: + case CKM_CAST_MAC_GENERAL: + case CKM_CAST_CBC_PAD: + case CKM_CAST_KEY_GEN: + case CKM_PBE_MD5_CAST_CBC: + return CKK_CAST; + case CKM_CAST3_ECB: + case CKM_CAST3_CBC: + case CKM_CAST3_MAC: + case CKM_CAST3_MAC_GENERAL: + case CKM_CAST3_CBC_PAD: + case CKM_CAST3_KEY_GEN: + case CKM_PBE_MD5_CAST3_CBC: + return CKK_CAST3; + case CKM_CAST5_ECB: + case CKM_CAST5_CBC: + case CKM_CAST5_MAC: + case CKM_CAST5_MAC_GENERAL: + case CKM_CAST5_CBC_PAD: + case CKM_CAST5_KEY_GEN: + case CKM_PBE_MD5_CAST5_CBC: + return CKK_CAST5; + case CKM_RSA_PKCS: + case CKM_RSA_9796: + case CKM_RSA_X_509: + case CKM_MD2_RSA_PKCS: + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_KEY_WRAP_SET_OAEP: + case CKM_RSA_PKCS_KEY_PAIR_GEN: + return CKK_RSA; + case CKM_DSA: + case CKM_DSA_SHA1: + case CKM_DSA_KEY_PAIR_GEN: + return CKK_DSA; + case CKM_DH_PKCS_DERIVE: + case CKM_DH_PKCS_KEY_PAIR_GEN: + return CKK_DH; + case CKM_KEA_KEY_DERIVE: + case CKM_KEA_KEY_PAIR_GEN: + return CKK_KEA; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ + case CKM_ECDH1_DERIVE: + return CKK_EC; /* CKK_ECDSA is deprecated */ + 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_TLS_MASTER_KEY_DERIVE_DH: + case CKM_TLS_KEY_AND_MAC_DERIVE: + case CKM_SHA_1_HMAC: + case CKM_SHA_1_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: + return CKK_GENERIC_SECRET; + default: + return pk11_lookup(type)->keyType; + } +} + +/* + * Get the Key Gen Mechanism needed for the given + * crypto mechanism + */ +CK_MECHANISM_TYPE +PK11_GetKeyGen(CK_MECHANISM_TYPE type) +{ + return PK11_GetKeyGenWithSize(type, 0); +} + +CK_MECHANISM_TYPE +PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size) +{ + switch (type) { + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_AES_MAC: + case CKM_AES_MAC_GENERAL: + case CKM_AES_CBC_PAD: + case CKM_AES_KEY_GEN: + return CKM_AES_KEY_GEN; + case CKM_DES_ECB: + case CKM_DES_CBC: + case CKM_DES_MAC: + case CKM_DES_MAC_GENERAL: + case CKM_KEY_WRAP_LYNKS: + case CKM_DES_CBC_PAD: + case CKM_DES_KEY_GEN: + return CKM_DES_KEY_GEN; + case CKM_DES3_ECB: + case CKM_DES3_CBC: + case CKM_DES3_MAC: + case CKM_DES3_MAC_GENERAL: + case CKM_DES3_CBC_PAD: + return (size == 16) ? CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN; + case CKM_DES3_KEY_GEN: + return CKM_DES3_KEY_GEN; + case CKM_DES2_KEY_GEN: + return CKM_DES2_KEY_GEN; + case CKM_CDMF_ECB: + case CKM_CDMF_CBC: + case CKM_CDMF_MAC: + case CKM_CDMF_MAC_GENERAL: + case CKM_CDMF_CBC_PAD: + case CKM_CDMF_KEY_GEN: + return CKM_CDMF_KEY_GEN; + case CKM_RC2_ECB: + case CKM_RC2_CBC: + case CKM_RC2_MAC: + case CKM_RC2_MAC_GENERAL: + case CKM_RC2_CBC_PAD: + case CKM_RC2_KEY_GEN: + return CKM_RC2_KEY_GEN; + case CKM_RC4: + case CKM_RC4_KEY_GEN: + return CKM_RC4_KEY_GEN; + case CKM_RC5_ECB: + case CKM_RC5_CBC: + case CKM_RC5_MAC: + case CKM_RC5_MAC_GENERAL: + case CKM_RC5_CBC_PAD: + case CKM_RC5_KEY_GEN: + return CKM_RC5_KEY_GEN; + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_SKIPJACK_WRAP: + case CKM_SKIPJACK_KEY_GEN: + return CKM_SKIPJACK_KEY_GEN; + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_BATON_WRAP: + case CKM_BATON_KEY_GEN: + return CKM_BATON_KEY_GEN; + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + case CKM_JUNIPER_WRAP: + case CKM_JUNIPER_KEY_GEN: + return CKM_JUNIPER_KEY_GEN; + case CKM_IDEA_CBC: + case CKM_IDEA_ECB: + case CKM_IDEA_MAC: + case CKM_IDEA_MAC_GENERAL: + case CKM_IDEA_CBC_PAD: + case CKM_IDEA_KEY_GEN: + return CKM_IDEA_KEY_GEN; + case CKM_CAST_ECB: + case CKM_CAST_CBC: + case CKM_CAST_MAC: + case CKM_CAST_MAC_GENERAL: + case CKM_CAST_CBC_PAD: + case CKM_CAST_KEY_GEN: + return CKM_CAST_KEY_GEN; + case CKM_CAST3_ECB: + case CKM_CAST3_CBC: + case CKM_CAST3_MAC: + case CKM_CAST3_MAC_GENERAL: + case CKM_CAST3_CBC_PAD: + case CKM_CAST3_KEY_GEN: + return CKM_CAST3_KEY_GEN; + case CKM_CAST5_ECB: + case CKM_CAST5_CBC: + case CKM_CAST5_MAC: + case CKM_CAST5_MAC_GENERAL: + case CKM_CAST5_CBC_PAD: + case CKM_CAST5_KEY_GEN: + return CKM_CAST5_KEY_GEN; + case CKM_RSA_PKCS: + case CKM_RSA_9796: + case CKM_RSA_X_509: + case CKM_MD2_RSA_PKCS: + case CKM_MD5_RSA_PKCS: + case CKM_SHA1_RSA_PKCS: + case CKM_SHA256_RSA_PKCS: + case CKM_SHA384_RSA_PKCS: + case CKM_SHA512_RSA_PKCS: + case CKM_KEY_WRAP_SET_OAEP: + case CKM_RSA_PKCS_KEY_PAIR_GEN: + return CKM_RSA_PKCS_KEY_PAIR_GEN; + case CKM_DSA: + case CKM_DSA_SHA1: + case CKM_DSA_KEY_PAIR_GEN: + return CKM_DSA_KEY_PAIR_GEN; + case CKM_DH_PKCS_DERIVE: + case CKM_DH_PKCS_KEY_PAIR_GEN: + return CKM_DH_PKCS_KEY_PAIR_GEN; + case CKM_KEA_KEY_DERIVE: + case CKM_KEA_KEY_PAIR_GEN: + return CKM_KEA_KEY_PAIR_GEN; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ + case CKM_ECDH1_DERIVE: + 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: + return CKM_SSL3_PRE_MASTER_KEY_GEN; + case CKM_SHA_1_HMAC: + case CKM_SHA_1_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_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: + 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: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + case CKM_PBE_SHA1_RC2_128_CBC: + case CKM_PBE_SHA1_RC4_40: + case CKM_PBE_SHA1_RC4_128: + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_PBE_SHA1_DES2_EDE_CBC: + return type; + default: + return pk11_lookup(type)->keyGen; + } +} + +/* + * get the mechanism block size + */ +int +PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params) +{ + CK_RC5_PARAMS *rc5_params; + CK_RC5_CBC_PARAMS *rc5_cbc_params; + switch (type) { + case CKM_RC5_ECB: + if ((params) && (params->data)) { + rc5_params = (CK_RC5_PARAMS *) params->data; + return (rc5_params->ulWordsize)*2; + } + return 8; + case CKM_RC5_CBC: + case CKM_RC5_CBC_PAD: + if ((params) && (params->data)) { + rc5_cbc_params = (CK_RC5_CBC_PARAMS *) params->data; + return (rc5_cbc_params->ulWordsize)*2; + } + return 8; + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_RC2_ECB: + case CKM_IDEA_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + case CKM_RC2_CBC: + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_RC2_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + case CKM_PBE_MD2_DES_CBC: + case CKM_PBE_MD5_DES_CBC: + 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: + case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + case CKM_PBE_SHA1_RC2_128_CBC: + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_PBE_SHA1_DES2_EDE_CBC: + return 8; + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + return 4; + case CKM_AES_ECB: + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + case CKM_BATON_ECB128: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + return 16; + case CKM_BATON_ECB96: + return 12; + case CKM_RC4: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: + case CKM_PBE_SHA1_RC4_40: + case CKM_PBE_SHA1_RC4_128: + return 0; + case CKM_RSA_PKCS: + case CKM_RSA_9796: + case CKM_RSA_X_509: + /*actually it's the modulus length of the key!*/ + return -1; /* failure */ + default: + return pk11_lookup(type)->blockSize; + } +} + +/* + * get the iv length + */ +int +PK11_GetIVLength(CK_MECHANISM_TYPE type) +{ + switch (type) { + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_RC2_ECB: + case CKM_IDEA_ECB: + case CKM_SKIPJACK_WRAP: + case CKM_BATON_WRAP: + case CKM_RC5_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + return 0; + case CKM_RC2_CBC: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_PBE_MD2_DES_CBC: + case CKM_PBE_MD5_DES_CBC: + 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: + case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + case CKM_PBE_SHA1_RC2_128_CBC: + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_PBE_SHA1_DES2_EDE_CBC: + case CKM_RC5_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_RC2_CBC_PAD: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_RC5_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + return 8; + case CKM_AES_CBC: + case CKM_AES_CBC_PAD: + return 16; + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + return 24; + case CKM_RC4: + case CKM_RSA_PKCS: + case CKM_RSA_9796: + case CKM_RSA_X_509: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: + case CKM_PBE_SHA1_RC4_40: + case CKM_PBE_SHA1_RC4_128: + return 0; + default: + return pk11_lookup(type)->iv; + } +} + + +/* These next two utilities are here to help facilitate future + * Dynamic Encrypt/Decrypt symetric key mechanisms, and to allow functions + * like SSL and S-MIME to automatically add them. + */ +SECItem * +PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv) +{ + CK_RC2_CBC_PARAMS *rc2_params = NULL; + CK_RC2_PARAMS *rc2_ecb_params = NULL; + CK_RC5_PARAMS *rc5_params = NULL; + CK_RC5_CBC_PARAMS *rc5_cbc_params = NULL; + SECItem *param; + + param = (SECItem *)PORT_Alloc(sizeof(SECItem)); + if (param == NULL) return NULL; + param->data = NULL; + param->len = 0; + param->type = 0; + switch (type) { + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_RSA_PKCS: + case CKM_RSA_X_509: + case CKM_RSA_9796: + case CKM_IDEA_ECB: + case CKM_CDMF_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + case CKM_RC4: + break; + case CKM_RC2_ECB: + rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); + if (rc2_ecb_params == NULL) break; + /* Maybe we should pass the key size in too to get this value? */ + *rc2_ecb_params = 128; + param->data = (unsigned char *) rc2_ecb_params; + param->len = sizeof(CK_RC2_PARAMS); + break; + case CKM_RC2_CBC: + case CKM_RC2_CBC_PAD: + rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); + if (rc2_params == NULL) break; + /* Maybe we should pass the key size in too to get this value? */ + rc2_params->ulEffectiveBits = 128; + if (iv && iv->data) + PORT_Memcpy(rc2_params->iv,iv->data,sizeof(rc2_params->iv)); + param->data = (unsigned char *) rc2_params; + param->len = sizeof(CK_RC2_CBC_PARAMS); + break; + case CKM_RC5_CBC: + case CKM_RC5_CBC_PAD: + rc5_cbc_params = (CK_RC5_CBC_PARAMS *) + PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + ((iv) ? iv->len : 0)); + if (rc5_cbc_params == NULL) break; + if (iv && iv->data) { + rc5_cbc_params->pIv = ((CK_BYTE_PTR) rc5_cbc_params) + + sizeof(CK_RC5_CBC_PARAMS); + PORT_Memcpy(rc5_cbc_params->pIv,iv->data,iv->len); + rc5_cbc_params->ulIvLen = iv->len; + rc5_cbc_params->ulWordsize = iv->len/2; + } else { + rc5_cbc_params->ulWordsize = 4; + rc5_cbc_params->pIv = NULL; + rc5_cbc_params->ulIvLen = iv->len; + } + rc5_cbc_params->ulRounds = 16; + param->data = (unsigned char *) rc5_cbc_params; + param->len = sizeof(CK_RC5_CBC_PARAMS); + break; + case CKM_RC5_ECB: + rc5_params = (CK_RC5_PARAMS *)PORT_Alloc(sizeof(CK_RC5_PARAMS)); + if (rc5_params == NULL) break; + if (iv && iv->data && iv->len) { + rc5_params->ulWordsize = iv->len/2; + } else { + rc5_params->ulWordsize = 4; + } + rc5_params->ulRounds = 16; + param->data = (unsigned char *) rc5_params; + param->len = sizeof(CK_RC5_PARAMS); + break; + case CKM_AES_CBC: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_CDMF_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_CDMF_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + if ((iv == NULL) || (iv->data == NULL)) break; + param->data = (unsigned char*)PORT_Alloc(iv->len); + if (param->data != NULL) { + PORT_Memcpy(param->data,iv->data,iv->len); + param->len = iv->len; + } + break; + /* unknown mechanism, pass IV in if it's there */ + default: + if (pk11_lookup(type)->iv == 0) { + break; + } + if ((iv == NULL) || (iv->data == NULL)) { + break; + } + param->data = (unsigned char*)PORT_Alloc(iv->len); + if (param->data != NULL) { + PORT_Memcpy(param->data,iv->data,iv->len); + param->len = iv->len; + } + break; + } + return param; +} + +unsigned char * +PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len) +{ + CK_RC2_CBC_PARAMS *rc2_params; + CK_RC5_CBC_PARAMS *rc5_cbc_params; + + *len = 0; + switch (type) { + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_RSA_PKCS: + case CKM_RSA_X_509: + case CKM_RSA_9796: + case CKM_IDEA_ECB: + case CKM_CDMF_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + case CKM_RC4: + return NULL; + case CKM_RC2_ECB: + return NULL; + case CKM_RC2_CBC: + case CKM_RC2_CBC_PAD: + rc2_params = (CK_RC2_CBC_PARAMS *)param->data; + *len = sizeof(rc2_params->iv); + return &rc2_params->iv[0]; + case CKM_RC5_CBC: + case CKM_RC5_CBC_PAD: + rc5_cbc_params = (CK_RC5_CBC_PARAMS *) param->data; + *len = rc5_cbc_params->ulIvLen; + return rc5_cbc_params->pIv; + case CKM_AES_CBC: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_CDMF_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_CDMF_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + break; + /* unknown mechanism, pass IV in if it's there */ + default: + break; + } + if (param->data) { + *len = param->len; + } + return param->data; +} + +typedef struct sec_rc5cbcParameterStr { + SECItem version; + SECItem rounds; + SECItem blockSizeInBits; + SECItem iv; +} sec_rc5cbcParameter; + +static const SEC_ASN1Template sec_rc5ecb_parameter_template[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(sec_rc5cbcParameter) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc5cbcParameter,version) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc5cbcParameter,rounds) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc5cbcParameter,blockSizeInBits) }, + { 0 } +}; + +static const SEC_ASN1Template sec_rc5cbc_parameter_template[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(sec_rc5cbcParameter) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc5cbcParameter,version) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc5cbcParameter,rounds) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc5cbcParameter,blockSizeInBits) }, + { SEC_ASN1_OCTET_STRING, + offsetof(sec_rc5cbcParameter,iv) }, + { 0 } +}; + +typedef struct sec_rc2cbcParameterStr { + SECItem rc2ParameterVersion; + SECItem iv; +} sec_rc2cbcParameter; + +static const SEC_ASN1Template sec_rc2cbc_parameter_template[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(sec_rc2cbcParameter) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, + { SEC_ASN1_OCTET_STRING, + offsetof(sec_rc2cbcParameter,iv) }, + { 0 } +}; + +static const SEC_ASN1Template sec_rc2ecb_parameter_template[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(sec_rc2cbcParameter) }, + { SEC_ASN1_INTEGER, + offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, + { 0 } +}; + +/* S/MIME picked id values to represent differnt keysizes */ +/* I do have a formula, but it ain't pretty, and it only works because you + * can always match three points to a parabola:) */ +static unsigned char rc2_map(SECItem *version) +{ + long x; + + x = DER_GetInteger(version); + + switch (x) { + case 58: return 128; + case 120: return 64; + case 160: return 40; + } + return 128; +} + +static unsigned long rc2_unmap(unsigned long x) +{ + switch (x) { + case 128: return 58; + case 64: return 120; + case 40: return 160; + } + return 58; +} + + + +/* Generate a mechaism param from a type, and iv. */ +SECItem * +PK11_ParamFromAlgid(SECAlgorithmID *algid) +{ + CK_RC2_CBC_PARAMS * rc2_cbc_params = NULL; + CK_RC2_PARAMS * rc2_ecb_params = NULL; + CK_RC5_CBC_PARAMS * rc5_cbc_params = NULL; + CK_RC5_PARAMS * rc5_ecb_params = NULL; + PRArenaPool * arena = NULL; + SECItem * mech = NULL; + SECOidTag algtag; + SECStatus rv; + CK_MECHANISM_TYPE type; + /* initialize these to prevent UMRs in the ASN1 decoder. */ + SECItem iv = {siBuffer, NULL, 0}; + sec_rc2cbcParameter rc2 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; + sec_rc5cbcParameter rc5 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}, + {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; + + algtag = SECOID_GetAlgorithmTag(algid); + type = PK11_AlgtagToMechanism(algtag); + + mech = PORT_New(SECItem); + if (mech == NULL) { + return NULL; + } + mech->type = siBuffer; + mech->data = NULL; + mech->len = 0; + + arena = PORT_NewArena(1024); + if (!arena) { + goto loser; + } + + /* handle the complicated cases */ + switch (type) { + case CKM_RC2_ECB: + rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2ecb_parameter_template, + &(algid->parameters)); + if (rv != SECSuccess) { + goto loser; + } + rc2_ecb_params = PORT_New(CK_RC2_PARAMS); + if (rc2_ecb_params == NULL) { + goto loser; + } + *rc2_ecb_params = rc2_map(&rc2.rc2ParameterVersion); + mech->data = (unsigned char *) rc2_ecb_params; + mech->len = sizeof *rc2_ecb_params; + break; + case CKM_RC2_CBC: + case CKM_RC2_CBC_PAD: + rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2cbc_parameter_template, + &(algid->parameters)); + if (rv != SECSuccess) { + goto loser; + } + rc2_cbc_params = PORT_New(CK_RC2_CBC_PARAMS); + if (rc2_cbc_params == NULL) { + goto loser; + } + mech->data = (unsigned char *) rc2_cbc_params; + mech->len = sizeof *rc2_cbc_params; + rc2_cbc_params->ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); + if (rc2.iv.len != sizeof rc2_cbc_params->iv) { + PORT_SetError(SEC_ERROR_INPUT_LEN); + goto loser; + } + PORT_Memcpy(rc2_cbc_params->iv, rc2.iv.data, rc2.iv.len); + break; + case CKM_RC5_ECB: + rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5ecb_parameter_template, + &(algid->parameters)); + if (rv != SECSuccess) { + goto loser; + } + rc5_ecb_params = PORT_New(CK_RC5_PARAMS); + if (rc5_ecb_params == NULL) { + goto loser; + } + rc5_ecb_params->ulRounds = DER_GetInteger(&rc5.rounds); + rc5_ecb_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; + mech->data = (unsigned char *) rc5_ecb_params; + mech->len = sizeof *rc5_ecb_params; + break; + case CKM_RC5_CBC: + case CKM_RC5_CBC_PAD: + rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5cbc_parameter_template, + &(algid->parameters)); + if (rv != SECSuccess) { + goto loser; + } + rc5_cbc_params = (CK_RC5_CBC_PARAMS *) + PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + rc5.iv.len); + if (rc5_cbc_params == NULL) { + goto loser; + } + mech->data = (unsigned char *) rc5_cbc_params; + mech->len = sizeof *rc5_cbc_params; + rc5_cbc_params->ulRounds = DER_GetInteger(&rc5.rounds); + rc5_cbc_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; + rc5_cbc_params->pIv = ((CK_BYTE_PTR)rc5_cbc_params) + + sizeof(CK_RC5_CBC_PARAMS); + rc5_cbc_params->ulIvLen = rc5.iv.len; + PORT_Memcpy(rc5_cbc_params->pIv, rc5.iv.data, rc5.iv.len); + break; + case CKM_PBE_MD2_DES_CBC: + case CKM_PBE_MD5_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: + case CKM_PBE_SHA1_DES2_EDE_CBC: + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + case CKM_PBE_SHA1_RC2_128_CBC: + case CKM_PBE_SHA1_RC4_40: + case CKM_PBE_SHA1_RC4_128: + rv = pbe_PK11AlgidToParam(algid,mech); + if (rv != SECSuccess) { + goto loser; + } + break; + case CKM_RC4: + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_IDEA_ECB: + case CKM_CDMF_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + break; + + default: + if (pk11_lookup(type)->iv == 0) { + break; + } + /* FALL THROUGH */ + case CKM_AES_CBC: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_CDMF_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_AES_CBC_PAD: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_CDMF_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + /* simple cases are simply octet string encoded IVs */ + rv = SEC_ASN1DecodeItem(arena, &iv, SEC_OctetStringTemplate, + &(algid->parameters)); + if (rv != SECSuccess || iv.data == NULL) { + goto loser; + } + /* XXX Should be some IV length sanity check here. */ + mech->data = (unsigned char*)PORT_Alloc(iv.len); + if (mech->data == NULL) { + goto loser; + } + PORT_Memcpy(mech->data, iv.data, iv.len); + mech->len = iv.len; + break; + } + PORT_FreeArena(arena, PR_FALSE); + return mech; + +loser: + if (arena) + PORT_FreeArena(arena, PR_FALSE); + SECITEM_FreeItem(mech,PR_TRUE); + return NULL; +} + +/* + * Generate an IV for the given mechanism + */ +static SECStatus +pk11_GenIV(CK_MECHANISM_TYPE type, SECItem *iv) { + int iv_size = PK11_GetIVLength(type); + SECStatus rv; + + iv->len = iv_size; + if (iv_size == 0) { + iv->data = NULL; + return SECSuccess; + } + + iv->data = (unsigned char *) PORT_Alloc(iv_size); + if (iv->data == NULL) { + iv->len = 0; + return SECFailure; + } + + rv = PK11_GenerateRandom(iv->data,iv->len); + if (rv != SECSuccess) { + PORT_Free(iv->data); + iv->data = NULL; iv->len = 0; + return SECFailure; + } + return SECSuccess; +} + + +/* + * create a new paramter block from the passed in MECHANISM and the + * key. Use Netscape's S/MIME Rules for the New param block. + */ +SECItem * +PK11_GenerateNewParam(CK_MECHANISM_TYPE type, PK11SymKey *key) { + CK_RC2_CBC_PARAMS *rc2_params; + CK_RC2_PARAMS *rc2_ecb_params; + SECItem *mech; + SECItem iv; + SECStatus rv; + + + mech = (SECItem *) PORT_Alloc(sizeof(SECItem)); + if (mech == NULL) return NULL; + + rv = SECSuccess; + mech->type = siBuffer; + switch (type) { + case CKM_RC4: + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_IDEA_ECB: + case CKM_CDMF_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + mech->data = NULL; + mech->len = 0; + break; + case CKM_RC2_ECB: + rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); + if (rc2_ecb_params == NULL) { + rv = SECFailure; + break; + } + /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, + * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ + *rc2_ecb_params = PK11_GetKeyLength(key)*8; + mech->data = (unsigned char *) rc2_ecb_params; + mech->len = sizeof(CK_RC2_PARAMS); + break; + case CKM_RC2_CBC: + case CKM_RC2_CBC_PAD: + rv = pk11_GenIV(type,&iv); + if (rv != SECSuccess) { + break; + } + rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); + if (rc2_params == NULL) { + PORT_Free(iv.data); + rv = SECFailure; + break; + } + /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, + * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ + rc2_params->ulEffectiveBits = PK11_GetKeyLength(key)*8; + if (iv.data) + PORT_Memcpy(rc2_params->iv,iv.data,sizeof(rc2_params->iv)); + mech->data = (unsigned char *) rc2_params; + mech->len = sizeof(CK_RC2_CBC_PARAMS); + PORT_Free(iv.data); + break; + case CKM_RC5_ECB: + PORT_Free(mech); + return PK11_ParamFromIV(type,NULL); + case CKM_RC5_CBC: + case CKM_RC5_CBC_PAD: + rv = pk11_GenIV(type,&iv); + if (rv != SECSuccess) { + break; + } + PORT_Free(mech); + return PK11_ParamFromIV(type,&iv); + default: + if (pk11_lookup(type)->iv == 0) { + mech->data = NULL; + mech->len = 0; + break; + } + case CKM_AES_CBC: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_CDMF_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_CDMF_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + rv = pk11_GenIV(type,&iv); + if (rv != SECSuccess) { + break; + } + mech->data = (unsigned char*)PORT_Alloc(iv.len); + if (mech->data == NULL) { + PORT_Free(iv.data); + rv = SECFailure; + break; + } + PORT_Memcpy(mech->data,iv.data,iv.len); + mech->len = iv.len; + PORT_Free(iv.data); + break; + } + if (rv != SECSuccess) { + SECITEM_FreeItem(mech,PR_TRUE); + return NULL; + } + return mech; + +} + +#define RC5_V10 0x10 + +/* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */ +SECStatus +PK11_ParamToAlgid(SECOidTag algTag, SECItem *param, + PRArenaPool *arena, SECAlgorithmID *algid) { + CK_RC2_CBC_PARAMS *rc2_params; + sec_rc2cbcParameter rc2; + CK_RC5_CBC_PARAMS *rc5_params; + sec_rc5cbcParameter rc5; + CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(algTag); + SECItem *newParams = NULL; + SECStatus rv = SECFailure; + unsigned long rc2version; + + rv = SECSuccess; + switch (type) { + case CKM_RC4: + case CKM_AES_ECB: + case CKM_DES_ECB: + case CKM_DES3_ECB: + case CKM_IDEA_ECB: + case CKM_CDMF_ECB: + case CKM_CAST_ECB: + case CKM_CAST3_ECB: + case CKM_CAST5_ECB: + newParams = NULL; + rv = SECSuccess; + break; + case CKM_RC2_ECB: + break; + case CKM_RC2_CBC: + case CKM_RC2_CBC_PAD: + rc2_params = (CK_RC2_CBC_PARAMS *)param->data; + rc2version = rc2_unmap(rc2_params->ulEffectiveBits); + if (SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), + rc2version) == NULL) + break; + rc2.iv.data = rc2_params->iv; + rc2.iv.len = sizeof(rc2_params->iv); + newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc2, + sec_rc2cbc_parameter_template); + PORT_Free(rc2.rc2ParameterVersion.data); + if (newParams == NULL) + break; + rv = SECSuccess; + break; + + case CKM_RC5_ECB: /* well not really... */ + break; + case CKM_RC5_CBC: + case CKM_RC5_CBC_PAD: + rc5_params = (CK_RC5_CBC_PARAMS *)param->data; + if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.version, RC5_V10) == NULL) + break; + if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.blockSizeInBits, + rc5_params->ulWordsize*8) == NULL) { + PORT_Free(rc5.version.data); + break; + } + if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.rounds, + rc5_params->ulWordsize*8) == NULL) { + PORT_Free(rc5.blockSizeInBits.data); + PORT_Free(rc5.version.data); + break; + } + rc5.iv.data = rc5_params->pIv; + rc5.iv.len = rc5_params->ulIvLen; + newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc5, + sec_rc5cbc_parameter_template); + PORT_Free(rc5.version.data); + PORT_Free(rc5.blockSizeInBits.data); + PORT_Free(rc5.rounds.data); + if (newParams == NULL) + break; + rv = SECSuccess; + break; + case CKM_PBE_MD2_DES_CBC: + case CKM_PBE_MD5_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_PBE_SHA1_DES2_EDE_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + case CKM_PBE_SHA1_RC2_128_CBC: + case CKM_PBE_SHA1_RC4_40: + case CKM_PBE_SHA1_RC4_128: + return PBE_PK11ParamToAlgid(algTag, param, arena, algid); + default: + if (pk11_lookup(type)->iv == 0) { + rv = SECSuccess; + newParams = NULL; + break; + } + case CKM_AES_CBC: + case CKM_DES_CBC: + case CKM_DES3_CBC: + case CKM_IDEA_CBC: + case CKM_CDMF_CBC: + case CKM_CAST_CBC: + case CKM_CAST3_CBC: + case CKM_CAST5_CBC: + case CKM_DES_CBC_PAD: + case CKM_DES3_CBC_PAD: + case CKM_IDEA_CBC_PAD: + case CKM_CDMF_CBC_PAD: + case CKM_CAST_CBC_PAD: + case CKM_CAST3_CBC_PAD: + case CKM_CAST5_CBC_PAD: + case CKM_SKIPJACK_CBC64: + case CKM_SKIPJACK_ECB64: + case CKM_SKIPJACK_OFB64: + case CKM_SKIPJACK_CFB64: + case CKM_SKIPJACK_CFB32: + case CKM_SKIPJACK_CFB16: + case CKM_SKIPJACK_CFB8: + case CKM_BATON_ECB128: + case CKM_BATON_ECB96: + case CKM_BATON_CBC128: + case CKM_BATON_COUNTER: + case CKM_BATON_SHUFFLE: + case CKM_JUNIPER_ECB128: + case CKM_JUNIPER_CBC128: + case CKM_JUNIPER_COUNTER: + case CKM_JUNIPER_SHUFFLE: + newParams = SEC_ASN1EncodeItem(NULL,NULL,param, + SEC_OctetStringTemplate); + rv = SECSuccess; + break; + } + + if (rv != SECSuccess) { + if (newParams) SECITEM_FreeItem(newParams,PR_TRUE); + return rv; + } + + rv = SECOID_SetAlgorithmID(arena, algid, algTag, newParams); + SECITEM_FreeItem(newParams,PR_TRUE); + return rv; +} + +/* turn an OID algorithm tag into a PKCS #11 mechanism. This allows us to + * map OID's directly into the PKCS #11 mechanism we want to call. We find + * this mapping in our standard OID table */ +CK_MECHANISM_TYPE +PK11_AlgtagToMechanism(SECOidTag algTag) { + SECOidData *oid = SECOID_FindOIDByTag(algTag); + + if (oid) return (CK_MECHANISM_TYPE) oid->mechanism; + return CKM_INVALID_MECHANISM; +} + +/* turn a mechanism into an oid. */ +SECOidTag +PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type) { + SECOidData *oid = SECOID_FindOIDByMechanism((unsigned long)type); + + if (oid) return oid->offset; + return SEC_OID_UNKNOWN; +} + +/* Determine appropriate blocking mechanism, used when wrapping private keys + * which require PKCS padding. If the mechanism does not map to a padding + * mechanism, we simply return the mechanism. + */ +CK_MECHANISM_TYPE +PK11_GetPadMechanism(CK_MECHANISM_TYPE type) { + switch(type) { + case CKM_AES_CBC: + return CKM_AES_CBC_PAD; + case CKM_DES_CBC: + return CKM_DES_CBC_PAD; + case CKM_DES3_CBC: + return CKM_DES3_CBC_PAD; + case CKM_RC2_CBC: + return CKM_RC2_CBC_PAD; + case CKM_CDMF_CBC: + return CKM_CDMF_CBC_PAD; + case CKM_CAST_CBC: + return CKM_CAST_CBC_PAD; + case CKM_CAST3_CBC: + return CKM_CAST3_CBC_PAD; + case CKM_CAST5_CBC: + return CKM_CAST5_CBC_PAD; + case CKM_RC5_CBC: + return CKM_RC5_CBC_PAD; + case CKM_IDEA_CBC: + return CKM_IDEA_CBC_PAD; + default: + break; + } + + return type; +} + +static PRBool +pk11_isAllZero(unsigned char *data,int len) { + while (len--) { + if (*data++) { + return PR_FALSE; + } + } + return PR_TRUE; +} + +CK_RV +PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, + CK_MECHANISM_PTR pCryptoMechanism, + SECItem *pbe_pwd, PRBool faulty3DES) +{ + int iv_len = 0; + CK_PBE_PARAMS_PTR pPBEparams; + CK_RC2_CBC_PARAMS_PTR rc2_params; + CK_ULONG rc2_key_len; + + if((pPBEMechanism == CK_NULL_PTR) || (pCryptoMechanism == CK_NULL_PTR)) { + return CKR_HOST_MEMORY; + } + + pPBEparams = (CK_PBE_PARAMS_PTR)pPBEMechanism->pParameter; + iv_len = PK11_GetIVLength(pPBEMechanism->mechanism); + + if (iv_len) { + if (pk11_isAllZero(pPBEparams->pInitVector,iv_len)) { + SECItem param; + PK11SymKey *symKey; + PK11SlotInfo *intSlot = PK11_GetInternalSlot(); + + if (intSlot == NULL) { + return CKR_DEVICE_ERROR; + } + + param.data = pPBEMechanism->pParameter; + param.len = pPBEMechanism->ulParameterLen; + + symKey = PK11_RawPBEKeyGen(intSlot, + pPBEMechanism->mechanism, ¶m, pbe_pwd, faulty3DES, NULL); + PK11_FreeSlot(intSlot); + if (symKey== NULL) { + return CKR_DEVICE_ERROR; /* sigh */ + } + PK11_FreeSymKey(symKey); + } + } + + switch(pPBEMechanism->mechanism) { + case CKM_PBE_MD2_DES_CBC: + case CKM_PBE_MD5_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_DES_CBC: + pCryptoMechanism->mechanism = CKM_DES_CBC; + goto have_crypto_mechanism; + case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: + case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: + case CKM_PBE_SHA1_DES3_EDE_CBC: + case CKM_PBE_SHA1_DES2_EDE_CBC: + pCryptoMechanism->mechanism = CKM_DES3_CBC; +have_crypto_mechanism: + pCryptoMechanism->pParameter = PORT_Alloc(iv_len); + pCryptoMechanism->ulParameterLen = (CK_ULONG)iv_len; + if(pCryptoMechanism->pParameter == NULL) { + return CKR_HOST_MEMORY; + } + PORT_Memcpy((unsigned char *)(pCryptoMechanism->pParameter), + (unsigned char *)(pPBEparams->pInitVector), + iv_len); + break; + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: + case CKM_PBE_SHA1_RC4_40: + case CKM_PBE_SHA1_RC4_128: + pCryptoMechanism->mechanism = CKM_RC4; + pCryptoMechanism->ulParameterLen = 0; + pCryptoMechanism->pParameter = CK_NULL_PTR; + break; + case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: + case CKM_PBE_SHA1_RC2_40_CBC: + rc2_key_len = 40; + goto have_key_len; + case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: + rc2_key_len = 128; +have_key_len: + pCryptoMechanism->mechanism = CKM_RC2_CBC; + pCryptoMechanism->ulParameterLen = (CK_ULONG) + sizeof(CK_RC2_CBC_PARAMS); + pCryptoMechanism->pParameter = (CK_RC2_CBC_PARAMS_PTR) + PORT_ZAlloc(sizeof(CK_RC2_CBC_PARAMS)); + if(pCryptoMechanism->pParameter == NULL) { + return CKR_HOST_MEMORY; + } + rc2_params = (CK_RC2_CBC_PARAMS_PTR)pCryptoMechanism->pParameter; + PORT_Memcpy((unsigned char *)rc2_params->iv, + (unsigned char *)pPBEparams->pInitVector, + iv_len); + rc2_params->ulEffectiveBits = rc2_key_len; + break; + default: + return CKR_MECHANISM_INVALID; + } + + return CKR_OK; +} + +/* Make a Key type to an appropriate signing/verification mechanism */ +CK_MECHANISM_TYPE +pk11_mapSignKeyType(KeyType keyType) +{ + switch (keyType) { + case rsaKey: + return CKM_RSA_PKCS; + case fortezzaKey: + case dsaKey: + return CKM_DSA; +#ifdef NSS_ENABLE_ECC + case ecKey: + return CKM_ECDSA; +#endif /* NSS_ENABLE_ECC */ + case dhKey: + default: + break; + } + return CKM_INVALID_MECHANISM; +} + +CK_MECHANISM_TYPE +pk11_mapWrapKeyType(KeyType keyType) +{ + switch (keyType) { + case rsaKey: + return CKM_RSA_PKCS; + /* Add fortezza?? */ + default: + break; + } + return CKM_INVALID_MECHANISM; +} + +SECOidTag +PK11_FortezzaMapSig(SECOidTag algTag) +{ + switch (algTag) { + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_DSS: + case SEC_OID_MISSI_DSS_OLD: + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: + return SEC_OID_ANSIX9_DSA_SIGNATURE; + default: + break; + } + return algTag; +} diff --git a/security/nss/lib/pk11wrap/pk11nobj.c b/security/nss/lib/pk11wrap/pk11nobj.c new file mode 100644 index 00000000000..8b8fd5c0552 --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11nobj.c @@ -0,0 +1,796 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects, + * etc). + */ + +#include "secport.h" +#include "seccomon.h" +#include "secmod.h" +#include "secmodi.h" +#include "secmodti.h" +#include "pkcs11.h" +#include "pk11func.h" +#include "cert.h" +#include "certi.h" +#include "secitem.h" +#include "sechash.h" +#include "secoid.h" + +#include "certdb.h" +#include "secerr.h" +#include "sslerr.h" + +#ifndef NSS_3_4_CODE +#define NSS_3_4_CODE +#endif /* NSS_3_4_CODE */ +#include "pki3hack.h" +#include "dev3hack.h" + +#include "devm.h" +#include "pki.h" +#include "pkim.h" + +CK_TRUST +pk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena, + CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type) +{ + CK_TRUST rv = 0; + SECItem item; + + item.data = NULL; + item.len = 0; + + if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) { + PORT_Assert(item.len == sizeof(CK_TRUST)); + PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST)); + /* Damn, is there an endian problem here? */ + return rv; + } + + return 0; +} + +PRBool +pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust) +{ + PRArenaPool *arena; + + CK_ATTRIBUTE tobjTemplate[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_CERT_SHA1_HASH, NULL, 0 }, + }; + + CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; + CK_OBJECT_HANDLE tobjID; + unsigned char sha1_hash[SHA1_LENGTH]; + + CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth; + + PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len); + + PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc)); + PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, + SHA1_LENGTH); + + tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, + sizeof(tobjTemplate)/sizeof(tobjTemplate[0])); + if( CK_INVALID_HANDLE == tobjID ) { + return PR_FALSE; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if( NULL == arena ) return PR_FALSE; + + /* Unfortunately, it seems that PK11_GetAttributes doesn't deal + * well with nonexistant attributes. I guess we have to check + * the trust info fields one at a time. + */ + + /* We could verify CKA_CERT_HASH here */ + + /* We could verify CKA_EXPIRES here */ + + + /* "Purpose" trust information */ + serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH); + clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH); + codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING); + emailProtection = pk11_GetTrustField(slot, arena, tobjID, + CKA_TRUST_EMAIL_PROTECTION); + /* Here's where the fun logic happens. We have to map back from the + * key usage, extended key usage, purpose, and possibly other trust values + * into the old trust-flags bits. */ + + /* First implementation: keep it simple for testing. We can study what other + * mappings would be appropriate and add them later.. fgmr 20000724 */ + + if ( serverAuth == CKT_NETSCAPE_TRUSTED ) { + trust->sslFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; + } + + if ( serverAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { + trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | + CERTDB_NS_TRUSTED_CA; + } + if ( clientAuth == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { + trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA ; + } + + if ( emailProtection == CKT_NETSCAPE_TRUSTED ) { + trust->emailFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; + } + + if ( emailProtection == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { + trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; + } + + if( codeSigning == CKT_NETSCAPE_TRUSTED ) { + trust->objectSigningFlags |= CERTDB_VALID_PEER | CERTDB_TRUSTED; + } + + if( codeSigning == CKT_NETSCAPE_TRUSTED_DELEGATOR ) { + trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED_CA; + } + + /* There's certainly a lot more logic that can go here.. */ + + PORT_FreeArena(arena, PR_FALSE); + + return PR_TRUE; +} + +static SECStatus +pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg) +{ + SECItem derCrl; + CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg; + CERTCrlNode *new_node = NULL; + CK_ATTRIBUTE fetchCrl[3] = { + { CKA_VALUE, NULL, 0}, + { CKA_NETSCAPE_KRL, NULL, 0}, + { CKA_NETSCAPE_URL, NULL, 0}, + }; + const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); + CK_RV crv; + SECStatus rv = SECFailure; + + crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize); + if (CKR_OK != crv) { + PORT_SetError(PK11_MapError(crv)); + goto loser; + } + + if (!fetchCrl[1].pValue) { + PORT_SetError(SEC_ERROR_CRL_INVALID); + goto loser; + } + + new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode)); + if (new_node == NULL) { + goto loser; + } + + if (*((CK_BBOOL *)fetchCrl[1].pValue)) + new_node->type = SEC_KRL_TYPE; + else + new_node->type = SEC_CRL_TYPE; + + derCrl.type = siBuffer; + derCrl.data = (unsigned char *)fetchCrl[0].pValue; + derCrl.len = fetchCrl[0].ulValueLen; + new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type); + if (new_node->crl == NULL) { + goto loser; + } + + if (fetchCrl[2].pValue) { + int nnlen = fetchCrl[2].ulValueLen; + new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen+1); + if ( !new_node->crl->url ) { + goto loser; + } + PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); + new_node->crl->url[nnlen] = 0; + } else { + new_node->crl->url = NULL; + } + + + new_node->next = NULL; + if (head->last) { + head->last->next = new_node; + head->last = new_node; + } else { + head->first = head->last = new_node; + } + rv = SECSuccess; + +loser: + return(rv); +} + +/* + * Return a list of all the CRLs + */ +SECStatus +PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) { + pk11TraverseSlot creater; + CK_ATTRIBUTE theTemplate[2]; + CK_ATTRIBUTE *attrs; + CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL; + + attrs = theTemplate; + PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++; + if (type != -1) { + CK_BBOOL isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); + PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++; + } + + creater.callback = pk11_CollectCrls; + creater.callbackArg = (void *) nodes; + creater.findTemplate = theTemplate; + creater.templateCount = (attrs - theTemplate); + + return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, wincx); +} + +/* + * return the crl associated with a derSubjectName + */ +SECItem * +PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle, + SECItem *name, int type, char **url) +{ +#ifdef NSS_CLASSIC + CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; + CK_ATTRIBUTE theTemplate[] = { + { CKA_SUBJECT, NULL, 0 }, + { CKA_CLASS, NULL, 0 }, + { CKA_NETSCAPE_KRL, NULL, 0 }, + }; + CK_ATTRIBUTE crlData[] = { + { CKA_VALUE, NULL, 0 }, + { CKA_NETSCAPE_URL, NULL, 0 }, + }; + /* if you change the array, change the variable below as well */ + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); + CK_BBOOL ck_true = CK_TRUE; + CK_BBOOL ck_false = CK_FALSE; + CK_OBJECT_HANDLE crlh = CK_INVALID_HANDLE; + CK_ATTRIBUTE *attrs = theTemplate; + CK_RV crv; + SECItem *derCrl = NULL; + + PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; + PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; + PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, (type == SEC_CRL_TYPE) ? + &ck_false : &ck_true, sizeof (CK_BBOOL)); attrs++; + + if (*slot) { + crlh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); + } else { + PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, + PR_FALSE,PR_TRUE,NULL); + PK11SlotListElement *le; + + /* loop through all the fortezza tokens */ + for (le = list->head; le; le = le->next) { + crlh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); + if (crlh != CK_INVALID_HANDLE) { + *slot = PK11_ReferenceSlot(le->slot); + break; + } + } + PK11_FreeSlotList(list); + } + + if (crlh == CK_INVALID_HANDLE) { + PORT_SetError(SEC_ERROR_NO_KRL); + return NULL; + } + crv = PK11_GetAttributes(NULL,*slot,crlh,crlData,2); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError (crv)); + goto loser; + } + + derCrl = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); + if (derCrl == NULL) { + goto loser; + } + + derCrl->data = crlData[0].pValue; + derCrl->len = crlData[0].ulValueLen; + + if (crlHandle) { + *crlHandle = crlh; + } + + if ((url) && crlData[1].ulValueLen != 0) { + /* make sure it's a null terminated string */ + *url = PORT_ZAlloc (crlData[1].ulValueLen+1); + if (*url) { + PORT_Memcpy(*url,crlData[1].pValue,crlData[1].ulValueLen); + } + } + + +loser: + if (!derCrl) { + if (crlData[0].pValue) PORT_Free(crlData[0].pValue); + } + if (crlData[1].pValue) PORT_Free(crlData[1].pValue); + return derCrl; +#else + NSSCRL **crls, **crlp, *crl; + NSSDER subject; + SECItem *rvItem; + NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); + NSSITEM_FROM_SECITEM(&subject, name); + if (*slot) { + nssCryptokiObject **instances; + nssPKIObjectCollection *collection; + nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; + NSSToken *token = PK11Slot_GetNSSToken(*slot); + collection = nssCRLCollection_Create(td, NULL); + if (!collection) { + return NULL; + } + instances = nssToken_FindCRLsBySubject(token, NULL, &subject, + tokenOnly, 0, NULL); + nssPKIObjectCollection_AddInstances(collection, instances, 0); + nss_ZFreeIf(instances); + crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL); + nssPKIObjectCollection_Destroy(collection); + } else { + crls = nssTrustDomain_FindCRLsBySubject(td, &subject); + } + if ((!crls) || (*crls == NULL)) { + if (crls) { + nssCRLArray_Destroy(crls); + } + if (NSS_GetError() == NSS_ERROR_NOT_FOUND) { + PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); + } + return NULL; + } + crl = NULL; + for (crlp = crls; *crlp; crlp++) { + if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) || + ((*crlp)->isKRL && type != SEC_CRL_TYPE)) + { + crl = nssCRL_AddRef(*crlp); + break; + } + } + nssCRLArray_Destroy(crls); + if (!crl) { + /* CRL collection was found, but no interesting CRL's were on it. + * Not an error */ + PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); + return NULL; + } + if (crl->url) { + *url = PORT_Strdup(crl->url); + if (!*url) { + nssCRL_Destroy(crl); + return NULL; + } + } else { + *url = NULL; + } + rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size); + if (!rvItem) { + PORT_Free(*url); + nssCRL_Destroy(crl); + return NULL; + } + memcpy(rvItem->data, crl->encoding.data, crl->encoding.size); + *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot); + *crlHandle = crl->object.instances[0]->handle; + nssCRL_Destroy(crl); + return rvItem; +#endif +} + +CK_OBJECT_HANDLE +PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name, + char *url, int type) +{ +#ifdef NSS_CLASSIC + CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; + CK_ATTRIBUTE theTemplate[] = { + { CKA_SUBJECT, NULL, 0 }, + { CKA_CLASS, NULL, 0 }, + { CKA_NETSCAPE_KRL, NULL, 0 }, + { CKA_NETSCAPE_URL, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + { CKA_TOKEN, NULL, 0 } + }; + /* if you change the array, change the variable below as well */ + int tsize; + CK_BBOOL ck_true = CK_TRUE; + CK_BBOOL ck_false = CK_FALSE; + CK_OBJECT_HANDLE crlh = CK_INVALID_HANDLE; + CK_ATTRIBUTE *attrs = theTemplate; + CK_SESSION_HANDLE rwsession; + CK_RV crv; + + PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; + PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; + PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, (type == SEC_CRL_TYPE) ? + &ck_false : &ck_true, sizeof (CK_BBOOL)); attrs++; + if (url) { + PK11_SETATTRS(attrs, CKA_NETSCAPE_URL, url, PORT_Strlen(url)+1); attrs++; + } + PK11_SETATTRS(attrs, CKA_VALUE,crl->data,crl->len); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true,sizeof(CK_BBOOL)); attrs++; + + tsize = attrs - &theTemplate[0]; + PORT_Assert(tsize <= sizeof(theTemplate)/sizeof(theTemplate[0])); + + rwsession = PK11_GetRWSession(slot); + if (rwsession == CK_INVALID_SESSION) { + PORT_SetError(SEC_ERROR_READ_ONLY); + return crlh; + } + + crv = PK11_GETTAB(slot)-> + C_CreateObject(rwsession,theTemplate,tsize,&crlh); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + } + + PK11_RestoreROSession(slot,rwsession); + + return crlh; +#else + NSSItem derCRL, derSubject; + NSSToken *token = PK11Slot_GetNSSToken(slot); + nssCryptokiObject *object; + PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE; + CK_OBJECT_HANDLE rvH; + + NSSITEM_FROM_SECITEM(&derSubject, name); + NSSITEM_FROM_SECITEM(&derCRL, crl); + + object = nssToken_ImportCRL(token, NULL, + &derSubject, &derCRL, isKRL, url, PR_TRUE); + + if (object) { + rvH = object->handle; + nssCryptokiObject_Destroy(object); + } else { + rvH = CK_INVALID_HANDLE; + } + return rvH; +#endif +} + + +/* + * delete a crl. + */ +SECStatus +SEC_DeletePermCRL(CERTSignedCrl *crl) +{ +#ifdef NSS_CLASSIC + PK11SlotInfo *slot = crl->slot; + CK_RV crv; + + if (slot == NULL) { + /* shouldn't happen */ + PORT_SetError( SEC_ERROR_CRL_INVALID); + return SECFailure; + } + + crv = PK11_DestroyTokenObject(slot,crl->pkcs11ID); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + crl->slot = NULL; + PK11_FreeSlot(slot); + return SECSuccess; +#else + PRStatus status; + NSSToken *token; + nssCryptokiObject *object; + PK11SlotInfo *slot = crl->slot; + + if (slot == NULL) { + PORT_Assert(slot); + /* shouldn't happen */ + PORT_SetError( SEC_ERROR_CRL_INVALID); + return SECFailure; + } + token = PK11Slot_GetNSSToken(slot); + + object = nss_ZNEW(NULL, nssCryptokiObject); + object->token = nssToken_AddRef(token); + object->handle = crl->pkcs11ID; + object->isTokenObject = PR_TRUE; + + status = nssToken_DeleteStoredObject(object); + + nssCryptokiObject_Destroy(object); + return (status == PR_SUCCESS) ? SECSuccess : SECFailure; +#endif +} + +/* + * return the certificate associated with a derCert + */ +SECItem * +PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr, + SECItem *name, SECItem **profileTime) +{ + CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; + CK_ATTRIBUTE theTemplate[] = { + { CKA_SUBJECT, NULL, 0 }, + { CKA_CLASS, NULL, 0 }, + { CKA_NETSCAPE_EMAIL, NULL, 0 }, + }; + CK_ATTRIBUTE smimeData[] = { + { CKA_SUBJECT, NULL, 0 }, + { CKA_VALUE, NULL, 0 }, + }; + /* if you change the array, change the variable below as well */ + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); + CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; + CK_ATTRIBUTE *attrs = theTemplate; + CK_RV crv; + SECItem *emailProfile = NULL; + + PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; + PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; + PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); + attrs++; + + if (*slot) { + smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); + } else { + PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, + PR_FALSE,PR_TRUE,NULL); + PK11SlotListElement *le; + + /* loop through all the fortezza tokens */ + for (le = list->head; le; le = le->next) { + smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); + if (smimeh != CK_INVALID_HANDLE) { + *slot = PK11_ReferenceSlot(le->slot); + break; + } + } + PK11_FreeSlotList(list); + } + + if (smimeh == CK_INVALID_HANDLE) { + PORT_SetError(SEC_ERROR_NO_KRL); + return NULL; + } + + if (profileTime) { + PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0); + } + + crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError (crv)); + goto loser; + } + + if (!profileTime) { + SECItem profileSubject; + + profileSubject.data = (unsigned char*) smimeData[0].pValue; + profileSubject.len = smimeData[0].ulValueLen; + if (!SECITEM_ItemsAreEqual(&profileSubject,name)) { + goto loser; + } + } + + emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); + if (emailProfile == NULL) { + goto loser; + } + + emailProfile->data = (unsigned char*) smimeData[1].pValue; + emailProfile->len = smimeData[1].ulValueLen; + + if (profileTime) { + *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); + if (*profileTime) { + (*profileTime)->data = (unsigned char*) smimeData[0].pValue; + (*profileTime)->len = smimeData[0].ulValueLen; + } + } + +loser: + if (emailProfile == NULL) { + if (smimeData[1].pValue) { + PORT_Free(smimeData[1].pValue); + } + } + if (profileTime == NULL || *profileTime == NULL) { + if (smimeData[0].pValue) { + PORT_Free(smimeData[0].pValue); + } + } + return emailProfile; +} + + +SECStatus +PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, + SECItem *emailProfile, SECItem *profileTime) +{ + CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; + CK_BBOOL ck_true = CK_TRUE; + CK_ATTRIBUTE theTemplate[] = { + { CKA_CLASS, NULL, 0 }, + { CKA_TOKEN, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_NETSCAPE_EMAIL, NULL, 0 }, + { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 }, + { CKA_VALUE, NULL, 0 } + }; + /* if you change the array, change the variable below as well */ + int realSize = 0; + CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; + CK_ATTRIBUTE *attrs = theTemplate; + CK_SESSION_HANDLE rwsession; + PK11SlotInfo *free_slot = NULL; + CK_RV crv; +#ifdef DEBUG + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); +#endif + + PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; + PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++; + PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++; + PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, + emailAddr, PORT_Strlen(emailAddr)+1); attrs++; + if (profileTime) { + PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data, + profileTime->len); attrs++; + PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data, + emailProfile->len); attrs++; + } + realSize = attrs - theTemplate; + PORT_Assert (realSize <= tsize); + + if (slot == NULL) { + free_slot = slot = PK11_GetInternalKeySlot(); + /* we need to free the key slot in the end!!! */ + } + + rwsession = PK11_GetRWSession(slot); + if (rwsession == CK_INVALID_SESSION) { + PORT_SetError(SEC_ERROR_READ_ONLY); + if (free_slot) { + PK11_FreeSlot(free_slot); + } + return SECFailure; + } + + crv = PK11_GETTAB(slot)-> + C_CreateObject(rwsession,theTemplate,realSize,&smimeh); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + } + + PK11_RestoreROSession(slot,rwsession); + + if (free_slot) { + PK11_FreeSlot(free_slot); + } + return SECSuccess; +} + + +CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url, + CERTSignedCrl *newCrl, SECItem *derCrl, int type); + +/* import the CRL into the token */ + +CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, + int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena, + PRInt32 decodeoptions) +{ + CERTSignedCrl *newCrl, *crl; + SECStatus rv; + CERTCertificate *caCert = NULL; + + newCrl = crl = NULL; + + do { + newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type, + decodeoptions); + if (newCrl == NULL) { + if (type == SEC_CRL_TYPE) { + /* only promote error when the error code is too generic */ + if (PORT_GetError () == SEC_ERROR_BAD_DER) + PORT_SetError(SEC_ERROR_CRL_INVALID); + } else { + PORT_SetError(SEC_ERROR_KRL_INVALID); + } + break; + } + + if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){ + CERTCertDBHandle* handle = CERT_GetDefaultCertDB(); + PR_ASSERT(handle != NULL); + caCert = CERT_FindCertByName (handle, + &newCrl->crl.derName); + if (caCert == NULL) { + PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); + break; + } + + /* If caCert is a v3 certificate, make sure that it can be used for + crl signing purpose */ + rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN); + if (rv != SECSuccess) { + break; + } + + rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert, + PR_Now(), wincx); + if (rv != SECSuccess) { + if (type == SEC_CRL_TYPE) { + PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE); + } else { + PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE); + } + break; + } + } + + crl = crl_storeCRL(slot, url, newCrl, derCRL, type); + + } while (0); + + if (crl == NULL) { + SEC_DestroyCrl (newCrl); + } + if (caCert) { + CERT_DestroyCertificate(caCert); + } + return (crl); +} diff --git a/security/nss/lib/pk11wrap/pk11obj.c b/security/nss/lib/pk11wrap/pk11obj.c new file mode 100644 index 00000000000..bec9c6438be --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11obj.c @@ -0,0 +1,1579 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta , and + * Douglas Stebila , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This file manages object type indepentent functions. + */ +#include "seccomon.h" +#include "secmod.h" +#include "secmodi.h" +#include "secmodti.h" +#include "pkcs11.h" +#include "pkcs11t.h" +#include "pk11func.h" +#include "key.h" +#include "secitem.h" +#include "secerr.h" +#include "sslerr.h" + +#define PK11_SEARCH_CHUNKSIZE 10 + +/* + * Build a block big enough to hold the data + */ +SECItem * +PK11_BlockData(SECItem *data,unsigned long size) { + SECItem *newData; + + newData = (SECItem *)PORT_Alloc(sizeof(SECItem)); + if (newData == NULL) return NULL; + + newData->len = (data->len + (size-1))/size; + newData->len *= size; + + newData->data = (unsigned char *) PORT_ZAlloc(newData->len); + if (newData->data == NULL) { + PORT_Free(newData); + return NULL; + } + PORT_Memset(newData->data,newData->len-data->len,newData->len); + PORT_Memcpy(newData->data,data->data,data->len); + return newData; +} + + +SECStatus +PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { + CK_RV crv; + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object); + PK11_ExitSlotMonitor(slot); + if (crv != CKR_OK) { + return SECFailure; + } + return SECSuccess; +} + +SECStatus +PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { + CK_RV crv; + SECStatus rv = SECSuccess; + CK_SESSION_HANDLE rwsession; + + + rwsession = PK11_GetRWSession(slot); + + crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object); + if (crv != CKR_OK) { + rv = SECFailure; + PORT_SetError(PK11_MapError(crv)); + } + PK11_RestoreROSession(slot,rwsession); + return rv; +} + +/* + * Read in a single attribute into a SECItem. Allocate space for it with + * PORT_Alloc unless an arena is supplied. In the latter case use the arena + * to allocate the space. + */ +SECStatus +PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type, PRArenaPool *arena, SECItem *result) { + CK_ATTRIBUTE attr = { 0, NULL, 0 }; + CK_RV crv; + + attr.type = type; + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PORT_SetError(PK11_MapError(crv)); + return SECFailure; + } + if (arena) { + attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen); + } else { + attr.pValue = PORT_Alloc(attr.ulValueLen); + } + if (attr.pValue == NULL) { + PK11_ExitSlotMonitor(slot); + return SECFailure; + } + crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); + PK11_ExitSlotMonitor(slot); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + if (!arena) PORT_Free(attr.pValue); + return SECFailure; + } + + result->data = (unsigned char*)attr.pValue; + result->len = attr.ulValueLen; + + return SECSuccess; +} + +/* + * Read in a single attribute into As a Ulong. + */ +CK_ULONG +PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type) { + CK_ATTRIBUTE attr; + CK_ULONG value = CK_UNAVAILABLE_INFORMATION; + CK_RV crv; + + PK11_SETATTRS(&attr,type,&value,sizeof(value)); + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); + PK11_ExitSlotMonitor(slot); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + } + return value; +} + +/* + * check to see if a bool has been set. + */ +CK_BBOOL +PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type ) +{ + CK_BBOOL ckvalue = CK_FALSE; + CK_ATTRIBUTE theTemplate; + CK_RV crv; + + /* Prepare to retrieve the attribute. */ + PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) ); + + /* Retrieve attribute value. */ + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id, + &theTemplate, 1 ); + PK11_ExitSlotMonitor(slot); + if( crv != CKR_OK ) { + PORT_SetError( PK11_MapError( crv ) ); + return CK_FALSE; + } + + return ckvalue; +} + +/* + * returns a full list of attributes. Allocate space for them. If an arena is + * provided, allocate space out of the arena. + */ +CK_RV +PK11_GetAttributes(PRArenaPool *arena,PK11SlotInfo *slot, + CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count) +{ + int i; + /* make pedantic happy... note that it's only used arena != NULL */ + void *mark = NULL; + CK_RV crv; + + /* + * first get all the lengths of the parameters. + */ + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + return crv; + } + + if (arena) { + mark = PORT_ArenaMark(arena); + if (mark == NULL) return CKR_HOST_MEMORY; + } + + /* + * now allocate space to store the results. + */ + for (i=0; i < count; i++) { + if (arena) { + attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen); + if (attr[i].pValue == NULL) { + /* arena failures, just release the mark */ + PORT_ArenaRelease(arena,mark); + PK11_ExitSlotMonitor(slot); + return CKR_HOST_MEMORY; + } + } else { + attr[i].pValue = PORT_Alloc(attr[i].ulValueLen); + if (attr[i].pValue == NULL) { + /* Separate malloc failures, loop to release what we have + * so far */ + int j; + for (j= 0; j < i; j++) { + PORT_Free(attr[j].pValue); + /* don't give the caller pointers to freed memory */ + attr[j].pValue = NULL; + } + PK11_ExitSlotMonitor(slot); + return CKR_HOST_MEMORY; + } + } + } + + /* + * finally get the results. + */ + crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); + PK11_ExitSlotMonitor(slot); + if (crv != CKR_OK) { + if (arena) { + PORT_ArenaRelease(arena,mark); + } else { + for (i= 0; i < count; i++) { + PORT_Free(attr[i].pValue); + /* don't give the caller pointers to freed memory */ + attr[i].pValue = NULL; + } + } + } else if (arena && mark) { + PORT_ArenaUnmark(arena,mark); + } + return crv; +} + +PRBool +PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) +{ + return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN); +} + +char * +PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) +{ + char *nickname = NULL; + SECItem result; + SECStatus rv; + + rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result); + if (rv != SECSuccess) { + return NULL; + } + + nickname = PORT_ZAlloc(result.len+1); + if (nickname == NULL) { + PORT_Free(result.data); + return NULL; + } + PORT_Memcpy(nickname, result.data, result.len); + PORT_Free(result.data); + return nickname; +} + +SECStatus +PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + const char *nickname) +{ + int len = PORT_Strlen(nickname); + CK_ATTRIBUTE setTemplate; + CK_RV crv; + CK_SESSION_HANDLE rwsession; + + if (len < 0) { + return SECFailure; + } + + PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len); + rwsession = PK11_GetRWSession(slot); + crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, + &setTemplate, 1); + PK11_RestoreROSession(slot, rwsession); + if (crv != CKR_OK) { + PORT_SetError(PK11_MapError(crv)); + return SECFailure; + } + return SECSuccess; +} + +/* + * strip leading zero's from key material + */ +void +pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) { + char *ptr = (char *)attrib->pValue; + unsigned long len = attrib->ulValueLen; + + while (len && (*ptr == 0)) { + len--; + ptr++; + } + attrib->pValue = ptr; + attrib->ulValueLen = len; +} + +/* + * get a new session on a slot. If we run out of session, use the slot's + * 'exclusive' session. In this case owner becomes false. + */ +CK_SESSION_HANDLE +pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner) +{ + CK_SESSION_HANDLE session; + *owner = PR_TRUE; + if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); + if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION, + slot,pk11_notify,&session) != CKR_OK) { + *owner = PR_FALSE; + session = slot->session; + } + if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); + + return session; +} + +void +pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner) +{ + if (!owner) return; + if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); + (void) PK11_GETTAB(slot)->C_CloseSession(session); + if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); +} + + +SECStatus +PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session, + CK_ATTRIBUTE *theTemplate, int count, + PRBool token, CK_OBJECT_HANDLE *objectID) +{ + CK_SESSION_HANDLE rwsession; + CK_RV crv; + SECStatus rv = SECSuccess; + + rwsession = session; + if (token) { + rwsession = PK11_GetRWSession(slot); + } else if (rwsession == CK_INVALID_SESSION) { + rwsession = slot->session; + PK11_EnterSlotMonitor(slot); + } + crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, theTemplate, + count,objectID); + if(crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + rv = SECFailure; + } + if (token) { + PK11_RestoreROSession(slot, rwsession); + } else if (session == CK_INVALID_SESSION) { + PK11_ExitSlotMonitor(slot); + } + + return rv; +} + + +unsigned int +pk11_FlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) +{ + + const static CK_ATTRIBUTE_TYPE attrTypes[12] = { + CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN, + CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */, + 0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE + }; + + const CK_ATTRIBUTE_TYPE *pType = attrTypes; + CK_ATTRIBUTE *attr = attrs; + CK_FLAGS test = CKF_ENCRYPT; + + + PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS)); + flags &= CKF_KEY_OPERATION_FLAGS; + + for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) { + if (test & flags) { + flags ^= test; + PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); + ++attr; + } + } + return (attr - attrs); +} + +/* + * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually + * set up a signature to get the signaure length. + */ +static int +pk11_backupGetSignLength(SECKEYPrivateKey *key) +{ + PK11SlotInfo *slot = key->pkcs11Slot; + CK_MECHANISM mech = {0, NULL, 0 }; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + CK_ULONG len; + CK_RV crv; + unsigned char h_data[20] = { 0 }; + unsigned char buf[20]; /* obviously to small */ + CK_ULONG smallLen = sizeof(buf); + + mech.mechanism = pk11_mapSignKeyType(key->keyType); + + session = pk11_GetNewSession(slot,&owner); + if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); + if (crv != CKR_OK) { + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PORT_SetError( PK11_MapError(crv) ); + return -1; + } + len = 0; + crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data), + NULL, &len); + /* now call C_Sign with too small a buffer to clear the session state */ + (void) PK11_GETTAB(slot)-> + C_Sign(session,h_data,sizeof(h_data),buf,&smallLen); + + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return -1; + } + return len; +} + +/* + * get the length of a signature object based on the key + */ +int +PK11_SignatureLen(SECKEYPrivateKey *key) +{ + int val; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE theTemplate = { CKA_EC_PARAMS, NULL, 0 }; + SECItem params = {siBuffer, NULL, 0}; + int length; +#endif /* NSS_ENABLE_ECC */ + + switch (key->keyType) { + case rsaKey: + val = PK11_GetPrivateModulusLen(key); + if (val == -1) { + return pk11_backupGetSignLength(key); + } + return (unsigned long) val; + + case fortezzaKey: + case dsaKey: + return 40; +#ifdef NSS_ENABLE_ECC + case ecKey: + if (PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID, + &theTemplate, 1) == CKR_OK) { + if (theTemplate.pValue != NULL) { + params.len = theTemplate.ulValueLen; + params.data = (unsigned char *) theTemplate.pValue; + length = SECKEY_ECParamsToKeySize(¶ms); + PORT_Free(theTemplate.pValue); + } + length = ((length + 7)/8) * 2; + return length; + } + break; +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + PORT_SetError( SEC_ERROR_INVALID_KEY ); + return 0; +} + +/* + * copy a key (or any other object) on a token + */ +CK_OBJECT_HANDLE +PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject) +{ + CK_OBJECT_HANDLE destObject; + CK_RV crv; + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0, + &destObject); + PK11_ExitSlotMonitor(slot); + if (crv == CKR_OK) return destObject; + PORT_SetError( PK11_MapError(crv) ); + return CK_INVALID_HANDLE; +} + +PRBool +pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs, + CK_ATTRIBUTE_TYPE target) +{ + for (; numAttrs > 0; ++attr, --numAttrs) { + if (attr->type == target) + return PR_TRUE; + } + return PR_FALSE; +} + +/* + * Recover the Signed data. We need this because our old verify can't + * figure out which hash algorithm to use until we decryptted this. + */ +SECStatus +PK11_VerifyRecover(SECKEYPublicKey *key, + SECItem *sig, SECItem *dsig, void *wincx) +{ + PK11SlotInfo *slot = key->pkcs11Slot; + CK_OBJECT_HANDLE id = key->pkcs11ID; + CK_MECHANISM mech = {0, NULL, 0 }; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + CK_ULONG len; + CK_RV crv; + + mech.mechanism = pk11_mapSignKeyType(key->keyType); + + if (slot == NULL) { + slot = PK11_GetBestSlot(mech.mechanism,wincx); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return SECFailure; + } + id = PK11_ImportPublicKey(slot,key,PR_FALSE); + } else { + PK11_ReferenceSlot(slot); + } + + session = pk11_GetNewSession(slot,&owner); + if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id); + if (crv != CKR_OK) { + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PORT_SetError( PK11_MapError(crv) ); + PK11_FreeSlot(slot); + return SECFailure; + } + len = dsig->len; + crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data, + sig->len, dsig->data, &len); + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + dsig->len = len; + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + PK11_FreeSlot(slot); + return SECFailure; + } + PK11_FreeSlot(slot); + return SECSuccess; +} + +/* + * verify a signature from its hash. + */ +SECStatus +PK11_Verify(SECKEYPublicKey *key, SECItem *sig, SECItem *hash, void *wincx) +{ + PK11SlotInfo *slot = key->pkcs11Slot; + CK_OBJECT_HANDLE id = key->pkcs11ID; + CK_MECHANISM mech = {0, NULL, 0 }; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + CK_RV crv; + + mech.mechanism = pk11_mapSignKeyType(key->keyType); + + if (slot == NULL) { + slot = PK11_GetBestSlot(mech.mechanism,wincx); + + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return SECFailure; + } + id = PK11_ImportPublicKey(slot,key,PR_FALSE); + + } else { + PK11_ReferenceSlot(slot); + } + + session = pk11_GetNewSession(slot,&owner); + if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id); + if (crv != CKR_OK) { + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PK11_FreeSlot(slot); + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + crv = PK11_GETTAB(slot)->C_Verify(session,hash->data, + hash->len, sig->data, sig->len); + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PK11_FreeSlot(slot); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + return SECSuccess; +} + +/* + * sign a hash. The algorithm is determined by the key. + */ +SECStatus +PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash) +{ + PK11SlotInfo *slot = key->pkcs11Slot; + CK_MECHANISM mech = {0, NULL, 0 }; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + CK_ULONG len; + CK_RV crv; + + mech.mechanism = pk11_mapSignKeyType(key->keyType); + + if (!PK11_HasAttributeSet(slot,key->pkcs11ID,CKA_PRIVATE)) { + PK11_HandlePasswordCheck(slot, key->wincx); + } + + session = pk11_GetNewSession(slot,&owner); + if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); + if (crv != CKR_OK) { + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + len = sig->len; + crv = PK11_GETTAB(slot)->C_Sign(session,hash->data, + hash->len, sig->data, &len); + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + sig->len = len; + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + return SECSuccess; +} + +/* + * Now SSL 2.0 uses raw RSA stuff. These next to functions *must* use + * RSA keys, or they'll fail. We do the checks up front. If anyone comes + * up with a meaning for rawdecrypt for any other public key operation, + * then we need to move this check into some of PK11_PubDecrypt callers, + * (namely SSL 2.0). + */ +SECStatus +PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, + unsigned *outLen, unsigned int maxLen, unsigned char *enc, + unsigned encLen) +{ + PK11SlotInfo *slot = key->pkcs11Slot; + CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; + CK_ULONG out = maxLen; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + CK_RV crv; + + if (key->keyType != rsaKey) { + PORT_SetError( SEC_ERROR_INVALID_KEY ); + return SECFailure; + } + + /* Why do we do a PK11_handle check here? for simple + * decryption? .. because the user may have asked for 'ask always' + * and this is a private key operation. In practice, thought, it's mute + * since only servers wind up using this function */ + if (!PK11_HasAttributeSet(slot,key->pkcs11ID,CKA_PRIVATE)) { + PK11_HandlePasswordCheck(slot, key->wincx); + } + session = pk11_GetNewSession(slot,&owner); + if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_DecryptInit(session,&mech,key->pkcs11ID); + if (crv != CKR_OK) { + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + crv = PK11_GETTAB(slot)->C_Decrypt(session,enc, encLen, + data, &out); + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + *outLen = out; + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + return SECSuccess; +} + +/* The encrypt version of the above function */ +SECStatus +PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc, + unsigned char *data, unsigned dataLen, void *wincx) +{ + PK11SlotInfo *slot; + CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; + CK_OBJECT_HANDLE id; + CK_ULONG out = dataLen; + PRBool owner = PR_TRUE; + CK_SESSION_HANDLE session; + CK_RV crv; + + if (key->keyType != rsaKey) { + PORT_SetError( SEC_ERROR_BAD_KEY ); + return SECFailure; + } + + slot = PK11_GetBestSlot(mech.mechanism, wincx); + if (slot == NULL) { + PORT_SetError( SEC_ERROR_NO_MODULE ); + return SECFailure; + } + + id = PK11_ImportPublicKey(slot,key,PR_FALSE); + + session = pk11_GetNewSession(slot,&owner); + if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,id); + if (crv != CKR_OK) { + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PK11_FreeSlot(slot); + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + crv = PK11_GETTAB(slot)->C_Encrypt(session,data,dataLen,enc,&out); + if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); + pk11_CloseSession(slot,session,owner); + PK11_FreeSlot(slot); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + return SECSuccess; +} + +SECKEYPrivateKey * +PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, + CK_MECHANISM_TYPE wrapType, SECItem *param, + SECItem *wrappedKey, SECItem *label, + SECItem *idValue, PRBool perm, PRBool sensitive, + CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, + int usageCount, void *wincx) +{ + CK_BBOOL cktrue = CK_TRUE; + CK_BBOOL ckfalse = CK_FALSE; + CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; + CK_ATTRIBUTE keyTemplate[15] ; + int templateCount = 0; + CK_OBJECT_HANDLE privKeyID; + CK_MECHANISM mechanism; + CK_ATTRIBUTE *attrs = keyTemplate; + SECItem *param_free = NULL, *ck_id; + CK_RV crv; + CK_SESSION_HANDLE rwsession; + PK11SymKey *newKey = NULL; + int i; + + if(!slot || !wrappedKey || !idValue) { + /* SET AN ERROR!!! */ + return NULL; + } + + ck_id = PK11_MakeIDFromPubKey(idValue); + if(!ck_id) { + return NULL; + } + + PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse, + sizeof(cktrue)); attrs++; + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++; + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++; + PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, + sizeof(cktrue)); attrs++; + PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, + sizeof(cktrue)); attrs++; + PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++; + PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; + for (i=0; i < usageCount; i++) { + PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++; + } + + if (PK11_IsInternal(slot)) { + PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data, + idValue->len); attrs++; + } + + templateCount = attrs - keyTemplate; + PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) ); + + mechanism.mechanism = wrapType; + if(!param) param = param_free= PK11_ParamFromIV(wrapType, NULL); + if(param) { + mechanism.pParameter = param->data; + mechanism.ulParameterLen = param->len; + } else { + mechanism.pParameter = NULL; + mechanism.ulParameterLen = 0; + } + + if (wrappingKey->slot != slot) { + newKey = pk11_CopyToSlot(slot,wrapType,CKA_WRAP,wrappingKey); + } else { + newKey = PK11_ReferenceSymKey(wrappingKey); + } + + if (newKey) { + if (perm) { + /* Get RW Session will either lock the monitor if necessary, + * or return a thread safe session handle. */ + rwsession = PK11_GetRWSession(slot); + } else { + rwsession = slot->session; + PK11_EnterSlotMonitor(slot); + } + crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, + newKey->objectID, + wrappedKey->data, + wrappedKey->len, keyTemplate, + templateCount, &privKeyID); + + if (perm) { + PK11_RestoreROSession(slot, rwsession); + } else { + PK11_ExitSlotMonitor(slot); + } + PK11_FreeSymKey(newKey); + } else { + crv = CKR_FUNCTION_NOT_SUPPORTED; + } + + if(ck_id) { + SECITEM_FreeItem(ck_id, PR_TRUE); + ck_id = NULL; + } + + if (crv != CKR_OK) { + /* we couldn't unwrap the key, use the internal module to do the + * unwrap, then load the new key into the token */ + PK11SlotInfo *int_slot = PK11_GetInternalSlot(); + + if (int_slot && (slot != int_slot)) { + SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot, + wrappingKey, wrapType, param, wrappedKey, label, + idValue, PR_FALSE, PR_FALSE, + keyType, usage, usageCount, wincx); + if (privKey) { + SECKEYPrivateKey *newPrivKey = PK11_LoadPrivKey(slot,privKey, + NULL,perm,sensitive); + SECKEY_DestroyPrivateKey(privKey); + PK11_FreeSlot(int_slot); + return newPrivKey; + } + } + if (int_slot) PK11_FreeSlot(int_slot); + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx); +} + +/* + * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey + * The strategy is to get both keys to reside in the same slot, + * one that can perform the desired crypto mechanism and then + * call C_WrapKey after all the setup has taken place. + */ +SECStatus +PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, + SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, + SECItem *param, SECItem *wrappedKey, void *wincx) +{ + PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where + * the private key + * we are going to + * wrap lives. + */ + PK11SymKey *newSymKey = NULL; + SECKEYPrivateKey *newPrivKey = NULL; + SECItem *param_free = NULL; + CK_ULONG len = wrappedKey->len; + CK_MECHANISM mech; + CK_RV crv; + + if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) { + /* Figure out a slot that does the mechanism and try to import + * the private key onto that slot. + */ + PK11SlotInfo *int_slot = PK11_GetInternalSlot(); + + privSlot = int_slot; /* The private key has a new home */ + newPrivKey = PK11_LoadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE); + /* newPrivKey has allocated its own reference to the slot, so it's + * safe until we destroy newPrivkey. + */ + PK11_FreeSlot(int_slot); + if (newPrivKey == NULL) { + return SECFailure; + } + privKey = newPrivKey; + } + + if (privSlot != wrappingKey->slot) { + newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP, + wrappingKey); + wrappingKey = newSymKey; + } + + if (wrappingKey == NULL) { + if (newPrivKey) { + SECKEY_DestroyPrivateKey(newPrivKey); + } + return SECFailure; + } + mech.mechanism = wrapType; + if (!param) { + param = param_free = PK11_ParamFromIV(wrapType, NULL); + } + if (param) { + mech.pParameter = param->data; + mech.ulParameterLen = param->len; + } else { + mech.pParameter = NULL; + mech.ulParameterLen = 0; + } + + PK11_EnterSlotMonitor(privSlot); + crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, + wrappingKey->objectID, + privKey->pkcs11ID, + wrappedKey->data, &len); + PK11_ExitSlotMonitor(privSlot); + + if (newSymKey) { + PK11_FreeSymKey(newSymKey); + } + if (newPrivKey) { + SECKEY_DestroyPrivateKey(newPrivKey); + } + if (param_free) { + SECITEM_FreeItem(param_free,PR_TRUE); + } + + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + return SECFailure; + } + + wrappedKey->len = len; + return SECSuccess; +} + +/* + * return a linked, non-circular list of generic objects. + * If you are only interested + * in one object, just use the first object in the list. To find the + * rest of the list use PK11_GetNextGenericObject() to return the next object. + * + * You can walk the list with the following code: + * firstObj = PK11_FindGenericObjects(slot, objClass); + * for (thisObj=firstObj; thisObj; + * thisObj=PK11_GetNextGenericObject(thisObj)) { + * /* operate on thisObj */ +/* } + * + * If you want a particular object from the list... + * firstObj = PK11_FindGenericObjects(slot, objClass); + * for (thisObj=firstObj; thisObj; + * thisObj=PK11_GetNextGenericObject(thisObj)) { + * if (isMyObj(thisObj)) { + * if ( thisObj == firstObj) { + * /* NOTE: firstObj could be NULL at this point */ +/* firstObj = PK11_GetNextGenericObject(thsObj); + * } + * PK11_UnlinkGenericObject(thisObj); + * myObj = thisObj; + * break; + * } + * + * PK11_DestroyGenericObjects(firstObj); + * + * /* use myObj */ +/* PK11_DestroyGenericObject(myObj); + */ +PK11GenericObject * +PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass) +{ + CK_ATTRIBUTE template[1]; + CK_ATTRIBUTE *attrs = template; + CK_OBJECT_HANDLE *objectIDs = NULL; + PK11GenericObject *lastObj, *obj; + PK11GenericObject *firstObj = NULL; + int i, count = 0; + + + PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; + + objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count); + if (objectIDs == NULL) { + return NULL; + } + + /* where we connect our object once we've created it.. */ + for (i=0; i < count; i++) { + obj = PORT_New(PK11GenericObject); + if ( !obj ) { + PK11_DestroyGenericObjects(firstObj); + PORT_Free(objectIDs); + return NULL; + } + /* initialize it */ + obj->slot = PK11_ReferenceSlot(slot); + obj->objectID = objectIDs[i]; + obj->next = NULL; + obj->prev = NULL; + + /* link it in */ + if (firstObj == NULL) { + firstObj = obj; + } else { + PK11_LinkGenericObject(lastObj, obj); + } + lastObj = obj; + } + PORT_Free(objectIDs); + return firstObj; +} + +/* + * get the Next Object in the list. + */ +PK11GenericObject * +PK11_GetNextGenericObject(PK11GenericObject *object) +{ + return object->next; +} + +PK11GenericObject * +PK11_GetPrevGenericObject(PK11GenericObject *object) +{ + return object->prev; +} + +/* + * Link a single object into a new list. + * if the object is already in another list, remove it first. + */ +SECStatus +PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object) +{ + PK11_UnlinkGenericObject(object); + object->prev = list; + object->next = list->next; + list->next = object; + if (object->next != NULL) { + object->next->prev = object; + } + return SECSuccess; +} + +/* + * remove an object from the list. If the object isn't already in + * a list unlink becomes a noop. + */ +SECStatus +PK11_UnlinkGenericObject(PK11GenericObject *object) +{ + if (object->prev != NULL) { + object->prev->next = object->next; + } + if (object->next != NULL) { + object->next->prev = object->prev; + } + + object->next = NULL; + object->prev = NULL; + return SECSuccess; +} + +/* + * This function removes a single object from the list and destroys it. + * For an already unlinked object there is no difference between + * PK11_DestroyGenericObject and PK11_DestroyGenericObjects + */ +SECStatus +PK11_DestroyGenericObject(PK11GenericObject *object) +{ + if (object == NULL) { + return SECSuccess; + } + + PK11_UnlinkGenericObject(object); + if (object->slot) { + PK11_FreeSlot(object->slot); + } + PORT_Free(object); + return SECSuccess; +} + +/* + * walk down a link list of generic objects destroying them. + * This will destroy all objects in a list that the object is linked into. + * (the list is traversed in both directions). + */ +SECStatus +PK11_DestroyGenericObjects(PK11GenericObject *objects) +{ + PK11GenericObject *nextObject; + PK11GenericObject *prevObject = objects->prev; + + if (objects == NULL) { + return SECSuccess; + } + + nextObject = objects->next; + prevObject = objects->prev; + + /* delete all the objects after it in the list */ + for (; objects; objects = nextObject) { + nextObject = objects->next; + PK11_DestroyGenericObject(objects); + } + /* delete all the objects before it in the list */ + for (objects = prevObject; objects; objects = nextObject) { + prevObject = objects->prev; + PK11_DestroyGenericObject(objects); + } + return SECSuccess; +} + + +SECStatus +PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, + CK_ATTRIBUTE_TYPE attrType, SECItem *item) +{ + PK11SlotInfo *slot = NULL; + CK_OBJECT_HANDLE handle; + + switch (objType) { + case PK11_TypeGeneric: + slot = ((PK11GenericObject *)objSpec)->slot; + handle = ((PK11GenericObject *)objSpec)->objectID; + break; + case PK11_TypePrivKey: + slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; + handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; + break; + case PK11_TypePubKey: + slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; + handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; + break; + case PK11_TypeSymKey: + slot = ((PK11SymKey *)objSpec)->slot; + handle = ((PK11SymKey *)objSpec)->objectID; + break; + case PK11_TypeCert: /* don't handle cert case for now */ + default: + break; + } + if (slot == NULL) { + PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); + return SECFailure; + } + + return PK11_ReadAttribute(slot, handle, attrType, NULL, item); +} + + +/* + * return the object handle that matches the template + */ +CK_OBJECT_HANDLE +pk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize) +{ + CK_OBJECT_HANDLE object; + CK_RV crv; + CK_ULONG objectCount; + + /* + * issue the find + */ + PK11_EnterSlotMonitor(slot); + crv=PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, theTemplate, tsize); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError(crv) ); + return CK_INVALID_HANDLE; + } + + crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount); + PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); + PK11_ExitSlotMonitor(slot); + if ((crv != CKR_OK) || (objectCount < 1)) { + /* shouldn't use SSL_ERROR... here */ + PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) : + SSL_ERROR_NO_CERTIFICATE); + return CK_INVALID_HANDLE; + } + + /* blow up if the PKCS #11 module returns us and invalid object handle */ + PORT_Assert(object != CK_INVALID_HANDLE); + return object; +} + +/* + * return all the object handles that matches the template + */ +CK_OBJECT_HANDLE * +pk11_FindObjectsByTemplate(PK11SlotInfo *slot, + CK_ATTRIBUTE *findTemplate,int findCount,int *object_count) { + CK_OBJECT_HANDLE *objID = NULL; + CK_ULONG returned_count = 0; + CK_RV crv; + + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, findTemplate, + findCount); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError(crv) ); + *object_count = -1; + return NULL; + } + + + /* + * collect all the Matching Objects + */ + do { + CK_OBJECT_HANDLE *oldObjID = objID; + + if (objID == NULL) { + objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)* + (*object_count+ PK11_SEARCH_CHUNKSIZE)); + } else { + objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID, + sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE)); + } + + if (objID == NULL) { + if (oldObjID) PORT_Free(oldObjID); + break; + } + crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, + &objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + PORT_Free(objID); + objID = NULL; + break; + } + *object_count += returned_count; + } while (returned_count == PK11_SEARCH_CHUNKSIZE); + + PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); + PK11_ExitSlotMonitor(slot); + + if (objID && (*object_count == 0)) { + PORT_Free(objID); + return NULL; + } + if (objID == NULL) *object_count = -1; + return objID; +} +/* + * given a PKCS #11 object, match it's peer based on the KeyID. searchID + * is typically a privateKey or a certificate while the peer is the opposite + */ +CK_OBJECT_HANDLE +PK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID, + CK_OBJECT_CLASS matchclass) +{ + CK_ATTRIBUTE theTemplate[] = { + { CKA_ID, NULL, 0 }, + { CKA_CLASS, NULL, 0 } + }; + /* if you change the array, change the variable below as well */ + CK_ATTRIBUTE *keyclass = &theTemplate[1]; + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); + /* if you change the array, change the variable below as well */ + CK_OBJECT_HANDLE peerID; + CK_OBJECT_HANDLE parent; + PRArenaPool *arena; + CK_RV crv; + + /* now we need to create space for the public key */ + arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) return CK_INVALID_HANDLE; + + crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize); + if (crv != CKR_OK) { + PORT_FreeArena(arena,PR_FALSE); + PORT_SetError( PK11_MapError(crv) ); + return CK_INVALID_HANDLE; + } + + if ((theTemplate[0].ulValueLen == 0) || (theTemplate[0].ulValueLen == -1)) { + PORT_FreeArena(arena,PR_FALSE); + PORT_SetError(SEC_ERROR_BAD_KEY); + return CK_INVALID_HANDLE; + } + + + + /* + * issue the find + */ + parent = *(CK_OBJECT_CLASS *)(keyclass->pValue); + *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass; + + peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize); + PORT_FreeArena(arena,PR_FALSE); + + return peerID; +} + +/* + * count the number of objects that match the template. + */ +int +PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, + int templateCount) +{ + CK_OBJECT_HANDLE objID[PK11_SEARCH_CHUNKSIZE]; + int object_count = 0; + CK_ULONG returned_count = 0; + CK_RV crv; + + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, + findTemplate, templateCount); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PORT_SetError( PK11_MapError(crv) ); + return 0; + } + + /* + * collect all the Matching Objects + */ + do { + crv = PK11_GETTAB(slot)->C_FindObjects(slot->session, + objID,PK11_SEARCH_CHUNKSIZE,&returned_count); + if (crv != CKR_OK) { + PORT_SetError( PK11_MapError(crv) ); + break; + } + object_count += returned_count; + } while (returned_count == PK11_SEARCH_CHUNKSIZE); + + PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session); + PK11_ExitSlotMonitor(slot); + return object_count; +} + +/* + * Traverse all the objects in a given slot. + */ +SECStatus +PK11_TraverseSlot(PK11SlotInfo *slot, void *arg) +{ + int i; + CK_OBJECT_HANDLE *objID = NULL; + int object_count = 0; + pk11TraverseSlot *slotcb = (pk11TraverseSlot*) arg; + + objID = pk11_FindObjectsByTemplate(slot,slotcb->findTemplate, + slotcb->templateCount,&object_count); + + /*Actually this isn't a failure... there just were no objs to be found*/ + if (object_count == 0) { + return SECSuccess; + } + + if (objID == NULL) { + return SECFailure; + } + + for (i=0; i < object_count; i++) { + (*slotcb->callback)(slot,objID[i],slotcb->callbackArg); + } + PORT_Free(objID); + return SECSuccess; +} + +/* + * Traverse all the objects in all slots. + */ +SECStatus +pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), + void *arg,void *wincx) { + PK11SlotList *list; + PK11SlotListElement *le; + SECStatus rv; + + /* get them all! */ + list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,wincx); + if (list == NULL) return SECFailure; + + /* look at each slot and authenticate as necessary */ + for (le = list->head ; le; le = le->next) { + rv = pk11_AuthenticateUnfriendly(le->slot, PR_FALSE, wincx); + if (rv != SECSuccess) { + continue; + } + if (callback) { + (*callback)(le->slot,arg); + } + } + + PK11_FreeSlotList(list); + + return SECSuccess; +} + +CK_OBJECT_HANDLE * +PK11_FindObjectsFromNickname(char *nickname,PK11SlotInfo **slotptr, + CK_OBJECT_CLASS objclass, int *returnCount, void *wincx) +{ + char *tokenName; + char *delimit; + PK11SlotInfo *slot; + CK_OBJECT_HANDLE *objID; + CK_ATTRIBUTE findTemplate[] = { + { CKA_LABEL, NULL, 0}, + { CKA_CLASS, NULL, 0}, + }; + int findCount = sizeof(findTemplate)/sizeof(findTemplate[0]); + SECStatus rv; + PK11_SETATTRS(&findTemplate[1], CKA_CLASS, &objclass, sizeof(objclass)); + + *slotptr = slot = NULL; + *returnCount = 0; + /* first find the slot associated with this nickname */ + if ((delimit = PORT_Strchr(nickname,':')) != NULL) { + int len = delimit - nickname; + tokenName = (char*)PORT_Alloc(len+1); + PORT_Memcpy(tokenName,nickname,len); + tokenName[len] = 0; + + slot = *slotptr = PK11_FindSlotByName(tokenName); + PORT_Free(tokenName); + /* if we couldn't find a slot, assume the nickname is an internal cert + * with no proceding slot name */ + if (slot == NULL) { + slot = *slotptr = PK11_GetInternalKeySlot(); + } else { + nickname = delimit+1; + } + } else { + *slotptr = slot = PK11_GetInternalKeySlot(); + } + if (slot == NULL) { + return CK_INVALID_HANDLE; + } + + rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx); + if (rv != SECSuccess) { + PK11_FreeSlot(slot); + *slotptr = NULL; + return CK_INVALID_HANDLE; + } + + findTemplate[0].pValue = nickname; + findTemplate[0].ulValueLen = PORT_Strlen(nickname); + objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount,returnCount); + if (objID == NULL) { + /* PKCS #11 isn't clear on whether or not the NULL is + * stored in the template.... try the find again with the + * full null terminated string. */ + findTemplate[0].ulValueLen += 1; + objID = pk11_FindObjectsByTemplate(slot,findTemplate,findCount, + returnCount); + if (objID == NULL) { + /* Well that's the best we can do. It's just not here */ + /* what about faked nicknames? */ + PK11_FreeSlot(slot); + *slotptr = NULL; + *returnCount = 0; + } + } + + return objID; +} + +SECItem * +pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) +{ + CK_ATTRIBUTE theTemplate[] = { + { CKA_ID, NULL, 0 }, + }; + int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); + CK_RV crv; + SECItem *item; + + item = SECITEM_AllocItem(NULL, NULL, 0); + + if (item == NULL) { + return NULL; + } + + crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize); + if (crv != CKR_OK) { + SECITEM_FreeItem(item,PR_TRUE); + PORT_SetError( PK11_MapError(crv) ); + return NULL; + } + + item->data = (unsigned char*) theTemplate[0].pValue; + item->len =theTemplate[0].ulValueLen; + + return item; +} + diff --git a/security/nss/lib/pk11wrap/pk11pars.c b/security/nss/lib/pk11wrap/pk11pars.c index 401747d7d81..28a1b45cb12 100644 --- a/security/nss/lib/pk11wrap/pk11pars.c +++ b/security/nss/lib/pk11wrap/pk11pars.c @@ -43,6 +43,7 @@ #include "seccomon.h" #include "secmod.h" #include "secmodi.h" +#include "secmodti.h" #include "pki3hack.h" #include "secerr.h" diff --git a/security/nss/lib/pk11wrap/pk11pbe.c b/security/nss/lib/pk11wrap/pk11pbe.c index 1ec9dd438e5..cbe5dcd35a3 100644 --- a/security/nss/lib/pk11wrap/pk11pbe.c +++ b/security/nss/lib/pk11wrap/pk11pbe.c @@ -50,6 +50,12 @@ #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 { @@ -688,3 +694,152 @@ RSA_FormatBlock(SECItem *result, unsigned modulusLen, 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, 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) +{ + SECAlgorithmID *algid = NULL; + algid = SEC_PKCS5CreateAlgorithmID(algorithm, salt, iteration); + return algid; +} + +PK11SymKey * +PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech, + SECItem *pwitem, PRBool faulty3DES, void *wincx) +{ + /* pbe stuff */ + CK_PBE_PARAMS *pbe_params; + PK11SymKey *symKey; + + if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) { + type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC; + } + if(mech == NULL) { + return NULL; + } + + pbe_params = (CK_PBE_PARAMS *)mech->data; + pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwitem->len); + if(pbe_params->pPassword != NULL) { + PORT_Memcpy(pbe_params->pPassword, pwitem->data, pwitem->len); + pbe_params->ulPasswordLen = pwitem->len; + } else { + SECITEM_ZfreeItem(mech, PR_TRUE); + return NULL; + } + + symKey = PK11_KeyGen(slot, type, mech, 0, wincx); + + PORT_ZFree(pbe_params->pPassword, pwitem->len); + pbe_params->pPassword = NULL; + pbe_params->ulPasswordLen = 0; + return symKey; +} + +PK11SymKey * +PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem, + PRBool faulty3DES, void *wincx) +{ + /* pbe stuff */ + CK_MECHANISM_TYPE type; + SECItem *mech; + PK11SymKey *symKey; + + mech = PK11_ParamFromAlgid(algid); + type = PK11_AlgtagToMechanism(SECOID_FindOIDTag(&algid->algorithm)); + if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) { + type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC; + } + if(mech == NULL) { + return NULL; + } + symKey = PK11_RawPBEKeyGen(slot, type, mech, pwitem, faulty3DES, wincx); + + SECITEM_ZfreeItem(mech, PR_TRUE); + return symKey; +} + +SECItem * +PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem) +{ + /* pbe stuff */ + CK_MECHANISM_TYPE type; + SECItem *mech; + PK11SymKey *symKey; + PK11SlotInfo *slot = PK11_GetInternalSlot(); + int iv_len = 0; + CK_PBE_PARAMS_PTR pPBEparams; + SECItem src; + SECItem *iv; + + + mech = PK11_ParamFromAlgid(algid); + type = PK11_AlgtagToMechanism(SECOID_FindOIDTag(&algid->algorithm)); + if(mech == NULL) { + return NULL; + } + symKey = PK11_RawPBEKeyGen(slot, type, mech, pwitem, PR_FALSE, NULL); + PK11_FreeSlot(slot); + if (symKey == NULL) { + SECITEM_ZfreeItem(mech, PR_TRUE); + return NULL; + } + PK11_FreeSymKey(symKey); + pPBEparams = (CK_PBE_PARAMS_PTR)mech->data; + iv_len = PK11_GetIVLength(type); + + src.data = (unsigned char *)pPBEparams->pInitVector; + src.len = iv_len; + iv = SECITEM_DupItem(&src); + + SECITEM_ZfreeItem(mech, PR_TRUE); + return iv; +} diff --git a/security/nss/lib/pk11wrap/pk11pqg.c b/security/nss/lib/pk11wrap/pk11pqg.c index dcd9296a896..dd5e5ef3c75 100644 --- a/security/nss/lib/pk11wrap/pk11pqg.c +++ b/security/nss/lib/pk11wrap/pk11pqg.c @@ -40,6 +40,7 @@ #include "pk11func.h" #include "secmod.h" #include "secmodi.h" +#include "secmodti.h" #include "pkcs11t.h" #include "pk11pqg.h" #include "pqgutil.h" diff --git a/security/nss/lib/pk11wrap/pk11priv.h b/security/nss/lib/pk11wrap/pk11priv.h new file mode 100644 index 00000000000..3c1d4fc391b --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11priv.h @@ -0,0 +1,217 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef _PK11PRIV_H_ +#define _PK11PRIV_H_ +#include "plarena.h" +#include "seccomon.h" +#include "secoidt.h" +#include "secdert.h" +#include "keyt.h" +#include "certt.h" +#include "pkcs11t.h" +#include "secmodt.h" +#include "seccomon.h" +#include "pkcs7t.h" +#include "cmsreclist.h" + +/* + * These are the private NSS functions. They are not exported by nss.def, and + * are not callable outside nss3.dll. + */ + +SEC_BEGIN_PROTOS + +/************************************************************ + * Generic Slot Lists Management + ************************************************************/ +PK11SlotList * PK11_NewSlotList(void); +PK11SlotList * PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type, + PRBool needRW,void *wincx); +SECStatus PK11_AddSlotToList(PK11SlotList *list,PK11SlotInfo *slot); +SECStatus PK11_DeleteSlotFromList(PK11SlotList *list,PK11SlotListElement *le); +PK11SlotListElement *PK11_FindSlotElement(PK11SlotList *list, + PK11SlotInfo *slot); +PK11SlotInfo *PK11_FindSlotBySerial(char *serial); + +/************************************************************ + * Generic Slot Management + ************************************************************/ +CK_OBJECT_HANDLE PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject); +SECStatus PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type, PRArenaPool *arena, SECItem *result); +CK_ULONG PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type); +char * PK11_MakeString(PRArenaPool *arena,char *space,char *staticSring, + int stringLen); +int PK11_MapError(CK_RV error); +CK_SESSION_HANDLE PK11_GetRWSession(PK11SlotInfo *slot); +void PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession); +PRBool PK11_RWSessionHasLock(PK11SlotInfo *slot, + CK_SESSION_HANDLE session_handle); +PK11SlotInfo *PK11_NewSlotInfo(SECMODModule *mod); +void PK11_EnterSlotMonitor(PK11SlotInfo *); +void PK11_ExitSlotMonitor(PK11SlotInfo *); +void PK11_CleanKeyList(PK11SlotInfo *slot); + + +/************************************************************ + * Slot Password Management + ************************************************************/ +SECStatus PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx); +SECStatus PK11_VerifyPW(PK11SlotInfo *slot,char *pw); +void PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx); +void PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func); +void PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func); + +/************************************************************ + * Manage the built-In Slot Lists + ************************************************************/ +SECStatus PK11_InitSlotLists(void); +void PK11_DestroySlotLists(void); +PK11SlotList *PK11_GetSlotList(CK_MECHANISM_TYPE type); +void PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count); +void PK11_ClearSlotList(PK11SlotInfo *slot); + + +/****************************************************************** + * Slot initialization + ******************************************************************/ +PRBool PK11_VerifyMechanism(PK11SlotInfo *slot,PK11SlotInfo *intern, + CK_MECHANISM_TYPE mech, SECItem *data, SECItem *iv); +PRBool PK11_VerifySlotMechanisms(PK11SlotInfo *slot); +SECStatus pk11_CheckVerifyTest(PK11SlotInfo *slot); +SECStatus PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts); +void PK11_InitSlot(SECMODModule *mod,CK_SLOT_ID slotID,PK11SlotInfo *slot); +PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot); +SECStatus PK11_ReadSlotCerts(PK11SlotInfo *slot); + +/********************************************************************* + * Mechanism Mapping functions + *********************************************************************/ +void PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key, + CK_MECHANISM_TYPE keygen, int ivLen, int blocksize); +CK_MECHANISM_TYPE PK11_GetKeyMechanism(CK_KEY_TYPE type); +CK_MECHANISM_TYPE PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size); + +/********************************************************************** + * Symetric, Public, and Private Keys + **********************************************************************/ +PK11SymKey *PK11_CreateSymKey(PK11SlotInfo *slot, + CK_MECHANISM_TYPE type, PRBool owner, void *wincx); +/* Key Generation specialized for SDR (fixed DES3 key) */ +PK11SymKey *PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx); +SECKEYPublicKey *PK11_ExtractPublicKey(PK11SlotInfo *slot, KeyType keyType, + CK_OBJECT_HANDLE id); +CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate *cert, + void *wincx, PK11SlotInfo **pSlot); +PK11SymKey * pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey); + +/********************************************************************** + * Certs + **********************************************************************/ +CERTCertificate *PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey); +SECStatus PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, + SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg); +SECKEYPrivateKey * PK11_FindPrivateKeyFromNickname(char *nickname, void *wincx); +CK_OBJECT_HANDLE * PK11_FindObjectsFromNickname(char *nickname, + PK11SlotInfo **slotptr, CK_OBJECT_CLASS objclass, int *returnCount, + void *wincx); +CK_OBJECT_HANDLE PK11_MatchItem(PK11SlotInfo *slot,CK_OBJECT_HANDLE peer, + CK_OBJECT_CLASS o_class); +CK_BBOOL PK11_HasAttributeSet( PK11SlotInfo *slot, + CK_OBJECT_HANDLE id, + CK_ATTRIBUTE_TYPE type ); +CK_RV PK11_GetAttributes(PRArenaPool *arena,PK11SlotInfo *slot, + CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count); +int PK11_NumberCertsForCertSubject(CERTCertificate *cert); +SECStatus PK11_TraverseCertsForSubject(CERTCertificate *cert, + SECStatus(*callback)(CERTCertificate *, void *), void *arg); +CERTCertificate *PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, + SECItem *derCert, void *wincx); +CERTCertificate *PK11_FindCertFromDERSubjectAndNickname( + PK11SlotInfo *slot, + CERTCertificate *cert, char *nickname, + void *wincx); +SECStatus PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, + PK11SlotInfo *slot2, CERTCertificate **cert1, CERTCertificate **cert2); +SECStatus PK11_TraverseCertsInSlot(PK11SlotInfo *slot, + SECStatus(* callback)(CERTCertificate*, void *), void *arg); +SECStatus PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx); + + +/********************************************************************** + * Crypto Contexts + **********************************************************************/ +PK11Context * PK11_CreateContextByRawKey(PK11SlotInfo *slot, + CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, + SECItem *key, SECItem *param, void *wincx); +PRBool PK11_HashOK(SECOidTag hashAlg); + + +/********************************************************************** + * Functions which are depricated.... + **********************************************************************/ + +SECItem * +PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *handle, + SECItem *derName, int type, char **url); + +CK_OBJECT_HANDLE +PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, + SECItem *name, char *url, int type); + +SECItem * +PK11_FindSMimeProfile(PK11SlotInfo **slotp, char *emailAddr, SECItem *derSubj, + SECItem **profileTime); +SECStatus +PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, + SECItem *emailProfile, SECItem *profileTime); + +PRBool PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle); + +char * PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) ; +SECStatus PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, + const char *nickname) ; + + +/* private */ +SECStatus pk11_TraverseAllSlots( SECStatus (*callback)(PK11SlotInfo *,void *), + void *cbArg, void *pwArg); + +SEC_END_PROTOS + +#endif diff --git a/security/nss/lib/pk11wrap/pk11pub.h b/security/nss/lib/pk11wrap/pk11pub.h new file mode 100644 index 00000000000..62cfc6712a4 --- /dev/null +++ b/security/nss/lib/pk11wrap/pk11pub.h @@ -0,0 +1,583 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Douglas Stebila , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#ifndef _PK11PUB_H_ +#define _PK11PUB_H_ +#include "plarena.h" +#include "seccomon.h" +#include "secoidt.h" +#include "secdert.h" +#include "keyt.h" +#include "certt.h" +#include "pkcs11t.h" +#include "secmodt.h" +#include "seccomon.h" +#include "pkcs7t.h" +#include "cmsreclist.h" + +/* + * Exported PK11 wrap functions. + */ + +SEC_BEGIN_PROTOS + +/************************************************************ + * Generic Slot Lists Management + ************************************************************/ +void PK11_FreeSlotList(PK11SlotList *list); +PK11SlotListElement * PK11_GetFirstSafe(PK11SlotList *list); +PK11SlotListElement *PK11_GetNextSafe(PK11SlotList *list, + PK11SlotListElement *le, PRBool restart); + +/************************************************************ + * Generic Slot Management + ************************************************************/ +PK11SlotInfo *PK11_ReferenceSlot(PK11SlotInfo *slot); +void PK11_FreeSlot(PK11SlotInfo *slot); +SECStatus PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object); +SECStatus PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object); +PK11SlotInfo *PK11_GetInternalKeySlot(void); +PK11SlotInfo *PK11_GetInternalSlot(void); +SECStatus PK11_Logout(PK11SlotInfo *slot); +void PK11_LogoutAll(void); + + +/************************************************************ + * Slot Password Management + ************************************************************/ +void PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout); +void PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout); +SECStatus PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw); +SECStatus PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw); +PRBool PK11_IsLoggedIn(PK11SlotInfo *slot, void *wincx); +SECStatus PK11_InitPin(PK11SlotInfo *slot,char *ssopw, char *pk11_userpwd); +SECStatus PK11_ChangePW(PK11SlotInfo *slot,char *oldpw, char *newpw); +void PK11_SetPasswordFunc(PK11PasswordFunc func); +int PK11_GetMinimumPwdLength(PK11SlotInfo *slot); +SECStatus PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd); +SECStatus PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx); +SECStatus PK11_TokenRefresh(PK11SlotInfo *slot); + + +/****************************************************************** + * Slot info functions + ******************************************************************/ +PK11SlotInfo *PK11_FindSlotByName(char *name); +/****************************************************************** + * PK11_FindSlotsByNames searches for a PK11SlotInfo using one or + * more criteria : dllName, slotName and tokenName . In addition, if + * presentOnly is set , only slots with a token inserted will be + * returned. + ******************************************************************/ +PK11SlotList *PK11_FindSlotsByNames(const char *dllName, + const char* slotName, const char* tokenName, PRBool presentOnly); +PRBool PK11_IsReadOnly(PK11SlotInfo *slot); +PRBool PK11_IsInternal(PK11SlotInfo *slot); +char * PK11_GetTokenName(PK11SlotInfo *slot); +char * PK11_GetSlotName(PK11SlotInfo *slot); +PRBool PK11_NeedLogin(PK11SlotInfo *slot); +PRBool PK11_IsFriendly(PK11SlotInfo *slot); +PRBool PK11_IsHW(PK11SlotInfo *slot); +PRBool PK11_NeedUserInit(PK11SlotInfo *slot); +PRBool PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot); +int PK11_GetSlotSeries(PK11SlotInfo *slot); +int PK11_GetCurrentWrapIndex(PK11SlotInfo *slot); +unsigned long PK11_GetDefaultFlags(PK11SlotInfo *slot); +CK_SLOT_ID PK11_GetSlotID(PK11SlotInfo *slot); +SECMODModuleID PK11_GetModuleID(PK11SlotInfo *slot); +SECStatus PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info); +SECStatus PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info); +PRBool PK11_IsDisabled(PK11SlotInfo *slot); +PRBool PK11_HasRootCerts(PK11SlotInfo *slot); +PK11DisableReasons PK11_GetDisabledReason(PK11SlotInfo *slot); +/* Prevents the slot from being used, and set disable reason to user-disable */ +/* NOTE: Mechanisms that were ON continue to stay ON */ +/* Therefore, when the slot is enabled, it will remember */ +/* what mechanisms needs to be turned on */ +PRBool PK11_UserDisableSlot(PK11SlotInfo *slot); +/* Allow all mechanisms that are ON before UserDisableSlot() */ +/* was called to be available again */ +PRBool PK11_UserEnableSlot(PK11SlotInfo *slot); +/* + * wait for a specific slot event. + * event is a specific event to wait for. Currently only + * PK11TokenChangeOrRemovalEvent and PK11TokenPresentEvents are defined. + * timeout can be an interval time to wait, PR_INTERVAL_NO_WAIT (meaning only + * poll once), or PR_INTERVAL_NO_TIMEOUT (meaning block until a change). + * pollInterval is a suggested pulling interval value. '0' means use the + * default. Future implementations that don't poll may ignore this value. + * series is the current series for the last slot. This should be the series + * value for the slot the last time you read persistant information from the + * slot. For instance, if you publish a cert from the slot, you should obtain + * the slot series at that time. Then PK11_WaitForTokenEvent can detect a + * a change in the slot between the time you publish and the time + * PK11_WaitForTokenEvent is called, elliminating potential race conditions. + * + * The current status that is returned is: + * PK11TokenNotRemovable - always returned for any non-removable token. + * PK11TokenPresent - returned when the token is present and we are waiting + * on a PK11TokenPresentEvent. Then next event to look for is a + * PK11TokenChangeOrRemovalEvent. + * PK11TokenChanged - returned when the old token has been removed and a new + * token ad been inserted, and we are waiting for a + * PK11TokenChangeOrRemovalEvent. The next event to look for is another + * PK11TokenChangeOrRemovalEvent. + * PK11TokenRemoved - returned when the token is not present and we are + * waiting for a PK11TokenChangeOrRemovalEvent. The next event to look for + * is a PK11TokenPresentEvent. + */ +PK11TokenStatus PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event, + PRIntervalTime timeout, PRIntervalTime pollInterval, int series); + +PRBool PK11_NeedPWInit(void); +PRBool PK11_TokenExists(CK_MECHANISM_TYPE); +SECStatus PK11_GetModInfo(SECMODModule *mod, CK_INFO *info); +PRBool PK11_IsFIPS(void); +SECMODModule *PK11_GetModule(PK11SlotInfo *slot); + +/********************************************************************* + * Slot mapping utility functions. + *********************************************************************/ +PRBool PK11_IsPresent(PK11SlotInfo *slot); +PRBool PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type); +PK11SlotList * PK11_GetAllTokens(CK_MECHANISM_TYPE type,PRBool needRW, + PRBool loadCerts, void *wincx); +PK11SlotInfo *PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type, int count, + void *wincx); +PK11SlotInfo *PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx); +CK_MECHANISM_TYPE PK11_GetBestWrapMechanism(PK11SlotInfo *slot); +int PK11_GetBestKeyLength(PK11SlotInfo *slot, CK_MECHANISM_TYPE type); + +/********************************************************************* + * Mechanism Mapping functions + *********************************************************************/ +CK_MECHANISM_TYPE PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len); +CK_MECHANISM_TYPE PK11_GetKeyGen(CK_MECHANISM_TYPE type); +int PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params); +int PK11_GetIVLength(CK_MECHANISM_TYPE type); +SECItem *PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv); +unsigned char *PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len); +SECItem * PK11_BlockData(SECItem *data,unsigned long size); + +/* PKCS #11 to DER mapping functions */ +SECItem *PK11_ParamFromAlgid(SECAlgorithmID *algid); +SECItem *PK11_GenerateNewParam(CK_MECHANISM_TYPE, PK11SymKey *); +CK_MECHANISM_TYPE PK11_AlgtagToMechanism(SECOidTag algTag); +SECOidTag PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type); +SECOidTag PK11_FortezzaMapSig(SECOidTag algTag); +SECStatus PK11_ParamToAlgid(SECOidTag algtag, SECItem *param, + PRArenaPool *arena, SECAlgorithmID *algid); +SECStatus PK11_SeedRandom(PK11SlotInfo *,unsigned char *data,int len); +SECStatus PK11_RandomUpdate(void *data, size_t bytes); +SECStatus PK11_GenerateRandom(unsigned char *data,int len); +CK_RV PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, + CK_MECHANISM_PTR pCryptoMechanism, + SECItem *pbe_pwd, PRBool bad3DES); +CK_MECHANISM_TYPE PK11_GetPadMechanism(CK_MECHANISM_TYPE); + +/********************************************************************** + * Symetric, Public, and Private Keys + **********************************************************************/ +void PK11_FreeSymKey(PK11SymKey *key); +PK11SymKey *PK11_ReferenceSymKey(PK11SymKey *symKey); +PK11SymKey *PK11_ImportSymKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, void *wincx); +PK11SymKey *PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, + CK_MECHANISM_TYPE type, PK11Origin origin, CK_ATTRIBUTE_TYPE operation, + SECItem *key, CK_FLAGS flags, PRBool isPerm, void *wincx); +PK11SymKey *PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, + PK11Origin origin, CK_MECHANISM_TYPE type, CK_OBJECT_HANDLE keyID, + PRBool owner, void *wincx); +PK11SymKey *PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, + CK_MECHANISM_TYPE type,int series, void *wincx); +/* + * This function is not thread-safe. It can only be called when only + * one thread has a reference to wrapKey. + */ +void PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey); +CK_MECHANISM_TYPE PK11_GetMechanism(PK11SymKey *symKey); +CK_OBJECT_HANDLE PK11_ImportPublicKey(PK11SlotInfo *slot, + SECKEYPublicKey *pubKey, PRBool isToken); +PK11SymKey *PK11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, + SECItem *param, int keySize,void *wincx); +PK11SymKey *PK11_TokenKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + SECItem *param, int keySize, SECItem *keyid, + PRBool isToken, void *wincx); +PK11SymKey * PK11_ListFixedKeysInSlot(PK11SlotInfo *slot, char *nickname, + void *wincx); +PK11SymKey *PK11_GetNextSymKey(PK11SymKey *symKey); +CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *key); + +SECStatus PK11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey, + PK11SymKey *symKey, SECItem *wrappedKey); +SECStatus PK11_WrapSymKey(CK_MECHANISM_TYPE type, SECItem *params, + PK11SymKey *wrappingKey, PK11SymKey *symKey, SECItem *wrappedKey); +/* move a key to 'slot' optionally set the key attributes according to either + * operation or the flags and making the key permanent at the same time. + * If the key is moved to the same slot, operation and flags values are + * currently ignored */ +PK11SymKey *PK11_MoveSymKey(PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, + CK_FLAGS flags, PRBool perm, PK11SymKey *symKey); +/* + * derive a new key from the base key. + * PK11_Derive returns a key which can do exactly one operation, and is + * ephemeral (session key). + * PK11_DeriveWithFlags is the same as PK11_Derive, except you can use + * CKF_ flags to enable more than one operation. + * PK11_DeriveWithFlagsPerm is the same as PK11_DeriveWithFlags except you can + * (optionally) make the key permanent (token key). + */ +PK11SymKey *PK11_Derive(PK11SymKey *baseKey, CK_MECHANISM_TYPE mechanism, + SECItem *param, CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, int keySize); +PK11SymKey *PK11_DeriveWithFlags( PK11SymKey *baseKey, + CK_MECHANISM_TYPE derive, SECItem *param, CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, int keySize, CK_FLAGS flags); +PK11SymKey * PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, + CK_MECHANISM_TYPE derive, + SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, + int keySize, CK_FLAGS flags, PRBool isPerm); + +PK11SymKey *PK11_PubDerive( SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey, PRBool isSender, SECItem *randomA, SECItem *randomB, + CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, int keySize,void *wincx) ; +PK11SymKey *PK11_PubDeriveWithKDF( SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey, PRBool isSender, SECItem *randomA, SECItem *randomB, + CK_MECHANISM_TYPE derive, CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, int keySize, + CK_ULONG kdf, SECItem *sharedData, void *wincx); + +/* + * unwrap a new key with a symetric key. + * PK11_Unwrap returns a key which can do exactly one operation, and is + * ephemeral (session key). + * PK11_UnwrapWithFlags is the same as PK11_Unwrap, except you can use + * CKF_ flags to enable more than one operation. + * PK11_UnwrapWithFlagsPerm is the same as PK11_UnwrapWithFlags except you can + * (optionally) make the key permanent (token key). + */ +PK11SymKey *PK11_UnwrapSymKey(PK11SymKey *key, + CK_MECHANISM_TYPE wraptype, SECItem *param, SECItem *wrapppedKey, + CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize); +PK11SymKey *PK11_UnwrapSymKeyWithFlags(PK11SymKey *wrappingKey, + CK_MECHANISM_TYPE wrapType, SECItem *param, SECItem *wrappedKey, + CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize, + CK_FLAGS flags); +PK11SymKey * PK11_UnwrapSymKeyWithFlagsPerm(PK11SymKey *wrappingKey, + CK_MECHANISM_TYPE wrapType, + SECItem *param, SECItem *wrappedKey, + CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, + int keySize, CK_FLAGS flags, PRBool isPerm); + +/* + * unwrap a new key with a private key. + * PK11_PubUnwrap returns a key which can do exactly one operation, and is + * ephemeral (session key). + * PK11_PubUnwrapWithFlagsPerm is the same as PK11_PubUnwrap except you can + * use * CKF_ flags to enable more than one operation, and optionally make + * the key permanent (token key). + */ +PK11SymKey *PK11_PubUnwrapSymKey(SECKEYPrivateKey *key, SECItem *wrapppedKey, + CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize); +PK11SymKey * PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, + SECItem *wrappedKey, CK_MECHANISM_TYPE target, + CK_ATTRIBUTE_TYPE operation, int keySize, + CK_FLAGS flags, PRBool isPerm); +PK11SymKey *PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + SECItem *keyID, void *wincx); +SECStatus PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey,PRBool force); +SECStatus PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey); +SECStatus PK11_DeleteTokenSymKey(PK11SymKey *symKey); +SECStatus PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx); +SECKEYPrivateKey * PK11_LoadPrivKey(PK11SlotInfo *slot, + SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, + PRBool token, PRBool sensitive); +char * PK11_GetSymKeyNickname(PK11SymKey *symKey); +char * PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey); +char * PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey); +SECStatus PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname); +SECStatus PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, + const char *nickname); +SECStatus PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, + const char *nickname); + +/* size to hold key in bytes */ +unsigned int PK11_GetKeyLength(PK11SymKey *key); +/* size of actual secret parts of key in bits */ +/* algid is because RC4 strength is determined by the effective bits as well + * as the key bits */ +unsigned int PK11_GetKeyStrength(PK11SymKey *key,SECAlgorithmID *algid); +SECStatus PK11_ExtractKeyValue(PK11SymKey *symKey); +SECItem * PK11_GetKeyData(PK11SymKey *symKey); +PK11SlotInfo * PK11_GetSlotFromKey(PK11SymKey *symKey); +void *PK11_GetWindow(PK11SymKey *symKey); +SECKEYPrivateKey *PK11_GenerateKeyPair(PK11SlotInfo *slot, + CK_MECHANISM_TYPE type, void *param, SECKEYPublicKey **pubk, + PRBool isPerm, PRBool isSensitive, void *wincx); +SECKEYPrivateKey * PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, + CERTCertificate *cert, void *wincx); +SECKEYPrivateKey * PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx); +SECKEYPrivateKey * PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, + void *wincx); +int PK11_GetPrivateModulusLen(SECKEYPrivateKey *key); +SECStatus PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, + unsigned *outLen, unsigned int maxLen, unsigned char *enc, unsigned encLen); +/* The encrypt version of the above function */ +SECStatus PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc, + unsigned char *data, unsigned dataLen, void *wincx); +SECStatus PK11_ImportPrivateKeyInfo(PK11SlotInfo *slot, + SECKEYPrivateKeyInfo *pki, SECItem *nickname, + SECItem *publicValue, PRBool isPerm, PRBool isPrivate, + unsigned int usage, void *wincx); +SECStatus PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, + SECKEYPrivateKeyInfo *pki, SECItem *nickname, + SECItem *publicValue, PRBool isPerm, PRBool isPrivate, + unsigned int usage, SECKEYPrivateKey** privk, void *wincx); +SECStatus PK11_ImportDERPrivateKeyInfo(PK11SlotInfo *slot, + SECItem *derPKI, SECItem *nickname, + SECItem *publicValue, PRBool isPerm, PRBool isPrivate, + unsigned int usage, void *wincx); +SECStatus PK11_ImportDERPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, + SECItem *derPKI, SECItem *nickname, + SECItem *publicValue, PRBool isPerm, PRBool isPrivate, + unsigned int usage, SECKEYPrivateKey** privk, void *wincx); +SECStatus PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, + SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, + SECItem *nickname, SECItem *publicValue, PRBool isPerm, + PRBool isPrivate, KeyType type, + unsigned int usage, void *wincx); +SECKEYPrivateKeyInfo *PK11_ExportPrivateKeyInfo( + CERTCertificate *cert, void *wincx); +SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivKeyInfo( + PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem, + SECKEYPrivateKey *pk, int iteration, void *wincx); +SECKEYEncryptedPrivateKeyInfo *PK11_ExportEncryptedPrivateKeyInfo( + PK11SlotInfo *slot, SECOidTag algTag, SECItem *pwitem, + CERTCertificate *cert, int iteration, void *wincx); +SECKEYPrivateKey *PK11_FindKeyByDERCert(PK11SlotInfo *slot, + CERTCertificate *cert, void *wincx); +SECKEYPublicKey *PK11_MakeKEAPubKey(unsigned char *data, int length); +SECStatus PK11_DigestKey(PK11Context *context, PK11SymKey *key); +PRBool PK11_VerifyKeyOK(PK11SymKey *key); +SECKEYPrivateKey *PK11_UnwrapPrivKey(PK11SlotInfo *slot, + PK11SymKey *wrappingKey, CK_MECHANISM_TYPE wrapType, + SECItem *param, SECItem *wrappedKey, SECItem *label, + SECItem *publicValue, PRBool token, PRBool sensitive, + CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, int usageCount, + void *wincx); +SECStatus PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, + SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, + SECItem *param, SECItem *wrappedKey, void *wincx); +SECItem* PK11_DEREncodePublicKey(SECKEYPublicKey *pubk); +PK11SymKey* PK11_CopySymKeyForSigning(PK11SymKey *originalKey, + CK_MECHANISM_TYPE mech); +SECKEYPrivateKeyList* PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, + char *nickname, void *wincx); +SECKEYPublicKeyList* PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, + char *nickname); +SECKEYPQGParams *PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey); +/* depricated */ +SECKEYPrivateKeyList* PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot); + +PK11SymKey *PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, + void *wincx); +SECKEYPrivateKey *PK11_ConvertSessionPrivKeyToTokenPrivKey( + SECKEYPrivateKey *privk, void* wincx); + +/********************************************************************** + * Certs + **********************************************************************/ +SECItem *PK11_MakeIDFromPubKey(SECItem *pubKeyData); +SECStatus PK11_TraverseSlotCerts( + SECStatus(* callback)(CERTCertificate*,SECItem *,void *), + void *arg, void *wincx); +CERTCertificate * PK11_FindCertFromNickname(char *nickname, void *wincx); +CERTCertList * PK11_FindCertsFromNickname(char *nickname, void *wincx); +SECStatus PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, + CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust); +SECStatus PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert, + CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust); +PK11SlotInfo *PK11_ImportCertForKey(CERTCertificate *cert, char *nickname, + void *wincx); +PK11SlotInfo *PK11_ImportDERCertForKey(SECItem *derCert, char *nickname, + void *wincx); +PK11SlotInfo *PK11_KeyForCertExists(CERTCertificate *cert, + CK_OBJECT_HANDLE *keyPtr, void *wincx); +PK11SlotInfo *PK11_KeyForDERCertExists(SECItem *derCert, + CK_OBJECT_HANDLE *keyPtr, void *wincx); +CERTCertificate * PK11_FindCertByIssuerAndSN(PK11SlotInfo **slot, + CERTIssuerAndSN *sn, void *wincx); +CERTCertificate * PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slot, + SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip, + SECKEYPrivateKey**privKey, void *wincx); +int PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, + void *wincx); +SECStatus PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, + PK11SlotInfo *slot, SECStatus(*callback)(CERTCertificate *, void *), + void *arg); +CERTCertificate *PK11_FindCertFromDERCert(PK11SlotInfo *slot, + CERTCertificate *cert, void *wincx); +SECStatus PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert, + char *nickname, PRBool addUsage, + void *wincx); +CERTCertificate *PK11_FindBestKEAMatch(CERTCertificate *serverCert,void *wincx); +PRBool PK11_FortezzaHasKEA(CERTCertificate *cert); +CK_OBJECT_HANDLE PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, + void *wincx); +SECStatus PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, + PK11SlotInfo *slot, SECStatus(*callback)(CERTCertificate *, void *), + void *arg); +CERTCertList * PK11_ListCerts(PK11CertListType type, void *pwarg); +CERTCertList * PK11_ListCertsInSlot(PK11SlotInfo *slot); +CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, + int type, void *wincx, PRInt32 importOptions, PRArenaPool* arena, PRInt32 decodeOptions); + +/********************************************************************** + * Sign/Verify + **********************************************************************/ +int PK11_SignatureLen(SECKEYPrivateKey *key); +PK11SlotInfo * PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key); +SECStatus PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash); +SECStatus PK11_VerifyRecover(SECKEYPublicKey *key, SECItem *sig, + SECItem *dsig, void * wincx); +SECStatus PK11_Verify(SECKEYPublicKey *key, SECItem *sig, + SECItem *hash, void *wincx); + + + +/********************************************************************** + * Crypto Contexts + **********************************************************************/ +void PK11_DestroyContext(PK11Context *context, PRBool freeit); +PK11Context *PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, SECItem *param); +PK11Context *PK11_CreateDigestContext(SECOidTag hashAlg); +PK11Context *PK11_CloneContext(PK11Context *old); +SECStatus PK11_DigestBegin(PK11Context *cx); +SECStatus PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in, + int32 len); +SECStatus PK11_DigestOp(PK11Context *context, const unsigned char *in, + unsigned len); +SECStatus PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, + int maxout, unsigned char *in, int inlen); +SECStatus PK11_Finalize(PK11Context *context); +SECStatus PK11_DigestFinal(PK11Context *context, unsigned char *data, + unsigned int *outLen, unsigned int length); +SECStatus PK11_SaveContext(PK11Context *cx,unsigned char *save, + int *len, int saveLength); + +/* Save the context's state, with possible allocation. + * The caller may supply an already allocated buffer in preAllocBuf, + * with length pabLen. If the buffer is large enough for the context's + * state, it will receive the state. + * If the buffer is not large enough (or NULL), then a new buffer will + * be allocated with PORT_Alloc. + * In either case, the state will be returned as a buffer, and the length + * of the state will be given in *stateLen. + */ +unsigned char * +PK11_SaveContextAlloc(PK11Context *cx, + unsigned char *preAllocBuf, unsigned int pabLen, + unsigned int *stateLen); + +SECStatus PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len); +SECStatus PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len); +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 * +PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem, + PRBool faulty3DES, void *wincx); +PK11SymKey * +PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *params, + SECItem *pwitem, PRBool faulty3DES, void *wincx); +SECItem * +PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem); + +/********************************************************************** + * Functions to manage secmod flags + **********************************************************************/ +PK11DefaultArrayEntry * PK11_GetDefaultArray(int *); +SECStatus PK11_UpdateSlotAttribute(PK11SlotInfo *, PK11DefaultArrayEntry *, + PRBool ); + +/********************************************************************** + * Functions to look at PKCS #11 dependent data + **********************************************************************/ +PK11GenericObject *PK11_FindGenericObjects(PK11SlotInfo *slot, + CK_OBJECT_CLASS objClass); +PK11GenericObject *PK11_GetNextGenericObject(PK11GenericObject *object); +PK11GenericObject *PK11_GetPrevtGenericObject(PK11GenericObject *object); +SECStatus PK11_UnlinkGenericObject(PK11GenericObject *object); +SECStatus PK11_LinkGenericObject(PK11GenericObject *list, + PK11GenericObject *object); +SECStatus PK11_DestroyGenericObjects(PK11GenericObject *object); +SECStatus PK11_DestroyGenericObject(PK11GenericObject *object); +SECStatus PK11_ReadRawAttribute(PK11ObjectType type, void *object, + CK_ATTRIBUTE_TYPE attr, SECItem *item); + + +/********************************************************************** + * New fucntions which are already depricated.... + **********************************************************************/ +SECItem * +PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot, + CERTCertificate *cert, void *pwarg); +SECItem * +PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *key); + +PRBool SECMOD_HasRootCerts(void); + +SEC_END_PROTOS + +#endif diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c index e2e939cdafc..4aad6fc3298 100644 --- a/security/nss/lib/pk11wrap/pk11skey.c +++ b/security/nss/lib/pk11wrap/pk11skey.c @@ -19,7 +19,6 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Dr Stephen Henson * Dr Vipul Gupta and * Douglas Stebila , Sun Microsystems Laboratories * @@ -45,23 +44,12 @@ #include "secmod.h" #include "nssilock.h" #include "secmodi.h" +#include "secmodti.h" #include "pkcs11.h" #include "pk11func.h" #include "secitem.h" -#include "key.h" #include "secoid.h" -#include "secasn1.h" -#include "sechash.h" -#include "cert.h" #include "secerr.h" -#include "secpkcs5.h" -#include "ec.h" - -#define PAIRWISE_SECITEM_TYPE siBuffer -#define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */ -#define PAIRWISE_MESSAGE_LENGTH 20 /* 160-bits */ - -static const SECItem pk11_null_params = { 0 }; /* forward static declarations. */ static PK11SymKey *pk11_DeriveWithTemplate(PK11SymKey *baseKey, @@ -69,86 +57,6 @@ static PK11SymKey *pk11_DeriveWithTemplate(PK11SymKey *baseKey, CK_ATTRIBUTE_TYPE operation, int keySize, CK_ATTRIBUTE *userAttr, unsigned int numAttrs, PRBool isPerm); -static PRBool pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, - unsigned int numAttrs, CK_ATTRIBUTE_TYPE target); - -/* - * strip leading zero's from key material - */ -void -pk11_SignedToUnsigned(CK_ATTRIBUTE *attrib) { - char *ptr = (char *)attrib->pValue; - unsigned long len = attrib->ulValueLen; - - while (len && (*ptr == 0)) { - len--; - ptr++; - } - attrib->pValue = ptr; - attrib->ulValueLen = len; -} - -/* - * get a new session on a slot. If we run out of session, use the slot's - * 'exclusive' session. In this case owner becomes false. - */ -static CK_SESSION_HANDLE -pk11_GetNewSession(PK11SlotInfo *slot,PRBool *owner) -{ - CK_SESSION_HANDLE session; - *owner = PR_TRUE; - if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); - if ( PK11_GETTAB(slot)->C_OpenSession(slot->slotID,CKF_SERIAL_SESSION, - slot,pk11_notify,&session) != CKR_OK) { - *owner = PR_FALSE; - session = slot->session; - } - if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); - - return session; -} - -static void -pk11_CloseSession(PK11SlotInfo *slot,CK_SESSION_HANDLE session,PRBool owner) -{ - if (!owner) return; - if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); - (void) PK11_GETTAB(slot)->C_CloseSession(session); - if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); -} - - -SECStatus -PK11_CreateNewObject(PK11SlotInfo *slot, CK_SESSION_HANDLE session, - CK_ATTRIBUTE *theTemplate, int count, - PRBool token, CK_OBJECT_HANDLE *objectID) -{ - CK_SESSION_HANDLE rwsession; - CK_RV crv; - SECStatus rv = SECSuccess; - - rwsession = session; - if (token) { - rwsession = PK11_GetRWSession(slot); - } else if (rwsession == CK_INVALID_SESSION) { - rwsession = slot->session; - PK11_EnterSlotMonitor(slot); - } - crv = PK11_GETTAB(slot)->C_CreateObject(rwsession, theTemplate, - count,objectID); - if(crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - rv = SECFailure; - } - if (token) { - PK11_RestoreROSession(slot, rwsession); - } else if (session == CK_INVALID_SESSION) { - PK11_ExitSlotMonitor(slot); - } - - return rv; -} - static void pk11_EnterKeyMonitor(PK11SymKey *symKey) { if (!symKey->sessionOwner || !(symKey->slot->isThreadSafe)) @@ -282,6 +190,47 @@ PK11_ReferenceSymKey(PK11SymKey *symKey) return symKey; } +/* + * Accessors + */ +CK_MECHANISM_TYPE +PK11_GetMechanism(PK11SymKey *symKey) +{ + return symKey->type; +} + +/* + * return the slot associated with a symetric key + */ +PK11SlotInfo * +PK11_GetSlotFromKey(PK11SymKey *symKey) +{ + return PK11_ReferenceSlot(symKey->slot); +} + +CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey) +{ + return PK11_GetKeyType(symKey->type,symKey->size); +} + +PK11SymKey * +PK11_GetNextSymKey(PK11SymKey *symKey) +{ + return symKey ? symKey->next : NULL; +} + +char * +PK11_GetSymKeyNickname(PK11SymKey *symKey) +{ + return PK11_GetObjectNickname(symKey->slot,symKey->objectID); +} + +SECStatus +PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname) +{ + return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname); +} + /* * turn key handle into an appropriate key object */ @@ -352,11 +301,6 @@ PK11_SetWrapKey(PK11SlotInfo *slot, int wrap, PK11SymKey *wrapKey) slot->wrapMechanism = wrapKey->type; } -CK_MECHANISM_TYPE -PK11_GetMechanism(PK11SymKey *symKey) -{ - return symKey->type; -} /* * figure out if a key is still valid or if it is stale. @@ -369,39 +313,6 @@ PK11_VerifyKeyOK(PK11SymKey *key) { return (PRBool)(key->series == key->slot->series); } -#define MAX_TEMPL_ATTRS 16 /* maximum attributes in template */ - -/* This mask includes all CK_FLAGs with an equivalent CKA_ attribute. */ -#define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL - -static unsigned int -pk11_FlagsToAttributes(CK_FLAGS flags, CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue) -{ - - const static CK_ATTRIBUTE_TYPE attrTypes[12] = { - CKA_ENCRYPT, CKA_DECRYPT, 0 /* DIGEST */, CKA_SIGN, - CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, 0 /* GEN */, - 0 /* GEN PAIR */, CKA_WRAP, CKA_UNWRAP, CKA_DERIVE - }; - - const CK_ATTRIBUTE_TYPE *pType = attrTypes; - CK_ATTRIBUTE *attr = attrs; - CK_FLAGS test = CKF_ENCRYPT; - - - PR_ASSERT(!(flags & ~CKF_KEY_OPERATION_FLAGS)); - flags &= CKF_KEY_OPERATION_FLAGS; - - for (; flags && test <= CKF_DERIVE; test <<= 1, ++pType) { - if (test & flags) { - flags ^= test; - PK11_SETATTRS(attr, *pType, ckTrue, sizeof *ckTrue); - ++attr; - } - } - return (attr - attrs); -} - static PK11SymKey * pk11_ImportSymKeyWithTempl(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin, PRBool isToken, CK_ATTRIBUTE *keyTemplate, @@ -507,150 +418,6 @@ PK11_ImportSymKeyWithFlags(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, return symKey; } -/* - * import a public key into the desired slot - */ -CK_OBJECT_HANDLE -PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey, - PRBool isToken) -{ - CK_BBOOL cktrue = CK_TRUE; - CK_BBOOL ckfalse = CK_FALSE; - CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; - CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; - CK_OBJECT_HANDLE objectID; - CK_ATTRIBUTE theTemplate[10]; - CK_ATTRIBUTE *signedattr = NULL; - CK_ATTRIBUTE *attrs = theTemplate; - int signedcount = 0; - int templateCount = 0; - SECStatus rv; - - /* if we already have an object in the desired slot, use it */ - if (!isToken && pubKey->pkcs11Slot == slot) { - return pubKey->pkcs11ID; - } - - /* free the existing key */ - if (pubKey->pkcs11Slot != NULL) { - PK11SlotInfo *oSlot = pubKey->pkcs11Slot; - PK11_EnterSlotMonitor(oSlot); - (void) PK11_GETTAB(oSlot)->C_DestroyObject(oSlot->session, - pubKey->pkcs11ID); - PK11_ExitSlotMonitor(oSlot); - PK11_FreeSlot(oSlot); - pubKey->pkcs11Slot = NULL; - } - PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++; - PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++; - PK11_SETATTRS(attrs, CKA_TOKEN, isToken ? &cktrue : &ckfalse, - sizeof(CK_BBOOL) ); attrs++; - - /* now import the key */ - { - switch (pubKey->keyType) { - case rsaKey: - keyType = CKK_RSA; - PK11_SETATTRS(attrs, CKA_WRAP, &cktrue, sizeof(CK_BBOOL) ); attrs++; - PK11_SETATTRS(attrs, CKA_ENCRYPT, &cktrue, - sizeof(CK_BBOOL) ); attrs++; - PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); attrs++; - signedattr = attrs; - PK11_SETATTRS(attrs, CKA_MODULUS, pubKey->u.rsa.modulus.data, - pubKey->u.rsa.modulus.len); attrs++; - PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, - pubKey->u.rsa.publicExponent.data, - pubKey->u.rsa.publicExponent.len); attrs++; - break; - case dsaKey: - keyType = CKK_DSA; - PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; - signedattr = attrs; - PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dsa.params.prime.data, - pubKey->u.dsa.params.prime.len); attrs++; - PK11_SETATTRS(attrs,CKA_SUBPRIME,pubKey->u.dsa.params.subPrime.data, - pubKey->u.dsa.params.subPrime.len); attrs++; - PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dsa.params.base.data, - pubKey->u.dsa.params.base.len); attrs++; - PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dsa.publicValue.data, - pubKey->u.dsa.publicValue.len); attrs++; - break; - case fortezzaKey: - keyType = CKK_DSA; - PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; - signedattr = attrs; - PK11_SETATTRS(attrs, CKA_PRIME,pubKey->u.fortezza.params.prime.data, - pubKey->u.fortezza.params.prime.len); attrs++; - PK11_SETATTRS(attrs,CKA_SUBPRIME, - pubKey->u.fortezza.params.subPrime.data, - pubKey->u.fortezza.params.subPrime.len);attrs++; - PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.fortezza.params.base.data, - pubKey->u.fortezza.params.base.len); attrs++; - PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.fortezza.DSSKey.data, - pubKey->u.fortezza.DSSKey.len); attrs++; - break; - case dhKey: - keyType = CKK_DH; - PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; - signedattr = attrs; - PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dh.prime.data, - pubKey->u.dh.prime.len); attrs++; - PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dh.base.data, - pubKey->u.dh.base.len); attrs++; - PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dh.publicValue.data, - pubKey->u.dh.publicValue.len); attrs++; - break; -#ifdef NSS_ENABLE_ECC - case ecKey: - keyType = CKK_EC; - PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; - PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; - signedattr = attrs; - PK11_SETATTRS(attrs, CKA_EC_PARAMS, - pubKey->u.ec.DEREncodedParams.data, - pubKey->u.ec.DEREncodedParams.len); attrs++; - PK11_SETATTRS(attrs, CKA_EC_POINT, pubKey->u.ec.publicValue.data, - pubKey->u.ec.publicValue.len); attrs++; - break; -#endif /* NSS_ENABLE_ECC */ - default: - PORT_SetError( SEC_ERROR_BAD_KEY ); - return CK_INVALID_HANDLE; - } - - templateCount = attrs - theTemplate; - signedcount = attrs - signedattr; - PORT_Assert(templateCount <= (sizeof(theTemplate)/sizeof(CK_ATTRIBUTE))); - for (attrs=signedattr; signedcount; attrs++, signedcount--) { - pk11_SignedToUnsigned(attrs); - } - rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate, - templateCount, isToken, &objectID); - if ( rv != SECSuccess) { - return CK_INVALID_HANDLE; - } - } - - pubKey->pkcs11ID = objectID; - pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); - - return objectID; -} - - -/* - * return the slot associated with a symetric key - */ -PK11SlotInfo * -PK11_GetSlotFromKey(PK11SymKey *symKey) -{ - return PK11_ReferenceSlot(symKey->slot); -} - -CK_KEY_TYPE PK11_GetSymKeyType(PK11SymKey *symKey) -{ - return PK11_GetKeyType(symKey->type,symKey->size); -} PK11SymKey * PK11_FindFixedKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *keyID, @@ -790,273 +557,6 @@ PK11_GetKeyData(PK11SymKey *symKey) return __PK11_GetKeyData(symKey); } -/* - * take an attribute and copy it into a secitem - */ -static CK_RV -pk11_Attr2SecItem(PRArenaPool *arena, CK_ATTRIBUTE *attr, SECItem *item) -{ - item->data = NULL; - - (void)SECITEM_AllocItem(arena, item, attr->ulValueLen); - if (item->data == NULL) { - return CKR_HOST_MEMORY; - } - PORT_Memcpy(item->data, attr->pValue, item->len); - return CKR_OK; -} - -/* - * extract a public key from a slot and id - */ -SECKEYPublicKey * -PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) -{ - CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; - PRArenaPool *arena; - PRArenaPool *tmp_arena; - SECKEYPublicKey *pubKey; - int templateCount = 0; - CK_KEY_TYPE pk11KeyType; - CK_RV crv; - CK_ATTRIBUTE template[8]; - CK_ATTRIBUTE *attrs= template; - CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value; -#ifdef NSS_ENABLE_ECC - CK_ATTRIBUTE *ecparams; -#endif /* NSS_ENABLE_ECC */ - - /* if we didn't know the key type, get it */ - if (keyType== nullKey) { - - pk11KeyType = PK11_ReadULongAttribute(slot,id,CKA_KEY_TYPE); - if (pk11KeyType == CK_UNAVAILABLE_INFORMATION) { - return NULL; - } - switch (pk11KeyType) { - case CKK_RSA: - keyType = rsaKey; - break; - case CKK_DSA: - keyType = dsaKey; - break; - case CKK_DH: - keyType = dhKey; - break; -#ifdef NSS_ENABLE_ECC - case CKK_EC: - keyType = ecKey; - break; -#endif /* NSS_ENABLE_ECC */ - default: - PORT_SetError( SEC_ERROR_BAD_KEY ); - return NULL; - } - } - - - /* now we need to create space for the public key */ - arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) return NULL; - tmp_arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); - if (tmp_arena == NULL) { - PORT_FreeArena (arena, PR_FALSE); - return NULL; - } - - - pubKey = (SECKEYPublicKey *) - PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); - if (pubKey == NULL) { - PORT_FreeArena (arena, PR_FALSE); - PORT_FreeArena (tmp_arena, PR_FALSE); - return NULL; - } - - pubKey->arena = arena; - pubKey->keyType = keyType; - pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); - pubKey->pkcs11ID = id; - PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, - sizeof(keyClass)); attrs++; - PK11_SETATTRS(attrs, CKA_KEY_TYPE, &pk11KeyType, - sizeof(pk11KeyType) ); attrs++; - switch (pubKey->keyType) { - case rsaKey: - modulus = attrs; - PK11_SETATTRS(attrs, CKA_MODULUS, NULL, 0); attrs++; - exponent = attrs; - PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, NULL, 0); attrs++; - - templateCount = attrs - template; - PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); - crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); - if (crv != CKR_OK) break; - - if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_RSA)) { - crv = CKR_OBJECT_HANDLE_INVALID; - break; - } - crv = pk11_Attr2SecItem(arena,modulus,&pubKey->u.rsa.modulus); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,exponent,&pubKey->u.rsa.publicExponent); - if (crv != CKR_OK) break; - break; - case dsaKey: - prime = attrs; - PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; - subprime = attrs; - PK11_SETATTRS(attrs, CKA_SUBPRIME, NULL, 0); attrs++; - base = attrs; - PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; - value = attrs; - PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; - templateCount = attrs - template; - PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); - crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); - if (crv != CKR_OK) break; - - if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DSA)) { - crv = CKR_OBJECT_HANDLE_INVALID; - break; - } - crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dsa.params.prime); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,subprime,&pubKey->u.dsa.params.subPrime); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dsa.params.base); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dsa.publicValue); - if (crv != CKR_OK) break; - break; - case dhKey: - prime = attrs; - PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; - base = attrs; - PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; - value =attrs; - PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; - templateCount = attrs - template; - PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); - crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); - if (crv != CKR_OK) break; - - if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DH)) { - crv = CKR_OBJECT_HANDLE_INVALID; - break; - } - crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dh.prime); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dh.base); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue); - if (crv != CKR_OK) break; - break; -#ifdef NSS_ENABLE_ECC - case ecKey: - pubKey->u.ec.size = 0; - ecparams = attrs; - PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++; - value =attrs; - PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++; - templateCount = attrs - template; - PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); - crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); - if (crv != CKR_OK) break; - - if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) { - crv = CKR_OBJECT_HANDLE_INVALID; - break; - } - - crv = pk11_Attr2SecItem(arena,ecparams, - &pubKey->u.ec.DEREncodedParams); - if (crv != CKR_OK) break; - crv = pk11_Attr2SecItem(arena,value,&pubKey->u.ec.publicValue); - if (crv != CKR_OK) break; - break; -#endif /* NSS_ENABLE_ECC */ - case fortezzaKey: - case nullKey: - default: - crv = CKR_OBJECT_HANDLE_INVALID; - break; - } - - PORT_FreeArena(tmp_arena,PR_FALSE); - - if (crv != CKR_OK) { - PORT_FreeArena(arena,PR_FALSE); - PK11_FreeSlot(slot); - PORT_SetError( PK11_MapError(crv) ); - return NULL; - } - - return pubKey; -} - -/* - * Build a Private Key structure from raw PKCS #11 information. - */ -SECKEYPrivateKey * -PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, - PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx) -{ - PRArenaPool *arena; - SECKEYPrivateKey *privKey; - PRBool isPrivate; - SECStatus rv; - - /* don't know? look it up */ - if (keyType == nullKey) { - CK_KEY_TYPE pk11Type = CKK_RSA; - - pk11Type = PK11_ReadULongAttribute(slot,privID,CKA_KEY_TYPE); - isTemp = (PRBool)!PK11_HasAttributeSet(slot,privID,CKA_TOKEN); - switch (pk11Type) { - case CKK_RSA: keyType = rsaKey; break; - case CKK_DSA: keyType = dsaKey; break; - case CKK_DH: keyType = dhKey; break; - case CKK_KEA: keyType = fortezzaKey; break; -#ifdef NSS_ENABLE_ECC - case CKK_EC: keyType = ecKey; break; -#endif /* NSS_ENABLE_ECC */ - default: - break; - } - } - - /* if the key is private, make sure we are authenticated to the - * token before we try to use it */ - isPrivate = (PRBool)PK11_HasAttributeSet(slot,privID,CKA_PRIVATE); - if (isPrivate) { - rv = PK11_Authenticate(slot, PR_TRUE, wincx); - if (rv != SECSuccess) { - return NULL; - } - } - - /* now we need to create space for the private key */ - arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) return NULL; - - privKey = (SECKEYPrivateKey *) - PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey)); - if (privKey == NULL) { - PORT_FreeArena(arena, PR_FALSE); - return NULL; - } - - privKey->arena = arena; - privKey->keyType = keyType; - privKey->pkcs11Slot = PK11_ReferenceSlot(slot); - privKey->pkcs11ID = privID; - privKey->pkcs11IsTemp = isTemp; - privKey->wincx = wincx; - - return privKey; -} - /* return the keylength if possible. '0' if not */ unsigned int PK11_GetKeyLength(PK11SymKey *key) @@ -1180,201 +680,6 @@ PK11_GetKeyStrength(PK11SymKey *key, SECAlgorithmID *algid) return PK11_GetKeyLength(key) * 8; } -/* Make a Key type to an appropriate signing/verification mechanism */ -static CK_MECHANISM_TYPE -pk11_mapSignKeyType(KeyType keyType) -{ - switch (keyType) { - case rsaKey: - return CKM_RSA_PKCS; - case fortezzaKey: - case dsaKey: - return CKM_DSA; -#ifdef NSS_ENABLE_ECC - case ecKey: - return CKM_ECDSA; -#endif /* NSS_ENABLE_ECC */ - case dhKey: - default: - break; - } - return CKM_INVALID_MECHANISM; -} - -static CK_MECHANISM_TYPE -pk11_mapWrapKeyType(KeyType keyType) -{ - switch (keyType) { - case rsaKey: - return CKM_RSA_PKCS; - /* Add fortezza?? */ - default: - break; - } - return CKM_INVALID_MECHANISM; -} - -/* - * Some non-compliant PKCS #11 vendors do not give us the modulus, so actually - * set up a signature to get the signaure length. - */ -static int -pk11_backupGetSignLength(SECKEYPrivateKey *key) -{ - PK11SlotInfo *slot = key->pkcs11Slot; - CK_MECHANISM mech = {0, NULL, 0 }; - PRBool owner = PR_TRUE; - CK_SESSION_HANDLE session; - CK_ULONG len; - CK_RV crv; - unsigned char h_data[20] = { 0 }; - unsigned char buf[20]; /* obviously to small */ - CK_ULONG smallLen = sizeof(buf); - - mech.mechanism = pk11_mapSignKeyType(key->keyType); - - session = pk11_GetNewSession(slot,&owner); - if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); - if (crv != CKR_OK) { - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PORT_SetError( PK11_MapError(crv) ); - return -1; - } - len = 0; - crv = PK11_GETTAB(slot)->C_Sign(session,h_data,sizeof(h_data), - NULL, &len); - /* now call C_Sign with too small a buffer to clear the session state */ - (void) PK11_GETTAB(slot)-> - C_Sign(session,h_data,sizeof(h_data),buf,&smallLen); - - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return -1; - } - return len; -} - -/* - * get the length of a signature object based on the key - */ -int -PK11_SignatureLen(SECKEYPrivateKey *key) -{ - int val; -#ifdef NSS_ENABLE_ECC - CK_ATTRIBUTE theTemplate = { CKA_EC_PARAMS, NULL, 0 }; - SECItem params = {siBuffer, NULL, 0}; - int length; -#endif /* NSS_ENABLE_ECC */ - - switch (key->keyType) { - case rsaKey: - val = PK11_GetPrivateModulusLen(key); - if (val == -1) { - return pk11_backupGetSignLength(key); - } - return (unsigned long) val; - - case fortezzaKey: - case dsaKey: - return 40; -#ifdef NSS_ENABLE_ECC - case ecKey: - if (PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID, - &theTemplate, 1) == CKR_OK) { - if (theTemplate.pValue != NULL) { - params.len = theTemplate.ulValueLen; - params.data = (unsigned char *) theTemplate.pValue; - length = SECKEY_ECParamsToKeySize(¶ms); - PORT_Free(theTemplate.pValue); - } - length = ((length + 7)/8) * 2; - return length; - } - break; -#endif /* NSS_ENABLE_ECC */ - default: - break; - } - PORT_SetError( SEC_ERROR_INVALID_KEY ); - return 0; -} - -PK11SlotInfo * -PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key) -{ - PK11SlotInfo *slot = key->pkcs11Slot; - slot = PK11_ReferenceSlot(slot); - return slot; -} - -/* - * Get the modulus length for raw parsing - */ -int -PK11_GetPrivateModulusLen(SECKEYPrivateKey *key) -{ - CK_ATTRIBUTE theTemplate = { CKA_MODULUS, NULL, 0 }; - PK11SlotInfo *slot = key->pkcs11Slot; - CK_RV crv; - int length; - - switch (key->keyType) { - case rsaKey: - crv = PK11_GetAttributes(NULL, slot, key->pkcs11ID, &theTemplate, 1); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return -1; - } - length = theTemplate.ulValueLen; - if ( *(unsigned char *)theTemplate.pValue == 0) { - length--; - } - if (theTemplate.pValue != NULL) - PORT_Free(theTemplate.pValue); - return (int) length; - - case fortezzaKey: - case dsaKey: - case dhKey: - default: - break; - } - if (theTemplate.pValue != NULL) - PORT_Free(theTemplate.pValue); - PORT_SetError( SEC_ERROR_INVALID_KEY ); - return -1; -} - -/* - * copy a key (or any other object) on a token - */ -CK_OBJECT_HANDLE -PK11_CopyKey(PK11SlotInfo *slot, CK_OBJECT_HANDLE srcObject) -{ - CK_OBJECT_HANDLE destObject; - CK_RV crv; - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_CopyObject(slot->session,srcObject,NULL,0, - &destObject); - PK11_ExitSlotMonitor(slot); - if (crv == CKR_OK) return destObject; - PORT_SetError( PK11_MapError(crv) ); - return CK_INVALID_HANDLE; -} - - -PK11SymKey * -pk11_KeyExchange(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, - CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, - PRBool perm, PK11SymKey *symKey); - - /* * The next three utilities are to deal with the fact that a given operation * may be a multi-slot affair. This creates a new key object that is copied @@ -1416,7 +721,7 @@ pk11_CopyToSlot(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, /* * Make sure the slot we are in the correct slot for the operation */ -static PK11SymKey * +PK11SymKey * pk11_ForceSlot(PK11SymKey *symKey,CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE operation) { @@ -1583,822 +888,32 @@ PK11_GenDES3TokenKey(PK11SlotInfo *slot, SECItem *keyid, void *cx) return PK11_TokenKeyGen(slot, CKM_DES3_CBC, 0, 0, keyid, PR_TRUE, cx); } -/* - * PKCS #11 pairwise consistency check utilized to validate key pair. - */ -static SECStatus -pk11_PairwiseConsistencyCheck(SECKEYPublicKey *pubKey, - SECKEYPrivateKey *privKey, CK_MECHANISM *mech, void* wincx ) +PK11SymKey* +PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx) { - /* Variables used for Encrypt/Decrypt functions. */ - unsigned char *known_message = (unsigned char *)"Known Crypto Message"; - CK_BBOOL isEncryptable = CK_FALSE; - CK_BBOOL canSignVerify = CK_FALSE; - CK_BBOOL isDerivable = CK_FALSE; - unsigned char plaintext[PAIRWISE_MESSAGE_LENGTH]; - CK_ULONG bytes_decrypted; - PK11SlotInfo *slot; - CK_OBJECT_HANDLE id; - unsigned char *ciphertext; - unsigned char *text_compared; - CK_ULONG max_bytes_encrypted; - CK_ULONG bytes_encrypted; - CK_ULONG bytes_compared; - CK_RV crv; - - /* Variables used for Signature/Verification functions. */ - unsigned char *known_digest = (unsigned char *)"Mozilla Rules World!"; - SECItem signature; - SECItem digest; /* always uses SHA-1 digest */ - int signature_length; - SECStatus rv; - - /**************************************************/ - /* Pairwise Consistency Check of Encrypt/Decrypt. */ - /**************************************************/ - - isEncryptable = PK11_HasAttributeSet( privKey->pkcs11Slot, - privKey->pkcs11ID, CKA_DECRYPT ); - - /* If the encryption attribute is set; attempt to encrypt */ - /* with the public key and decrypt with the private key. */ - if( isEncryptable ) { - /* Find a module to encrypt against */ - slot = PK11_GetBestSlot(pk11_mapWrapKeyType(privKey->keyType),wincx); - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return SECFailure; - } - - id = PK11_ImportPublicKey(slot,pubKey,PR_FALSE); - if (id == CK_INVALID_HANDLE) { - PK11_FreeSlot(slot); - return SECFailure; - } - - /* Compute max bytes encrypted from modulus length of private key. */ - max_bytes_encrypted = PK11_GetPrivateModulusLen( privKey ); - - - /* Prepare for encryption using the public key. */ - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB( slot )->C_EncryptInit( slot->session, - mech, id ); - if( crv != CKR_OK ) { - PK11_ExitSlotMonitor(slot); - PORT_SetError( PK11_MapError( crv ) ); - PK11_FreeSlot(slot); - return SECFailure; - } - - /* Allocate space for ciphertext. */ - ciphertext = (unsigned char *) PORT_Alloc( max_bytes_encrypted ); - if( ciphertext == NULL ) { - PK11_ExitSlotMonitor(slot); - PORT_SetError( SEC_ERROR_NO_MEMORY ); - PK11_FreeSlot(slot); - return SECFailure; - } - - /* Initialize bytes encrypted to max bytes encrypted. */ - bytes_encrypted = max_bytes_encrypted; - - /* Encrypt using the public key. */ - crv = PK11_GETTAB( slot )->C_Encrypt( slot->session, - known_message, - PAIRWISE_MESSAGE_LENGTH, - ciphertext, - &bytes_encrypted ); - PK11_ExitSlotMonitor(slot); - PK11_FreeSlot(slot); - if( crv != CKR_OK ) { - PORT_SetError( PK11_MapError( crv ) ); - PORT_Free( ciphertext ); - return SECFailure; - } - - /* Always use the smaller of these two values . . . */ - bytes_compared = ( bytes_encrypted > PAIRWISE_MESSAGE_LENGTH ) - ? PAIRWISE_MESSAGE_LENGTH - : bytes_encrypted; - - /* If there was a failure, the plaintext */ - /* goes at the end, therefore . . . */ - text_compared = ( bytes_encrypted > PAIRWISE_MESSAGE_LENGTH ) - ? (ciphertext + bytes_encrypted - - PAIRWISE_MESSAGE_LENGTH ) - : ciphertext; - - /* Check to ensure that ciphertext does */ - /* NOT EQUAL known input message text */ - /* per FIPS PUB 140-1 directive. */ - if( ( bytes_encrypted != max_bytes_encrypted ) || - ( PORT_Memcmp( text_compared, known_message, - bytes_compared ) == 0 ) ) { - /* Set error to Invalid PRIVATE Key. */ - PORT_SetError( SEC_ERROR_INVALID_KEY ); - PORT_Free( ciphertext ); - return SECFailure; - } - - slot = privKey->pkcs11Slot; - /* Prepare for decryption using the private key. */ - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB( slot )->C_DecryptInit( slot->session, - mech, - privKey->pkcs11ID ); - if( crv != CKR_OK ) { - PK11_ExitSlotMonitor(slot); - PORT_SetError( PK11_MapError(crv) ); - PORT_Free( ciphertext ); - return SECFailure; - } - - /* Initialize bytes decrypted to be the */ - /* expected PAIRWISE_MESSAGE_LENGTH. */ - bytes_decrypted = PAIRWISE_MESSAGE_LENGTH; - - /* Decrypt using the private key. */ - /* NOTE: No need to reset the */ - /* value of bytes_encrypted. */ - crv = PK11_GETTAB( slot )->C_Decrypt( slot->session, - ciphertext, - bytes_encrypted, - plaintext, - &bytes_decrypted ); - PK11_ExitSlotMonitor(slot); - - /* Finished with ciphertext; free it. */ - PORT_Free( ciphertext ); - - if( crv != CKR_OK ) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - - /* Check to ensure that the output plaintext */ - /* does EQUAL known input message text. */ - if( ( bytes_decrypted != PAIRWISE_MESSAGE_LENGTH ) || - ( PORT_Memcmp( plaintext, known_message, - PAIRWISE_MESSAGE_LENGTH ) != 0 ) ) { - /* Set error to Bad PUBLIC Key. */ - PORT_SetError( SEC_ERROR_BAD_KEY ); - return SECFailure; - } - } - - /**********************************************/ - /* Pairwise Consistency Check of Sign/Verify. */ - /**********************************************/ - - canSignVerify = PK11_HasAttributeSet ( privKey->pkcs11Slot, - privKey->pkcs11ID, CKA_SIGN); - - if (canSignVerify) - { - /* Initialize signature and digest data. */ - signature.data = NULL; - digest.data = NULL; - - /* Determine length of signature. */ - signature_length = PK11_SignatureLen( privKey ); - if( signature_length == 0 ) - goto failure; - - /* Allocate space for signature data. */ - signature.data = (unsigned char *) PORT_Alloc( signature_length ); - if( signature.data == NULL ) { - PORT_SetError( SEC_ERROR_NO_MEMORY ); - goto failure; - } - - /* Allocate space for known digest data. */ - digest.data = (unsigned char *) PORT_Alloc( PAIRWISE_DIGEST_LENGTH ); - if( digest.data == NULL ) { - PORT_SetError( SEC_ERROR_NO_MEMORY ); - goto failure; - } - - /* "Fill" signature type and length. */ - signature.type = PAIRWISE_SECITEM_TYPE; - signature.len = signature_length; - - /* "Fill" digest with known SHA-1 digest parameters. */ - digest.type = PAIRWISE_SECITEM_TYPE; - PORT_Memcpy( digest.data, known_digest, PAIRWISE_DIGEST_LENGTH ); - digest.len = PAIRWISE_DIGEST_LENGTH; - - /* Sign the known hash using the private key. */ - rv = PK11_Sign( privKey, &signature, &digest ); - if( rv != SECSuccess ) - goto failure; - - /* Verify the known hash using the public key. */ - rv = PK11_Verify( pubKey, &signature, &digest, wincx ); - if( rv != SECSuccess ) - goto failure; - - /* Free signature and digest data. */ - PORT_Free( signature.data ); - PORT_Free( digest.data ); - } - - - - /**********************************************/ - /* Pairwise Consistency Check for Derivation */ - /**********************************************/ - - isDerivable = PK11_HasAttributeSet ( privKey->pkcs11Slot, - privKey->pkcs11ID, CKA_DERIVE); - - if (isDerivable) - { - /* - * We are not doing consistency check for Diffie-Hellman Key - - * otherwise it would be here - * This is also true for Elliptic Curve Diffie-Hellman keys - * NOTE: EC keys are currently subjected to pairwise - * consistency check for signing/verification. - */ - - } - - return SECSuccess; - -failure: - if( signature.data != NULL ) - PORT_Free( signature.data ); - if( digest.data != NULL ) - PORT_Free( digest.data ); - - return SECFailure; -} - - - -/* - * take a private key in one pkcs11 module and load it into another: - * NOTE: the source private key is a rare animal... it can't be sensitive. - * This is used to do a key gen using one pkcs11 module and storing the - * result into another. - */ -SECKEYPrivateKey * -pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, - SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) -{ - CK_ATTRIBUTE privTemplate[] = { - /* class must be first */ - { CKA_CLASS, NULL, 0 }, - { CKA_KEY_TYPE, NULL, 0 }, - /* these three must be next */ - { CKA_TOKEN, NULL, 0 }, - { CKA_PRIVATE, NULL, 0 }, - { CKA_SENSITIVE, NULL, 0 }, - { CKA_ID, NULL, 0 }, -#ifdef notdef - { CKA_LABEL, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 }, -#endif - /* RSA */ - { CKA_MODULUS, NULL, 0 }, - { CKA_PRIVATE_EXPONENT, NULL, 0 }, - { CKA_PUBLIC_EXPONENT, NULL, 0 }, - { CKA_PRIME_1, NULL, 0 }, - { CKA_PRIME_2, NULL, 0 }, - { CKA_EXPONENT_1, NULL, 0 }, - { CKA_EXPONENT_2, NULL, 0 }, - { CKA_COEFFICIENT, NULL, 0 }, - }; - CK_ATTRIBUTE *attrs = NULL, *ap; - int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]); - PRArenaPool *arena; - CK_OBJECT_HANDLE objectID; - int i, count = 0; - int extra_count = 0; - CK_RV crv; - SECStatus rv; - - for (i=0; i < templateSize; i++) { - if (privTemplate[i].type == CKA_MODULUS) { - attrs= &privTemplate[i]; - count = i; - break; - } - } - PORT_Assert(attrs != NULL); - if (attrs == NULL) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return NULL; - } - - ap = attrs; - - switch (privKey->keyType) { - case rsaKey: - count = templateSize; - extra_count = templateSize - (attrs - privTemplate); - break; - case dsaKey: - ap->type = CKA_PRIME; ap++; count++; extra_count++; - ap->type = CKA_SUBPRIME; ap++; count++; extra_count++; - ap->type = CKA_BASE; ap++; count++; extra_count++; - ap->type = CKA_VALUE; ap++; count++; extra_count++; - break; - case dhKey: - ap->type = CKA_PRIME; ap++; count++; extra_count++; - ap->type = CKA_BASE; ap++; count++; extra_count++; - ap->type = CKA_VALUE; ap++; count++; extra_count++; - break; -#ifdef NSS_ENABLE_ECC - case ecKey: - ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++; - ap->type = CKA_VALUE; ap++; count++; extra_count++; - break; -#endif /* NSS_ENABLE_ECC */ - default: - count = 0; - extra_count = 0; - break; - } - - if (count == 0) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return NULL; - } - - arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) return NULL; - /* - * read out the old attributes. - */ - crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, - privTemplate,count); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - PORT_FreeArena(arena, PR_TRUE); - return NULL; - } - - /* Reset sensitive, token, and private */ - *(CK_BBOOL *)(privTemplate[2].pValue) = token ? CK_TRUE : CK_FALSE; - *(CK_BBOOL *)(privTemplate[3].pValue) = token ? CK_TRUE : CK_FALSE; - *(CK_BBOOL *)(privTemplate[4].pValue) = sensitive ? CK_TRUE : CK_FALSE; - - /* Not everyone can handle zero padded key values, give - * them the raw data as unsigned */ - for (ap=attrs; extra_count; ap++, extra_count--) { - pk11_SignedToUnsigned(ap); - } - - /* now Store the puppies */ - rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate, - count, token, &objectID); - PORT_FreeArena(arena, PR_TRUE); - if (rv != SECSuccess) { - return NULL; - } - - /* try loading the public key as a token object */ - if (pubKey) { - PK11_ImportPublicKey(slot, pubKey, PR_TRUE); - if (pubKey->pkcs11Slot) { - PK11_FreeSlot(pubKey->pkcs11Slot); - pubKey->pkcs11Slot = NULL; - pubKey->pkcs11ID = CK_INVALID_HANDLE; - } - } - - /* build new key structure */ - return PK11_MakePrivKey(slot, privKey->keyType, (PRBool)!token, - objectID, privKey->wincx); -} - -/* - * export this for PSM - */ -SECKEYPrivateKey * -PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, - SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) -{ - return pk11_loadPrivKey(slot,privKey,pubKey,token,sensitive); -} - - -/* - * Use the token to Generate a key. keySize must be 'zero' for fixed key - * length algorithms. NOTE: this means we can never generate a DES2 key - * from this interface! - */ -SECKEYPrivateKey * -PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, - void *param, SECKEYPublicKey **pubKey, PRBool token, - PRBool sensitive, void *wincx) -{ - /* we have to use these native types because when we call PKCS 11 modules - * we have to make sure that we are using the correct sizes for all the - * parameters. */ - CK_BBOOL ckfalse = CK_FALSE; + PK11SlotInfo* slot = symk->slot; + CK_ATTRIBUTE template[1]; + CK_ATTRIBUTE *attrs = template; CK_BBOOL cktrue = CK_TRUE; - CK_ULONG modulusBits; - CK_BYTE publicExponent[4]; - CK_ATTRIBUTE privTemplate[] = { - { CKA_SENSITIVE, NULL, 0}, - { CKA_TOKEN, NULL, 0}, - { CKA_PRIVATE, NULL, 0}, - { CKA_DERIVE, NULL, 0}, - { CKA_UNWRAP, NULL, 0}, - { CKA_SIGN, NULL, 0}, - { CKA_DECRYPT, NULL, 0}, - }; - CK_ATTRIBUTE rsaPubTemplate[] = { - { CKA_MODULUS_BITS, NULL, 0}, - { CKA_PUBLIC_EXPONENT, NULL, 0}, - { CKA_TOKEN, NULL, 0}, - { CKA_DERIVE, NULL, 0}, - { CKA_WRAP, NULL, 0}, - { CKA_VERIFY, NULL, 0}, - { CKA_VERIFY_RECOVER, NULL, 0}, - { CKA_ENCRYPT, NULL, 0}, - }; - CK_ATTRIBUTE dsaPubTemplate[] = { - { CKA_PRIME, NULL, 0 }, - { CKA_SUBPRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - { CKA_TOKEN, NULL, 0}, - { CKA_DERIVE, NULL, 0}, - { CKA_WRAP, NULL, 0}, - { CKA_VERIFY, NULL, 0}, - { CKA_VERIFY_RECOVER, NULL, 0}, - { CKA_ENCRYPT, NULL, 0}, - }; - CK_ATTRIBUTE dhPubTemplate[] = { - { CKA_PRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - { CKA_TOKEN, NULL, 0}, - { CKA_DERIVE, NULL, 0}, - { CKA_WRAP, NULL, 0}, - { CKA_VERIFY, NULL, 0}, - { CKA_VERIFY_RECOVER, NULL, 0}, - { CKA_ENCRYPT, NULL, 0}, - }; -#ifdef NSS_ENABLE_ECC - CK_ATTRIBUTE ecPubTemplate[] = { - { CKA_EC_PARAMS, NULL, 0 }, - { CKA_TOKEN, NULL, 0}, - { CKA_DERIVE, NULL, 0}, - { CKA_WRAP, NULL, 0}, - { CKA_VERIFY, NULL, 0}, - { CKA_VERIFY_RECOVER, NULL, 0}, - { CKA_ENCRYPT, NULL, 0}, - }; - int ecPubCount = sizeof(ecPubTemplate)/sizeof(ecPubTemplate[0]); - SECKEYECParams * ecParams; -#endif /* NSS_ENABLE_ECC */ - - int dsaPubCount = sizeof(dsaPubTemplate)/sizeof(dsaPubTemplate[0]); - /*CK_ULONG key_size = 0;*/ - CK_ATTRIBUTE *pubTemplate; - int privCount = sizeof(privTemplate)/sizeof(privTemplate[0]); - int rsaPubCount = sizeof(rsaPubTemplate)/sizeof(rsaPubTemplate[0]); - int dhPubCount = sizeof(dhPubTemplate)/sizeof(dhPubTemplate[0]); - int pubCount = 0; - PK11RSAGenParams *rsaParams; - SECKEYPQGParams *dsaParams; - SECKEYDHParams * dhParams; - CK_MECHANISM mechanism; - CK_MECHANISM test_mech; - CK_SESSION_HANDLE session_handle; CK_RV crv; - CK_OBJECT_HANDLE privID,pubID; - SECKEYPrivateKey *privKey; - KeyType keyType; - PRBool restore; - int peCount,i; - CK_ATTRIBUTE *attrs; - CK_ATTRIBUTE *privattrs; - SECItem *pubKeyIndex; - CK_ATTRIBUTE setTemplate; - SECStatus rv; - CK_MECHANISM_INFO mechanism_info; - CK_OBJECT_CLASS keyClass; - SECItem *cka_id; - PRBool haslock = PR_FALSE; - PRBool pubIsToken = PR_FALSE; + CK_OBJECT_HANDLE newKeyID; + CK_SESSION_HANDLE rwsession; - PORT_Assert(slot != NULL); - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE); - return NULL; - } + PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; - /* if our slot really doesn't do this mechanism, Generate the key - * in our internal token and write it out */ - if (!PK11_DoesMechanism(slot,type)) { - PK11SlotInfo *int_slot = PK11_GetInternalSlot(); - - /* don't loop forever looking for a slot */ - if (slot == int_slot) { - PK11_FreeSlot(int_slot); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return NULL; - } - - /* if there isn't a suitable slot, then we can't do the keygen */ - if (int_slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return NULL; - } - - /* generate the temporary key to load */ - privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE, - PR_FALSE, wincx); - PK11_FreeSlot(int_slot); - - /* if successful, load the temp key into the new token */ - if (privKey != NULL) { - SECKEYPrivateKey *newPrivKey = pk11_loadPrivKey(slot,privKey, - *pubKey,token,sensitive); - SECKEY_DestroyPrivateKey(privKey); - if (newPrivKey == NULL) { - SECKEY_DestroyPublicKey(*pubKey); - *pubKey = NULL; - } - return newPrivKey; - } - return NULL; - } - - - mechanism.mechanism = type; - mechanism.pParameter = NULL; - mechanism.ulParameterLen = 0; - test_mech.pParameter = NULL; - test_mech.ulParameterLen = 0; - - /* set up the private key template */ - privattrs = privTemplate; - PK11_SETATTRS(privattrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - PK11_SETATTRS(privattrs, CKA_TOKEN, token ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - PK11_SETATTRS(privattrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - - /* set up the mechanism specific info */ - switch (type) { - case CKM_RSA_PKCS_KEY_PAIR_GEN: - rsaParams = (PK11RSAGenParams *)param; - modulusBits = rsaParams->keySizeInBits; - peCount = 0; - - /* convert pe to a PKCS #11 string */ - for (i=0; i < 4; i++) { - if (peCount || (rsaParams->pe & - ((unsigned long)0xff000000L >> (i*8)))) { - publicExponent[peCount] = - (CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff); - peCount++; - } - } - PORT_Assert(peCount != 0); - attrs = rsaPubTemplate; - PK11_SETATTRS(attrs, CKA_MODULUS_BITS, - &modulusBits, sizeof(modulusBits)); attrs++; - PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, - publicExponent, peCount);attrs++; - pubTemplate = rsaPubTemplate; - pubCount = rsaPubCount; - keyType = rsaKey; - test_mech.mechanism = CKM_RSA_PKCS; - break; - case CKM_DSA_KEY_PAIR_GEN: - dsaParams = (SECKEYPQGParams *)param; - attrs = dsaPubTemplate; - PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data, - dsaParams->prime.len); attrs++; - PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data, - dsaParams->subPrime.len); attrs++; - PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data, - dsaParams->base.len); attrs++; - pubTemplate = dsaPubTemplate; - pubCount = dsaPubCount; - keyType = dsaKey; - test_mech.mechanism = CKM_DSA; - break; - case CKM_DH_PKCS_KEY_PAIR_GEN: - dhParams = (SECKEYDHParams *)param; - attrs = dhPubTemplate; - PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data, - dhParams->prime.len); attrs++; - PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data, - dhParams->base.len); attrs++; - pubTemplate = dhPubTemplate; - pubCount = dhPubCount; - keyType = dhKey; - test_mech.mechanism = CKM_DH_PKCS_DERIVE; - break; -#ifdef NSS_ENABLE_ECC - case CKM_EC_KEY_PAIR_GEN: - ecParams = (SECKEYECParams *)param; - attrs = ecPubTemplate; - PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, - ecParams->len); attrs++; - pubTemplate = ecPubTemplate; - pubCount = ecPubCount; - keyType = ecKey; - /* XXX An EC key can be used for other mechanisms too such - * as CKM_ECDSA and CKM_ECDSA_SHA1. How can we reflect - * that in test_mech.mechanism so the CKA_SIGN, CKA_VERIFY - * attributes are set correctly? - */ - test_mech.mechanism = CKM_ECDH1_DERIVE; - break; -#endif /* NSS_ENABLE_ECC */ - default: - PORT_SetError( SEC_ERROR_BAD_KEY ); - return NULL; - } - - /* now query the slot to find out how "good" a key we can generate */ - if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, - test_mech.mechanism,&mechanism_info); - if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); - if ((crv != CKR_OK) || (mechanism_info.flags == 0)) { - /* must be old module... guess what it should be... */ - switch (test_mech.mechanism) { - case CKM_RSA_PKCS: - mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT | - CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP);; - break; - case CKM_DSA: - mechanism_info.flags = CKF_SIGN | CKF_VERIFY; - break; - case CKM_DH_PKCS_DERIVE: - mechanism_info.flags = CKF_DERIVE; - break; -#ifdef NSS_ENABLE_ECC - case CKM_ECDH1_DERIVE: - mechanism_info.flags = CKF_DERIVE; - break; - case CKM_ECDSA: - case CKM_ECDSA_SHA1: - mechanism_info.flags = CKF_SIGN | CKF_VERIFY; - break; -#endif /* NSS_ENABLE_ECC */ - default: - break; - } - } - /* set the public key objects */ - PK11_SETATTRS(attrs, CKA_TOKEN, token ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); attrs++; - PK11_SETATTRS(attrs, CKA_DERIVE, - mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); attrs++; - PK11_SETATTRS(attrs, CKA_WRAP, - mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); attrs++; - PK11_SETATTRS(attrs, CKA_VERIFY, - mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); attrs++; - PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER, - mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); attrs++; - PK11_SETATTRS(attrs, CKA_ENCRYPT, - mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); attrs++; - PK11_SETATTRS(privattrs, CKA_DERIVE, - mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - PK11_SETATTRS(privattrs, CKA_UNWRAP, - mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - PK11_SETATTRS(privattrs, CKA_SIGN, - mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - PK11_SETATTRS(privattrs, CKA_DECRYPT, - mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse, - sizeof(CK_BBOOL)); privattrs++; - - if (token) { - session_handle = PK11_GetRWSession(slot); - haslock = PK11_RWSessionHasLock(slot,session_handle); - restore = PR_TRUE; - } else { - PK11_EnterSlotMonitor(slot); /* gross!! */ - session_handle = slot->session; - restore = PR_FALSE; - haslock = PR_TRUE; - } - - crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism, - pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID); + PK11_Authenticate(slot, PR_TRUE, wincx); + rwsession = PK11_GetRWSession(slot); + crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID, + template, 1, &newKeyID); + PK11_RestoreROSession(slot, rwsession); if (crv != CKR_OK) { - if (restore) { - PK11_RestoreROSession(slot,session_handle); - } else PK11_ExitSlotMonitor(slot); - PORT_SetError( PK11_MapError(crv) ); - return NULL; - } - /* This locking code is dangerous and needs to be more thought - * out... the real problem is that we're holding the mutex open this long - */ - if (haslock) { PK11_ExitSlotMonitor(slot); } - - /* swap around the ID's for older PKCS #11 modules */ - keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS); - if (keyClass != CKO_PUBLIC_KEY) { - CK_OBJECT_HANDLE tmp = pubID; - pubID = privID; - privID = tmp; + PORT_SetError( PK11_MapError(crv) ); + return NULL; } - *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID); - if (*pubKey == NULL) { - if (restore) { - /* we may have to restore the mutex so it get's exited properly - * in RestoreROSession */ - if (haslock) PK11_EnterSlotMonitor(slot); - PK11_RestoreROSession(slot,session_handle); - } - PK11_DestroyObject(slot,pubID); - PK11_DestroyObject(slot,privID); - return NULL; - } - - /* set the ID to the public key so we can find it again */ - pubKeyIndex = NULL; - switch (type) { - case CKM_RSA_PKCS_KEY_PAIR_GEN: - pubKeyIndex = &(*pubKey)->u.rsa.modulus; - break; - case CKM_DSA_KEY_PAIR_GEN: - pubKeyIndex = &(*pubKey)->u.dsa.publicValue; - break; - case CKM_DH_PKCS_KEY_PAIR_GEN: - pubKeyIndex = &(*pubKey)->u.dh.publicValue; - break; -#ifdef NSS_ENABLE_ECC - case CKM_EC_KEY_PAIR_GEN: - pubKeyIndex = &(*pubKey)->u.ec.publicValue; - break; -#endif /* NSS_ENABLE_ECC */ - } - PORT_Assert(pubKeyIndex != NULL); - - cka_id = PK11_MakeIDFromPubKey(pubKeyIndex); - pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN); - - PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len); - - if (haslock) { PK11_EnterSlotMonitor(slot); } - crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID, - &setTemplate, 1); - - if (crv == CKR_OK && pubIsToken) { - crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID, - &setTemplate, 1); - } - - - if (restore) { - PK11_RestoreROSession(slot,session_handle); - } else { - PK11_ExitSlotMonitor(slot); - } - SECITEM_FreeItem(cka_id,PR_TRUE); - - - if (crv != CKR_OK) { - PK11_DestroyObject(slot,pubID); - PK11_DestroyObject(slot,privID); - PORT_SetError( PK11_MapError(crv) ); - *pubKey = NULL; - return NULL; - } - - privKey = PK11_MakePrivKey(slot,keyType,(PRBool)!token,privID,wincx); - if (privKey == NULL) { - SECKEY_DestroyPublicKey(*pubKey); - PK11_DestroyObject(slot,privID); - *pubKey = NULL; - return NULL; /* due to pairwise consistency check */ - } - - /* Perform PKCS #11 pairwise consistency check. */ - rv = pk11_PairwiseConsistencyCheck( *pubKey, privKey, &test_mech, wincx ); - if( rv != SECSuccess ) { - SECKEY_DestroyPublicKey( *pubKey ); - SECKEY_DestroyPrivateKey( privKey ); - *pubKey = NULL; - privKey = NULL; - return NULL; - } - - return privKey; + return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin, + symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/); } /* @@ -2666,18 +1181,6 @@ PK11_DeriveWithFlagsPerm( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, keySize, keyTemplate, templateCount, isPerm); } -static PRBool -pk11_FindAttrInTemplate(CK_ATTRIBUTE * attr, - unsigned int numAttrs, - CK_ATTRIBUTE_TYPE target) -{ - for (; numAttrs > 0; ++attr, --numAttrs) { - if (attr->type == target) - return PR_TRUE; - } - return PR_FALSE; -} - static PK11SymKey * pk11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, SECItem *param, CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, @@ -2789,41 +1292,6 @@ pk11_DeriveWithTemplate( PK11SymKey *baseKey, CK_MECHANISM_TYPE derive, return symKey; } -/* build a public KEA key from the public value */ -SECKEYPublicKey * -PK11_MakeKEAPubKey(unsigned char *keyData,int length) -{ - SECKEYPublicKey *pubk; - SECItem pkData; - SECStatus rv; - PRArenaPool *arena; - - pkData.data = keyData; - pkData.len = length; - - arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); - if (arena == NULL) - return NULL; - - pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); - if (pubk == NULL) { - PORT_FreeArena (arena, PR_FALSE); - return NULL; - } - - pubk->arena = arena; - pubk->pkcs11Slot = 0; - pubk->pkcs11ID = CK_INVALID_HANDLE; - pubk->keyType = fortezzaKey; - rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData); - if (rv != SECSuccess) { - PORT_FreeArena (arena, PR_FALSE); - return NULL; - } - return pubk; -} - - /* * This Generates a wrapping key based on a privateKey, publicKey, and two * random numbers. For Mail usage RandomB should be NULL. In the Sender's @@ -3471,1829 +1939,33 @@ PK11_PubUnwrapSymKeyWithFlagsPerm(SECKEYPrivateKey *wrappingKey, wrappingKey->wincx, keyTemplate, templateCount, isPerm); } -/* - * Recover the Signed data. We need this because our old verify can't - * figure out which hash algorithm to use until we decryptted this. - */ -SECStatus -PK11_VerifyRecover(SECKEYPublicKey *key, - SECItem *sig, SECItem *dsig, void *wincx) -{ - PK11SlotInfo *slot = key->pkcs11Slot; - CK_OBJECT_HANDLE id = key->pkcs11ID; - CK_MECHANISM mech = {0, NULL, 0 }; - PRBool owner = PR_TRUE; - CK_SESSION_HANDLE session; - CK_ULONG len; - CK_RV crv; - - mech.mechanism = pk11_mapSignKeyType(key->keyType); - - if (slot == NULL) { - slot = PK11_GetBestSlot(mech.mechanism,wincx); - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return SECFailure; - } - id = PK11_ImportPublicKey(slot,key,PR_FALSE); - } else { - PK11_ReferenceSlot(slot); - } - - session = pk11_GetNewSession(slot,&owner); - if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_VerifyRecoverInit(session,&mech,id); - if (crv != CKR_OK) { - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PORT_SetError( PK11_MapError(crv) ); - PK11_FreeSlot(slot); - return SECFailure; - } - len = dsig->len; - crv = PK11_GETTAB(slot)->C_VerifyRecover(session,sig->data, - sig->len, dsig->data, &len); - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - dsig->len = len; - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - PK11_FreeSlot(slot); - return SECFailure; - } - PK11_FreeSlot(slot); - return SECSuccess; -} - -/* - * verify a signature from its hash. - */ -SECStatus -PK11_Verify(SECKEYPublicKey *key, SECItem *sig, SECItem *hash, void *wincx) -{ - PK11SlotInfo *slot = key->pkcs11Slot; - CK_OBJECT_HANDLE id = key->pkcs11ID; - CK_MECHANISM mech = {0, NULL, 0 }; - PRBool owner = PR_TRUE; - CK_SESSION_HANDLE session; - CK_RV crv; - - mech.mechanism = pk11_mapSignKeyType(key->keyType); - - if (slot == NULL) { - slot = PK11_GetBestSlot(mech.mechanism,wincx); - - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return SECFailure; - } - id = PK11_ImportPublicKey(slot,key,PR_FALSE); - - } else { - PK11_ReferenceSlot(slot); - } - - session = pk11_GetNewSession(slot,&owner); - if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_VerifyInit(session,&mech,id); - if (crv != CKR_OK) { - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PK11_FreeSlot(slot); - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - crv = PK11_GETTAB(slot)->C_Verify(session,hash->data, - hash->len, sig->data, sig->len); - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PK11_FreeSlot(slot); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - return SECSuccess; -} - -/* - * sign a hash. The algorithm is determined by the key. - */ -SECStatus -PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash) -{ - PK11SlotInfo *slot = key->pkcs11Slot; - CK_MECHANISM mech = {0, NULL, 0 }; - PRBool owner = PR_TRUE; - CK_SESSION_HANDLE session; - CK_ULONG len; - CK_RV crv; - - mech.mechanism = pk11_mapSignKeyType(key->keyType); - - if (!PK11_HasAttributeSet(slot,key->pkcs11ID,CKA_PRIVATE)) { - PK11_HandlePasswordCheck(slot, key->wincx); - } - - session = pk11_GetNewSession(slot,&owner); - if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_SignInit(session,&mech,key->pkcs11ID); - if (crv != CKR_OK) { - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - len = sig->len; - crv = PK11_GETTAB(slot)->C_Sign(session,hash->data, - hash->len, sig->data, &len); - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - sig->len = len; - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - return SECSuccess; -} - -/* - * Now SSL 2.0 uses raw RSA stuff. These next to functions *must* use - * RSA keys, or they'll fail. We do the checks up front. If anyone comes - * up with a meaning for rawdecrypt for any other public key operation, - * then we need to move this check into some of PK11_PubDecrypt callers, - * (namely SSL 2.0). - */ -SECStatus -PK11_PubDecryptRaw(SECKEYPrivateKey *key, unsigned char *data, - unsigned *outLen, unsigned int maxLen, unsigned char *enc, - unsigned encLen) -{ - PK11SlotInfo *slot = key->pkcs11Slot; - CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; - CK_ULONG out = maxLen; - PRBool owner = PR_TRUE; - CK_SESSION_HANDLE session; - CK_RV crv; - - if (key->keyType != rsaKey) { - PORT_SetError( SEC_ERROR_INVALID_KEY ); - return SECFailure; - } - - /* Why do we do a PK11_handle check here? for simple - * decryption? .. because the user may have asked for 'ask always' - * and this is a private key operation. In practice, thought, it's mute - * since only servers wind up using this function */ - if (!PK11_HasAttributeSet(slot,key->pkcs11ID,CKA_PRIVATE)) { - PK11_HandlePasswordCheck(slot, key->wincx); - } - session = pk11_GetNewSession(slot,&owner); - if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_DecryptInit(session,&mech,key->pkcs11ID); - if (crv != CKR_OK) { - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - crv = PK11_GETTAB(slot)->C_Decrypt(session,enc, encLen, - data, &out); - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - *outLen = out; - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - return SECSuccess; -} - -/* The encrypt version of the above function */ -SECStatus -PK11_PubEncryptRaw(SECKEYPublicKey *key, unsigned char *enc, - unsigned char *data, unsigned dataLen, void *wincx) -{ - PK11SlotInfo *slot; - CK_MECHANISM mech = {CKM_RSA_X_509, NULL, 0 }; - CK_OBJECT_HANDLE id; - CK_ULONG out = dataLen; - PRBool owner = PR_TRUE; - CK_SESSION_HANDLE session; - CK_RV crv; - - if (key->keyType != rsaKey) { - PORT_SetError( SEC_ERROR_BAD_KEY ); - return SECFailure; - } - - slot = PK11_GetBestSlot(mech.mechanism, wincx); - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return SECFailure; - } - - id = PK11_ImportPublicKey(slot,key,PR_FALSE); - - session = pk11_GetNewSession(slot,&owner); - if (!owner || !(slot->isThreadSafe)) PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_EncryptInit(session,&mech,id); - if (crv != CKR_OK) { - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PK11_FreeSlot(slot); - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - crv = PK11_GETTAB(slot)->C_Encrypt(session,data,dataLen,enc,&out); - if (!owner || !(slot->isThreadSafe)) PK11_ExitSlotMonitor(slot); - pk11_CloseSession(slot,session,owner); - PK11_FreeSlot(slot); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - return SECSuccess; -} - - -/********************************************************************** - * - * Now Deal with Crypto Contexts - * - **********************************************************************/ - -/* - * the monitors... - */ -void -PK11_EnterContextMonitor(PK11Context *cx) { - /* if we own the session and our slot is ThreadSafe, only monitor - * the Context */ - if ((cx->ownSession) && (cx->slot->isThreadSafe)) { - /* Should this use monitors instead? */ - PZ_Lock(cx->sessionLock); - } else { - PK11_EnterSlotMonitor(cx->slot); - } -} - -void -PK11_ExitContextMonitor(PK11Context *cx) { - /* if we own the session and our slot is ThreadSafe, only monitor - * the Context */ - if ((cx->ownSession) && (cx->slot->isThreadSafe)) { - /* Should this use monitors instead? */ - PZ_Unlock(cx->sessionLock); - } else { - PK11_ExitSlotMonitor(cx->slot); - } -} - -/* - * Free up a Cipher Context - */ -void -PK11_DestroyContext(PK11Context *context, PRBool freeit) -{ - pk11_CloseSession(context->slot,context->session,context->ownSession); - /* initialize the critical fields of the context */ - if (context->savedData != NULL ) PORT_Free(context->savedData); - if (context->key) PK11_FreeSymKey(context->key); - if (context->param && context->param != &pk11_null_params) - SECITEM_FreeItem(context->param, PR_TRUE); - if (context->sessionLock) PZ_DestroyLock(context->sessionLock); - PK11_FreeSlot(context->slot); - if (freeit) PORT_Free(context); -} - -/* - * save the current context. Allocate Space if necessary. - */ -static unsigned char * -pk11_saveContextHelper(PK11Context *context, unsigned char *buffer, - unsigned long *savedLength) +PK11SymKey* +PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech) { CK_RV crv; + CK_ATTRIBUTE setTemplate; + CK_BBOOL ckTrue = CK_TRUE; + PK11SlotInfo *slot = originalKey->slot; - /* If buffer is NULL, this will get the length */ - crv = PK11_GETTAB(context->slot)->C_GetOperationState(context->session, - (CK_BYTE_PTR)buffer, - savedLength); - if (!buffer || (crv == CKR_BUFFER_TOO_SMALL)) { - /* the given buffer wasn't big enough (or was NULL), but we - * have the length, so try again with a new buffer and the - * correct length - */ - unsigned long bufLen = *savedLength; - buffer = PORT_Alloc(bufLen); - if (buffer == NULL) { - return (unsigned char *)NULL; - } - crv = PK11_GETTAB(context->slot)->C_GetOperationState( - context->session, - (CK_BYTE_PTR)buffer, - savedLength); - if (crv != CKR_OK) { - PORT_ZFree(buffer, bufLen); - } + /* first just try to set this key up for signing */ + PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue)); + pk11_EnterKeyMonitor(originalKey); + crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session, + originalKey->objectID, &setTemplate, 1); + pk11_ExitKeyMonitor(originalKey); + if (crv == CKR_OK) { + return PK11_ReferenceSymKey(originalKey); } - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return (unsigned char *)NULL; - } - return buffer; + + /* nope, doesn't like it, use the pk11 copy object command */ + return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey); } - -void * -pk11_saveContext(PK11Context *context, void *space, unsigned long *savedLength) -{ - return pk11_saveContextHelper(context, - (unsigned char *)space, savedLength); -} - -/* - * restore the current context - */ -SECStatus -pk11_restoreContext(PK11Context *context,void *space, unsigned long savedLength) -{ - CK_RV crv; - CK_OBJECT_HANDLE objectID = (context->key) ? context->key->objectID: - CK_INVALID_HANDLE; - - PORT_Assert(space != NULL); - if (space == NULL) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - crv = PK11_GETTAB(context->slot)->C_SetOperationState(context->session, - (CK_BYTE_PTR)space, savedLength, objectID, 0); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv)); - return SECFailure; - } - return SECSuccess; -} - -SECStatus pk11_Finalize(PK11Context *context); - -/* - * Context initialization. Used by all flavors of CreateContext - */ -static SECStatus -pk11_context_init(PK11Context *context, CK_MECHANISM *mech_info) -{ - CK_RV crv; - PK11SymKey *symKey = context->key; - SECStatus rv = SECSuccess; - - switch (context->operation) { - case CKA_ENCRYPT: - crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, - mech_info, symKey->objectID); - break; - case CKA_DECRYPT: - if (context->fortezzaHack) { - CK_ULONG count = 0;; - /* generate the IV for fortezza */ - crv=PK11_GETTAB(context->slot)->C_EncryptInit(context->session, - mech_info, symKey->objectID); - if (crv != CKR_OK) break; - PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, - NULL, &count); - } - crv=PK11_GETTAB(context->slot)->C_DecryptInit(context->session, - mech_info, symKey->objectID); - break; - case CKA_SIGN: - crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, - mech_info, symKey->objectID); - break; - case CKA_VERIFY: - crv=PK11_GETTAB(context->slot)->C_SignInit(context->session, - mech_info, symKey->objectID); - break; - case CKA_DIGEST: - crv=PK11_GETTAB(context->slot)->C_DigestInit(context->session, - mech_info); - break; - default: - crv = CKR_OPERATION_NOT_INITIALIZED; - break; - } - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - - /* - * handle session starvation case.. use our last session to multiplex - */ - if (!context->ownSession) { - context->savedData = pk11_saveContext(context,context->savedData, - &context->savedLength); - if (context->savedData == NULL) rv = SECFailure; - /* clear out out session for others to use */ - pk11_Finalize(context); - } - return rv; -} - - -/* - * Common Helper Function do come up with a new context. - */ -static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type, - PK11SlotInfo *slot, CK_ATTRIBUTE_TYPE operation, PK11SymKey *symKey, - SECItem *param) -{ - CK_MECHANISM mech_info; - PK11Context *context; - SECStatus rv; - - PORT_Assert(slot != NULL); - if (!slot) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - context = (PK11Context *) PORT_Alloc(sizeof(PK11Context)); - if (context == NULL) { - return NULL; - } - - /* now deal with the fortezza hack... the fortezza hack is an attempt - * to get around the issue of the card not allowing you to do a FORTEZZA - * LoadIV/Encrypt, which was added because such a combination could be - * use to circumvent the key escrow system. Unfortunately SSL needs to - * do this kind of operation, so in SSL we do a loadIV (to verify it), - * Then GenerateIV, and through away the first 8 bytes on either side - * of the connection.*/ - context->fortezzaHack = PR_FALSE; - if (type == CKM_SKIPJACK_CBC64) { - if (symKey->origin == PK11_OriginFortezzaHack) { - context->fortezzaHack = PR_TRUE; - } - } - - /* initialize the critical fields of the context */ - context->operation = operation; - context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL; - context->slot = PK11_ReferenceSlot(slot); - context->session = pk11_GetNewSession(slot,&context->ownSession); - context->cx = symKey ? symKey->cx : NULL; - /* get our session */ - context->savedData = NULL; - - /* save the parameters so that some digesting stuff can do multiple - * begins on a single context */ - context->type = type; - if (param) { - if (param->len > 0) { - context->param = SECITEM_DupItem(param); - } else { - context->param = (SECItem *)&pk11_null_params; - } - } else { - context->param = NULL; - } - context->init = PR_FALSE; - context->sessionLock = PZ_NewLock(nssILockPK11cxt); - if ((context->param == NULL) || (context->sessionLock == NULL)) { - PK11_DestroyContext(context,PR_TRUE); - return NULL; - } - - mech_info.mechanism = type; - mech_info.pParameter = param->data; - mech_info.ulParameterLen = param->len; - PK11_EnterContextMonitor(context); - rv = pk11_context_init(context,&mech_info); - PK11_ExitContextMonitor(context); - - if (rv != SECSuccess) { - PK11_DestroyContext(context,PR_TRUE); - return NULL; - } - context->init = PR_TRUE; - return context; -} - - -/* - * put together the various PK11_Create_Context calls used by different - * parts of libsec. - */ -PK11Context * -__PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, - PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, - SECItem *param, void *wincx) -{ - PK11SymKey *symKey; - PK11Context *context; - - /* first get a slot */ - if (slot == NULL) { - slot = PK11_GetBestSlot(type,wincx); - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return NULL; - } - } else { - PK11_ReferenceSlot(slot); - } - - /* now import the key */ - symKey = PK11_ImportSymKey(slot, type, origin, operation, key, wincx); - if (symKey == NULL) return NULL; - - context = PK11_CreateContextBySymKey(type, operation, symKey, param); - - PK11_FreeSymKey(symKey); - PK11_FreeSlot(slot); - - return context; -} - -PK11Context * -PK11_CreateContextByRawKey(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, - PK11Origin origin, CK_ATTRIBUTE_TYPE operation, SECItem *key, - SECItem *param, void *wincx) -{ - return __PK11_CreateContextByRawKey(slot, type, origin, operation, - key, param, wincx); -} - - -/* - * Create a context from a key. We really should make sure we aren't using - * the same key in multiple session! - */ -PK11Context * -PK11_CreateContextBySymKey(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE operation, - PK11SymKey *symKey, SECItem *param) -{ - PK11SymKey *newKey; - PK11Context *context; - - /* if this slot doesn't support the mechanism, go to a slot that does */ - newKey = pk11_ForceSlot(symKey,type,operation); - if (newKey == NULL) { - PK11_ReferenceSymKey(symKey); - } else { - symKey = newKey; - } - - - /* Context Adopts the symKey.... */ - context = pk11_CreateNewContextInSlot(type, symKey->slot, operation, symKey, - param); - PK11_FreeSymKey(symKey); - return context; -} - -/* - * Digest contexts don't need keys, but the do need to find a slot. - * Macing should use PK11_CreateContextBySymKey. - */ -PK11Context * -PK11_CreateDigestContext(SECOidTag hashAlg) -{ - /* digesting has to work without authentication to the slot */ - CK_MECHANISM_TYPE type; - PK11SlotInfo *slot; - PK11Context *context; - SECItem param; - - type = PK11_AlgtagToMechanism(hashAlg); - slot = PK11_GetBestSlot(type, NULL); - if (slot == NULL) { - PORT_SetError( SEC_ERROR_NO_MODULE ); - return NULL; - } - - /* maybe should really be PK11_GenerateNewParam?? */ - param.data = NULL; - param.len = 0; - param.type = 0; - - context = pk11_CreateNewContextInSlot(type, slot, CKA_DIGEST, NULL, ¶m); - PK11_FreeSlot(slot); - return context; -} - -/* - * create a new context which is the clone of the state of old context. - */ -PK11Context * PK11_CloneContext(PK11Context *old) -{ - PK11Context *newcx; - PRBool needFree = PR_FALSE; - SECStatus rv = SECSuccess; - void *data; - unsigned long len; - - newcx = pk11_CreateNewContextInSlot(old->type, old->slot, old->operation, - old->key, old->param); - if (newcx == NULL) return NULL; - - /* now clone the save state. First we need to find the save state - * of the old session. If the old context owns it's session, - * the state needs to be saved, otherwise the state is in saveData. */ - if (old->ownSession) { - PK11_EnterContextMonitor(old); - data=pk11_saveContext(old,NULL,&len); - PK11_ExitContextMonitor(old); - needFree = PR_TRUE; - } else { - data = old->savedData; - len = old->savedLength; - } - - if (data == NULL) { - PK11_DestroyContext(newcx,PR_TRUE); - return NULL; - } - - /* now copy that state into our new context. Again we have different - * work if the new context owns it's own session. If it does, we - * restore the state gathered above. If it doesn't, we copy the - * saveData pointer... */ - if (newcx->ownSession) { - PK11_EnterContextMonitor(newcx); - rv = pk11_restoreContext(newcx,data,len); - PK11_ExitContextMonitor(newcx); - } else { - PORT_Assert(newcx->savedData != NULL); - if ((newcx->savedData == NULL) || (newcx->savedLength < len)) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } else { - PORT_Memcpy(newcx->savedData,data,len); - newcx->savedLength = len; - } - } - - if (needFree) PORT_Free(data); - - if (rv != SECSuccess) { - PK11_DestroyContext(newcx,PR_TRUE); - return NULL; - } - return newcx; -} - -/* - * save the current context state into a variable. Required to make FORTEZZA - * work. - */ -SECStatus -PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength) -{ - unsigned char * data = NULL; - CK_ULONG length = saveLength; - - if (cx->ownSession) { - PK11_EnterContextMonitor(cx); - data = pk11_saveContextHelper(cx, save, &length); - PK11_ExitContextMonitor(cx); - if (data) *len = length; - } else if ((unsigned) saveLength >= cx->savedLength) { - data = (unsigned char*)cx->savedData; - if (cx->savedData) { - PORT_Memcpy(save,cx->savedData,cx->savedLength); - } - *len = cx->savedLength; - } - if (data != NULL) { - if (cx->ownSession) { - PORT_ZFree(data, length); - } - return SECSuccess; - } else { - return SECFailure; - } -} - -/* same as above, but may allocate the return buffer. */ -unsigned char * -PK11_SaveContextAlloc(PK11Context *cx, - unsigned char *preAllocBuf, unsigned int pabLen, - unsigned int *stateLen) -{ - unsigned char *stateBuf = NULL; - unsigned long length = (unsigned long)pabLen; - - if (cx->ownSession) { - PK11_EnterContextMonitor(cx); - stateBuf = pk11_saveContextHelper(cx, preAllocBuf, &length); - PK11_ExitContextMonitor(cx); - *stateLen = (stateBuf != NULL) ? length : 0; - } else { - if (pabLen < cx->savedLength) { - stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength); - if (!stateBuf) { - return (unsigned char *)NULL; - } - } else { - stateBuf = preAllocBuf; - } - if (cx->savedData) { - PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength); - } - *stateLen = cx->savedLength; - } - return stateBuf; -} - -/* - * restore the context state into a new running context. Also required for - * FORTEZZA . - */ -SECStatus -PK11_RestoreContext(PK11Context *cx,unsigned char *save,int len) -{ - SECStatus rv = SECSuccess; - if (cx->ownSession) { - PK11_EnterContextMonitor(cx); - pk11_Finalize(cx); - rv = pk11_restoreContext(cx,save,len); - PK11_ExitContextMonitor(cx); - } else { - PORT_Assert(cx->savedData != NULL); - if ((cx->savedData == NULL) || (cx->savedLength < (unsigned) len)) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - } else { - PORT_Memcpy(cx->savedData,save,len); - cx->savedLength = len; - } - } - return rv; -} - -/* - * This is to get FIPS compliance until we can convert - * libjar to use PK11_ hashing functions. It returns PR_FALSE - * if we can't get a PK11 Context. - */ -PRBool -PK11_HashOK(SECOidTag algID) { - PK11Context *cx; - - cx = PK11_CreateDigestContext(algID); - if (cx == NULL) return PR_FALSE; - PK11_DestroyContext(cx, PR_TRUE); - return PR_TRUE; -} - - - -/* - * start a new digesting or Mac'ing operation on this context - */ -SECStatus PK11_DigestBegin(PK11Context *cx) -{ - CK_MECHANISM mech_info; - SECStatus rv; - - if (cx->init == PR_TRUE) { - return SECSuccess; - } - - /* - * make sure the old context is clear first - */ - PK11_EnterContextMonitor(cx); - pk11_Finalize(cx); - - mech_info.mechanism = cx->type; - mech_info.pParameter = cx->param->data; - mech_info.ulParameterLen = cx->param->len; - rv = pk11_context_init(cx,&mech_info); - PK11_ExitContextMonitor(cx); - - if (rv != SECSuccess) { - return SECFailure; - } - cx->init = PR_TRUE; - return SECSuccess; -} - -SECStatus -PK11_HashBuf(SECOidTag hashAlg, unsigned char *out, unsigned char *in, - int32 len) { - PK11Context *context; - unsigned int max_length; - unsigned int out_length; - SECStatus rv; - - context = PK11_CreateDigestContext(hashAlg); - if (context == NULL) return SECFailure; - - rv = PK11_DigestBegin(context); - if (rv != SECSuccess) { - PK11_DestroyContext(context, PR_TRUE); - return rv; - } - - rv = PK11_DigestOp(context, in, len); - if (rv != SECSuccess) { - PK11_DestroyContext(context, PR_TRUE); - return rv; - } - - /* XXX This really should have been an argument to this function! */ - max_length = HASH_ResultLenByOidTag(hashAlg); - PORT_Assert(max_length); - if (!max_length) - max_length = HASH_LENGTH_MAX; - - rv = PK11_DigestFinal(context,out,&out_length,max_length); - PK11_DestroyContext(context, PR_TRUE); - return rv; -} - - -/* - * execute a bulk encryption operation - */ -SECStatus -PK11_CipherOp(PK11Context *context, unsigned char * out, int *outlen, - int maxout, unsigned char *in, int inlen) -{ - CK_RV crv = CKR_OK; - CK_ULONG length = maxout; - CK_ULONG offset =0; - SECStatus rv = SECSuccess; - unsigned char *saveOut = out; - unsigned char *allocOut = NULL; - - /* if we ran out of session, we need to restore our previously stored - * state. - */ - PK11_EnterContextMonitor(context); - if (!context->ownSession) { - rv = pk11_restoreContext(context,context->savedData, - context->savedLength); - if (rv != SECSuccess) { - PK11_ExitContextMonitor(context); - return rv; - } - } - - /* - * The fortezza hack is to send 8 extra bytes on the first encrypted and - * loose them on the first decrypt. - */ - if (context->fortezzaHack) { - unsigned char random[8]; - if (context->operation == CKA_ENCRYPT) { - PK11_ExitContextMonitor(context); - rv = PK11_GenerateRandom(random,sizeof(random)); - PK11_EnterContextMonitor(context); - - /* since we are offseting the output, we can't encrypt back into - * the same buffer... allocate a temporary buffer just for this - * call. */ - allocOut = out = (unsigned char*)PORT_Alloc(maxout); - if (out == NULL) { - PK11_ExitContextMonitor(context); - return SECFailure; - } - crv = PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, - random,sizeof(random),out,&length); - - out += length; - maxout -= length; - offset = length; - } else if (context->operation == CKA_DECRYPT) { - length = sizeof(random); - crv = PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, - in,sizeof(random),random,&length); - inlen -= length; - in += length; - context->fortezzaHack = PR_FALSE; - } - } - - switch (context->operation) { - case CKA_ENCRYPT: - length = maxout; - crv=PK11_GETTAB(context->slot)->C_EncryptUpdate(context->session, - in, inlen, out, &length); - length += offset; - break; - case CKA_DECRYPT: - length = maxout; - crv=PK11_GETTAB(context->slot)->C_DecryptUpdate(context->session, - in, inlen, out, &length); - break; - default: - crv = CKR_OPERATION_NOT_INITIALIZED; - break; - } - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - *outlen = 0; - rv = SECFailure; - } else { - *outlen = length; - } - - if (context->fortezzaHack) { - if (context->operation == CKA_ENCRYPT) { - PORT_Assert(allocOut); - PORT_Memcpy(saveOut, allocOut, length); - PORT_Free(allocOut); - } - context->fortezzaHack = PR_FALSE; - } - - /* - * handle session starvation case.. use our last session to multiplex - */ - if (!context->ownSession) { - context->savedData = pk11_saveContext(context,context->savedData, - &context->savedLength); - if (context->savedData == NULL) rv = SECFailure; - - /* clear out out session for others to use */ - pk11_Finalize(context); - } - PK11_ExitContextMonitor(context); - return rv; -} - -/* - * execute a digest/signature operation - */ -SECStatus -PK11_DigestOp(PK11Context *context, const unsigned char * in, unsigned inLen) -{ - CK_RV crv = CKR_OK; - SECStatus rv = SECSuccess; - - /* if we ran out of session, we need to restore our previously stored - * state. - */ - context->init = PR_FALSE; - PK11_EnterContextMonitor(context); - if (!context->ownSession) { - rv = pk11_restoreContext(context,context->savedData, - context->savedLength); - if (rv != SECSuccess) { - PK11_ExitContextMonitor(context); - return rv; - } - } - - switch (context->operation) { - /* also for MAC'ing */ - case CKA_SIGN: - crv=PK11_GETTAB(context->slot)->C_SignUpdate(context->session, - (unsigned char *)in, - inLen); - break; - case CKA_VERIFY: - crv=PK11_GETTAB(context->slot)->C_VerifyUpdate(context->session, - (unsigned char *)in, - inLen); - break; - case CKA_DIGEST: - crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, - (unsigned char *)in, - inLen); - break; - default: - crv = CKR_OPERATION_NOT_INITIALIZED; - break; - } - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - rv = SECFailure; - } - - /* - * handle session starvation case.. use our last session to multiplex - */ - if (!context->ownSession) { - context->savedData = pk11_saveContext(context,context->savedData, - &context->savedLength); - if (context->savedData == NULL) rv = SECFailure; - - /* clear out out session for others to use */ - pk11_Finalize(context); - } - PK11_ExitContextMonitor(context); - return rv; -} - -/* - * Digest a key if possible./ - */ -SECStatus -PK11_DigestKey(PK11Context *context, PK11SymKey *key) -{ - CK_RV crv = CKR_OK; - SECStatus rv = SECSuccess; - PK11SymKey *newKey = NULL; - - if (!context || !key) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - /* if we ran out of session, we need to restore our previously stored - * state. - */ - if (context->slot != key->slot) { - newKey = pk11_CopyToSlot(context->slot,CKM_SSL3_SHA1_MAC,CKA_SIGN,key); - } else { - newKey = PK11_ReferenceSymKey(key); - } - - context->init = PR_FALSE; - PK11_EnterContextMonitor(context); - if (!context->ownSession) { - rv = pk11_restoreContext(context,context->savedData, - context->savedLength); - if (rv != SECSuccess) { - PK11_ExitContextMonitor(context); - PK11_FreeSymKey(newKey); - return rv; - } - } - - - if (newKey == NULL) { - crv = CKR_KEY_TYPE_INCONSISTENT; - if (key->data.data) { - crv=PK11_GETTAB(context->slot)->C_DigestUpdate(context->session, - key->data.data,key->data.len); - } - } else { - crv=PK11_GETTAB(context->slot)->C_DigestKey(context->session, - newKey->objectID); - } - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - rv = SECFailure; - } - - /* - * handle session starvation case.. use our last session to multiplex - */ - if (!context->ownSession) { - context->savedData = pk11_saveContext(context,context->savedData, - &context->savedLength); - if (context->savedData == NULL) rv = SECFailure; - - /* clear out out session for others to use */ - pk11_Finalize(context); - } - PK11_ExitContextMonitor(context); - if (newKey) PK11_FreeSymKey(newKey); - return rv; -} - -/* - * externally callable version of the lowercase pk11_finalize(). - */ -SECStatus -PK11_Finalize(PK11Context *context) { - SECStatus rv; - - PK11_EnterContextMonitor(context); - rv = pk11_Finalize(context); - PK11_ExitContextMonitor(context); - return rv; -} - -/* - * clean up a cipher operation, so the session can be used by - * someone new. - */ -SECStatus -pk11_Finalize(PK11Context *context) -{ - CK_ULONG count = 0; - CK_RV crv; - unsigned char stackBuf[256]; - unsigned char *buffer = NULL; - - if (!context->ownSession) { - return SECSuccess; - } - -finalize: - switch (context->operation) { - case CKA_ENCRYPT: - crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, - buffer, &count); - break; - case CKA_DECRYPT: - crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, - buffer, &count); - break; - case CKA_SIGN: - crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, - buffer, &count); - break; - case CKA_VERIFY: - crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, - buffer, count); - break; - case CKA_DIGEST: - crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, - buffer, &count); - break; - default: - crv = CKR_OPERATION_NOT_INITIALIZED; - break; - } - - if (crv != CKR_OK) { - if (buffer != stackBuf) { - PORT_Free(buffer); - } - if (crv == CKR_OPERATION_NOT_INITIALIZED) { - /* if there's no operation, it is finalized */ - return SECSuccess; - } - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - - /* try to finalize the session with a buffer */ - if (buffer == NULL) { - if (count <= sizeof stackBuf) { - buffer = stackBuf; - } else { - buffer = PORT_Alloc(count); - if (buffer == NULL) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - } - goto finalize; - } - if (buffer != stackBuf) { - PORT_Free(buffer); - } - return SECSuccess; -} - -/* - * Return the final digested or signed data... - * this routine can either take pre initialized data, or allocate data - * either out of an arena or out of the standard heap. - */ -SECStatus -PK11_DigestFinal(PK11Context *context,unsigned char *data, - unsigned int *outLen, unsigned int length) -{ - CK_ULONG len; - CK_RV crv; - SECStatus rv; - - - /* if we ran out of session, we need to restore our previously stored - * state. - */ - PK11_EnterContextMonitor(context); - if (!context->ownSession) { - rv = pk11_restoreContext(context,context->savedData, - context->savedLength); - if (rv != SECSuccess) { - PK11_ExitContextMonitor(context); - return rv; - } - } - - len = length; - switch (context->operation) { - case CKA_SIGN: - crv=PK11_GETTAB(context->slot)->C_SignFinal(context->session, - data,&len); - break; - case CKA_VERIFY: - crv=PK11_GETTAB(context->slot)->C_VerifyFinal(context->session, - data,len); - break; - case CKA_DIGEST: - crv=PK11_GETTAB(context->slot)->C_DigestFinal(context->session, - data,&len); - break; - case CKA_ENCRYPT: - crv=PK11_GETTAB(context->slot)->C_EncryptFinal(context->session, - data, &len); - break; - case CKA_DECRYPT: - crv = PK11_GETTAB(context->slot)->C_DecryptFinal(context->session, - data, &len); - break; - default: - crv = CKR_OPERATION_NOT_INITIALIZED; - break; - } - PK11_ExitContextMonitor(context); - - *outLen = (unsigned int) len; - context->init = PR_FALSE; /* allow Begin to start up again */ - - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - return SECSuccess; -} - -/**************************************************************************** - * - * 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, 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) -{ - SECAlgorithmID *algid = NULL; - algid = SEC_PKCS5CreateAlgorithmID(algorithm, salt, iteration); - return algid; -} - -PK11SymKey * -PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech, - SECItem *pwitem, PRBool faulty3DES, void *wincx) -{ - /* pbe stuff */ - CK_PBE_PARAMS *pbe_params; - PK11SymKey *symKey; - - if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) { - type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC; - } - if(mech == NULL) { - return NULL; - } - - pbe_params = (CK_PBE_PARAMS *)mech->data; - pbe_params->pPassword = (CK_CHAR_PTR)PORT_ZAlloc(pwitem->len); - if(pbe_params->pPassword != NULL) { - PORT_Memcpy(pbe_params->pPassword, pwitem->data, pwitem->len); - pbe_params->ulPasswordLen = pwitem->len; - } else { - SECITEM_ZfreeItem(mech, PR_TRUE); - return NULL; - } - - symKey = PK11_KeyGen(slot, type, mech, 0, wincx); - - PORT_ZFree(pbe_params->pPassword, pwitem->len); - pbe_params->pPassword = NULL; - pbe_params->ulPasswordLen = 0; - return symKey; -} - -PK11SymKey * -PK11_PBEKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem, - PRBool faulty3DES, void *wincx) -{ - /* pbe stuff */ - CK_MECHANISM_TYPE type; - SECItem *mech; - PK11SymKey *symKey; - - mech = PK11_ParamFromAlgid(algid); - type = PK11_AlgtagToMechanism(SECOID_FindOIDTag(&algid->algorithm)); - if(faulty3DES && (type == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC)) { - type = CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC; - } - if(mech == NULL) { - return NULL; - } - symKey = PK11_RawPBEKeyGen(slot, type, mech, pwitem, faulty3DES, wincx); - - SECITEM_ZfreeItem(mech, PR_TRUE); - return symKey; -} - -SECItem * -PK11_GetPBEIV(SECAlgorithmID *algid, SECItem *pwitem) -{ - /* pbe stuff */ - CK_MECHANISM_TYPE type; - SECItem *mech; - PK11SymKey *symKey; - PK11SlotInfo *slot = PK11_GetInternalSlot(); - int iv_len = 0; - CK_PBE_PARAMS_PTR pPBEparams; - SECItem src; - SECItem *iv; - - - mech = PK11_ParamFromAlgid(algid); - type = PK11_AlgtagToMechanism(SECOID_FindOIDTag(&algid->algorithm)); - if(mech == NULL) { - return NULL; - } - symKey = PK11_RawPBEKeyGen(slot, type, mech, pwitem, PR_FALSE, NULL); - PK11_FreeSlot(slot); - if (symKey == NULL) { - SECITEM_ZfreeItem(mech, PR_TRUE); - return NULL; - } - PK11_FreeSymKey(symKey); - pPBEparams = (CK_PBE_PARAMS_PTR)mech->data; - iv_len = PK11_GetIVLength(type); - - src.data = (unsigned char *)pPBEparams->pInitVector; - src.len = iv_len; - iv = SECITEM_DupItem(&src); - - SECITEM_ZfreeItem(mech, PR_TRUE); - return iv; -} - - -SECStatus -PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, - SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, - SECItem *nickname, SECItem *publicValue, PRBool isPerm, - PRBool isPrivate, KeyType keyType, - unsigned int keyUsage, void *wincx) -{ - CK_MECHANISM_TYPE mechanism; - SECItem *pbe_param, crypto_param; - PK11SymKey *key = NULL; - SECStatus rv = SECSuccess; - CK_MECHANISM cryptoMech, pbeMech; - CK_RV crv; - SECKEYPrivateKey *privKey = NULL; - PRBool faulty3DES = PR_FALSE; - int usageCount = 0; - CK_KEY_TYPE key_type; - CK_ATTRIBUTE_TYPE *usage = NULL; - CK_ATTRIBUTE_TYPE rsaUsage[] = { - CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER }; - CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN }; - CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE }; -#ifdef NSS_ENABLE_ECC - CK_ATTRIBUTE_TYPE ecUsage[] = { CKA_SIGN, CKA_DERIVE }; -#endif /* NSS_ENABLE_ECC */ - if((epki == NULL) || (pwitem == NULL)) - return SECFailure; - - crypto_param.data = NULL; - - mechanism = PK11_AlgtagToMechanism(SECOID_FindOIDTag( - &epki->algorithm.algorithm)); - - switch (keyType) { - default: - case rsaKey: - key_type = CKK_RSA; - switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) { - case KU_KEY_ENCIPHERMENT: - usage = rsaUsage; - usageCount = 2; - break; - case KU_DIGITAL_SIGNATURE: - usage = &rsaUsage[2]; - usageCount = 2; - break; - case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE: - case 0: /* default to everything */ - usage = rsaUsage; - usageCount = 4; - break; - } - break; - case dhKey: - key_type = CKK_DH; - usage = dhUsage; - usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]); - break; - case dsaKey: - key_type = CKK_DSA; - usage = dsaUsage; - usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]); - break; -#ifdef NSS_ENABLE_ECC - case ecKey: - key_type = CKK_EC; - switch (keyUsage & (KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) { - case KU_DIGITAL_SIGNATURE: - usage = ecUsage; - usageCount = 1; - break; - case KU_KEY_AGREEMENT: - usage = &ecUsage[1]; - usageCount = 1; - break; - case KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT: - default: /* default to everything */ - usage = ecUsage; - usageCount = 2; - break; - } - break; -#endif /* NSS_ENABLE_ECC */ - } - -try_faulty_3des: - pbe_param = PK11_ParamFromAlgid(&epki->algorithm); - - key = PK11_RawPBEKeyGen(slot, mechanism, pbe_param, pwitem, - faulty3DES, wincx); - if((key == NULL) || (pbe_param == NULL)) { - rv = SECFailure; - goto done; - } - - pbeMech.mechanism = mechanism; - pbeMech.pParameter = pbe_param->data; - pbeMech.ulParameterLen = pbe_param->len; - - crv = PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, - pwitem, faulty3DES); - if(crv != CKR_OK) { - rv = SECFailure; - goto done; - } - - cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMech.mechanism); - crypto_param.data = (unsigned char*)cryptoMech.pParameter; - crypto_param.len = cryptoMech.ulParameterLen; - - PORT_Assert(usage != NULL); - PORT_Assert(usageCount != 0); - privKey = PK11_UnwrapPrivKey(slot, key, cryptoMech.mechanism, - &crypto_param, &epki->encryptedData, - nickname, publicValue, isPerm, isPrivate, - key_type, usage, usageCount, wincx); - if(privKey) { - SECKEY_DestroyPrivateKey(privKey); - privKey = NULL; - rv = SECSuccess; - goto done; - } - /* if we are unable to import the key and the mechanism is - * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that - * the encrypted blob was created with a buggy key generation method - * which is described in the PKCS 12 implementation notes. So we - * need to try importing via that method. - */ - if((mechanism == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC) && (!faulty3DES)) { - /* clean up after ourselves before redoing the key generation. */ - - PK11_FreeSymKey(key); - key = NULL; - - if(pbe_param) { - SECITEM_ZfreeItem(pbe_param, PR_TRUE); - pbe_param = NULL; - } - - if(crypto_param.data) { - SECITEM_ZfreeItem(&crypto_param, PR_FALSE); - crypto_param.data = NULL; - cryptoMech.pParameter = NULL; - crypto_param.len = cryptoMech.ulParameterLen = 0; - } - - faulty3DES = PR_TRUE; - goto try_faulty_3des; - } - - /* key import really did fail */ - rv = SECFailure; - -done: - if(pbe_param != NULL) { - SECITEM_ZfreeItem(pbe_param, PR_TRUE); - pbe_param = NULL; - } - - if(crypto_param.data != NULL) { - SECITEM_ZfreeItem(&crypto_param, PR_FALSE); - } - - if(key != NULL) { - PK11_FreeSymKey(key); - } - - return rv; -} - -SECKEYPrivateKeyInfo * -PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx) -{ - return NULL; -} - -static int -pk11_private_key_encrypt_buffer_length(SECKEYPrivateKey *key) - -{ - CK_ATTRIBUTE rsaTemplate = { CKA_MODULUS, NULL, 0 }; - CK_ATTRIBUTE dsaTemplate = { CKA_PRIME, NULL, 0 }; -#ifdef NSS_ENABLE_ECC - /* XXX We should normally choose an attribute such that - * factor times its size is enough to hold the private key. - * For EC keys, we have no choice but to use CKA_EC_PARAMS, - * CKA_VALUE is not available for token keys. But for named - * curves, the number of bytes needed to represent the params - * is quite small so we bump up factor from 10 to 15. - */ - CK_ATTRIBUTE ecTemplate = { CKA_EC_PARAMS, NULL, 0 }; -#endif /* NSS_ENABLE_ECC */ - CK_ATTRIBUTE_PTR pTemplate; - CK_RV crv; - int length; - int factor = 10; - - if(!key) { - return -1; - } - - switch (key->keyType) { - case rsaKey: - pTemplate = &rsaTemplate; - break; - case dsaKey: - case dhKey: - pTemplate = &dsaTemplate; - break; -#ifdef NSS_ENABLE_ECC - case ecKey: - pTemplate = &ecTemplate; - factor = 15; - break; -#endif /* NSS_ENABLE_ECC */ - case fortezzaKey: - default: - pTemplate = NULL; - } - - if(!pTemplate) { - return -1; - } - - crv = PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID, - pTemplate, 1); - if(crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return -1; - } - - length = pTemplate->ulValueLen; - length *= factor; - - - if(pTemplate->pValue != NULL) { - PORT_Free(pTemplate->pValue); - } - - return length; -} - -SECKEYEncryptedPrivateKeyInfo * -PK11_ExportEncryptedPrivKeyInfo( - PK11SlotInfo *slot, /* optional, encrypt key in this slot */ - SECOidTag algTag, /* encrypt key with this algorithm */ - SECItem *pwitem, /* password for PBE encryption */ - SECKEYPrivateKey *pk, /* encrypt this private key */ - int iteration, /* interations for PBE alg */ - void *wincx) /* context for password callback ? */ -{ - SECKEYEncryptedPrivateKeyInfo *epki = NULL; - PRArenaPool *arena = NULL; - SECAlgorithmID *algid; - SECItem *pbe_param = NULL; - PK11SymKey *key = NULL; - SECStatus rv = SECSuccess; - int encryptBufLen; - CK_RV crv; - CK_ULONG encBufLenPtr; - CK_MECHANISM_TYPE mechanism; - CK_MECHANISM pbeMech; - CK_MECHANISM cryptoMech; - SECItem crypto_param; - SECItem encryptedKey = {siBuffer, NULL, 0}; - - if (!pwitem || !pk) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return NULL; - } - - algid = SEC_PKCS5CreateAlgorithmID(algTag, NULL, iteration); - if (algid == NULL) { - return NULL; - } - - crypto_param.data = NULL; - - arena = PORT_NewArena(2048); - if (arena) - epki = PORT_ArenaZNew(arena, SECKEYEncryptedPrivateKeyInfo); - if(epki == NULL) { - rv = SECFailure; - goto loser; - } - epki->arena = arena; - - mechanism = PK11_AlgtagToMechanism(algTag); - pbe_param = PK11_ParamFromAlgid(algid); - if (!pbe_param || mechanism == CKM_INVALID_MECHANISM) { - rv = SECFailure; - goto loser; - } - pbeMech.mechanism = mechanism; - pbeMech.pParameter = pbe_param->data; - pbeMech.ulParameterLen = pbe_param->len; - - /* if we didn't specify a slot, use the slot the private key was in */ - if (!slot) { - slot = pk->pkcs11Slot; - } - - /* if we specified a different slot, and the private key slot can do the - * pbe key gen, generate the key in the private key slot so we don't have - * to move it later */ - if (slot != pk->pkcs11Slot) { - if (PK11_DoesMechanism(pk->pkcs11Slot,mechanism)) { - slot = pk->pkcs11Slot; - } - } - key = PK11_RawPBEKeyGen(slot, mechanism, pbe_param, pwitem, - PR_FALSE, wincx); - - if((key == NULL) || (pbe_param == NULL)) { - rv = SECFailure; - goto loser; - } - - crv = PK11_MapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, - pwitem, PR_FALSE); - if(crv != CKR_OK) { - rv = SECFailure; - goto loser; - } - cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMech.mechanism); - crypto_param.data = (unsigned char *)cryptoMech.pParameter; - crypto_param.len = cryptoMech.ulParameterLen; - - - encryptBufLen = pk11_private_key_encrypt_buffer_length(pk); - if(encryptBufLen == -1) { - rv = SECFailure; - goto loser; - } - encryptedKey.len = (unsigned int)encryptBufLen; - encBufLenPtr = (CK_ULONG) encryptBufLen; - encryptedKey.data = (unsigned char *)PORT_ZAlloc(encryptedKey.len); - if(!encryptedKey.data) { - rv = SECFailure; - goto loser; - } - - /* If the key isn't in the private key slot, move it */ - if (key->slot != pk->pkcs11Slot) { - PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot, - key->type, CKA_WRAP, key); - if (newkey == NULL) { - rv= SECFailure; - goto loser; - } - - /* free the old key and use the new key */ - PK11_FreeSymKey(key); - key = newkey; - } - - /* we are extracting an encrypted privateKey structure. - * which needs to be freed along with the buffer into which it is - * returned. eventually, we should retrieve an encrypted key using - * pkcs8/pkcs5. - */ - PK11_EnterSlotMonitor(pk->pkcs11Slot); - crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, - &cryptoMech, key->objectID, pk->pkcs11ID, encryptedKey.data, - &encBufLenPtr); - PK11_ExitSlotMonitor(pk->pkcs11Slot); - encryptedKey.len = (unsigned int) encBufLenPtr; - if(crv != CKR_OK) { - rv = SECFailure; - goto loser; - } - - if(!encryptedKey.len) { - rv = SECFailure; - goto loser; - } - rv = SECITEM_CopyItem(arena, &epki->encryptedData, &encryptedKey); - if(rv != SECSuccess) { - goto loser; - } - - rv = SECOID_CopyAlgorithmID(arena, &epki->algorithm, algid); - -loser: - if(pbe_param != NULL) { - SECITEM_ZfreeItem(pbe_param, PR_TRUE); - pbe_param = NULL; - } - - if(crypto_param.data != NULL) { - SECITEM_ZfreeItem(&crypto_param, PR_FALSE); - crypto_param.data = NULL; - } - - if(key != NULL) { - PK11_FreeSymKey(key); - } - SECOID_DestroyAlgorithmID(algid, PR_TRUE); - - if(rv == SECFailure) { - if(arena != NULL) { - PORT_FreeArena(arena, PR_TRUE); - } - epki = NULL; - } - - return epki; +void +PK11_SetFortezzaHack(PK11SymKey *symKey) { + symKey->origin = PK11_OriginFortezzaHack; } -SECKEYEncryptedPrivateKeyInfo * -PK11_ExportEncryptedPrivateKeyInfo( - PK11SlotInfo *slot, /* optional, encrypt key in this slot */ - SECOidTag algTag, /* encrypt key with this algorithm */ - SECItem *pwitem, /* password for PBE encryption */ - CERTCertificate *cert, /* wrap priv key for this user cert */ - int iteration, /* interations for PBE alg */ - void *wincx) /* context for password callback ? */ -{ - SECKEYEncryptedPrivateKeyInfo *epki = NULL; - SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx); - if (pk != NULL) { - epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk, - iteration, wincx); - SECKEY_DestroyPrivateKey(pk); - } - return epki; -} - - /* * This is required to allow FORTEZZA_NULL and FORTEZZA_RC4 * working. This function simply gets a valid IV for the keys. @@ -5322,637 +1994,3 @@ PK11_GenerateFortezzaIV(PK11SymKey *symKey,unsigned char *iv,int len) PK11_ExitSlotMonitor(symKey->slot); return rv; } - -SECKEYPrivateKey * -PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, - CK_MECHANISM_TYPE wrapType, SECItem *param, - SECItem *wrappedKey, SECItem *label, - SECItem *idValue, PRBool perm, PRBool sensitive, - CK_KEY_TYPE keyType, CK_ATTRIBUTE_TYPE *usage, int usageCount, - void *wincx) -{ - CK_BBOOL cktrue = CK_TRUE; - CK_BBOOL ckfalse = CK_FALSE; - CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; - CK_ATTRIBUTE keyTemplate[15] ; - int templateCount = 0; - CK_OBJECT_HANDLE privKeyID; - CK_MECHANISM mechanism; - CK_ATTRIBUTE *attrs = keyTemplate; - SECItem *param_free = NULL, *ck_id; - CK_RV crv; - CK_SESSION_HANDLE rwsession; - PK11SymKey *newKey = NULL; - int i; - - if(!slot || !wrappedKey || !idValue) { - /* SET AN ERROR!!! */ - return NULL; - } - - ck_id = PK11_MakeIDFromPubKey(idValue); - if(!ck_id) { - return NULL; - } - - PK11_SETATTRS(attrs, CKA_TOKEN, perm ? &cktrue : &ckfalse, - sizeof(cktrue)); attrs++; - PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); attrs++; - PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); attrs++; - PK11_SETATTRS(attrs, CKA_PRIVATE, sensitive ? &cktrue : &ckfalse, - sizeof(cktrue)); attrs++; - PK11_SETATTRS(attrs, CKA_SENSITIVE, sensitive ? &cktrue : &ckfalse, - sizeof(cktrue)); attrs++; - PK11_SETATTRS(attrs, CKA_LABEL, label->data, label->len); attrs++; - PK11_SETATTRS(attrs, CKA_ID, ck_id->data, ck_id->len); attrs++; - for (i=0; i < usageCount; i++) { - PK11_SETATTRS(attrs, usage[i], &cktrue, sizeof(cktrue)); attrs++; - } - - if (PK11_IsInternal(slot)) { - PK11_SETATTRS(attrs, CKA_NETSCAPE_DB, idValue->data, - idValue->len); attrs++; - } - - templateCount = attrs - keyTemplate; - PR_ASSERT(templateCount <= (sizeof(keyTemplate) / sizeof(CK_ATTRIBUTE)) ); - - mechanism.mechanism = wrapType; - if(!param) param = param_free= PK11_ParamFromIV(wrapType, NULL); - if(param) { - mechanism.pParameter = param->data; - mechanism.ulParameterLen = param->len; - } else { - mechanism.pParameter = NULL; - mechanism.ulParameterLen = 0; - } - - if (wrappingKey->slot != slot) { - newKey = pk11_CopyToSlot(slot,wrapType,CKA_WRAP,wrappingKey); - } else { - newKey = PK11_ReferenceSymKey(wrappingKey); - } - - if (newKey) { - if (perm) { - /* Get RW Session will either lock the monitor if necessary, - * or return a thread safe session handle. */ - rwsession = PK11_GetRWSession(slot); - } else { - rwsession = slot->session; - PK11_EnterSlotMonitor(slot); - } - crv = PK11_GETTAB(slot)->C_UnwrapKey(rwsession, &mechanism, - newKey->objectID, - wrappedKey->data, - wrappedKey->len, keyTemplate, - templateCount, &privKeyID); - - if (perm) { - PK11_RestoreROSession(slot, rwsession); - } else { - PK11_ExitSlotMonitor(slot); - } - PK11_FreeSymKey(newKey); - } else { - crv = CKR_FUNCTION_NOT_SUPPORTED; - } - - if(ck_id) { - SECITEM_FreeItem(ck_id, PR_TRUE); - ck_id = NULL; - } - - if (crv != CKR_OK) { - /* we couldn't unwrap the key, use the internal module to do the - * unwrap, then load the new key into the token */ - PK11SlotInfo *int_slot = PK11_GetInternalSlot(); - - if (int_slot && (slot != int_slot)) { - SECKEYPrivateKey *privKey = PK11_UnwrapPrivKey(int_slot, - wrappingKey, wrapType, param, wrappedKey, label, - idValue, PR_FALSE, PR_FALSE, - keyType, usage, usageCount, wincx); - if (privKey) { - SECKEYPrivateKey *newPrivKey = pk11_loadPrivKey(slot,privKey, - NULL,perm,sensitive); - SECKEY_DestroyPrivateKey(privKey); - PK11_FreeSlot(int_slot); - return newPrivKey; - } - } - if (int_slot) PK11_FreeSlot(int_slot); - PORT_SetError( PK11_MapError(crv) ); - return NULL; - } - return PK11_MakePrivKey(slot, nullKey, PR_FALSE, privKeyID, wincx); -} - -#define ALLOC_BLOCK 10 - -/* - * Now we're going to wrap a SECKEYPrivateKey with a PK11SymKey - * The strategy is to get both keys to reside in the same slot, - * one that can perform the desired crypto mechanism and then - * call C_WrapKey after all the setup has taken place. - */ -SECStatus -PK11_WrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey, - SECKEYPrivateKey *privKey, CK_MECHANISM_TYPE wrapType, - SECItem *param, SECItem *wrappedKey, void *wincx) -{ - PK11SlotInfo *privSlot = privKey->pkcs11Slot; /* The slot where - * the private key - * we are going to - * wrap lives. - */ - PK11SymKey *newSymKey = NULL; - SECKEYPrivateKey *newPrivKey = NULL; - SECItem *param_free = NULL; - CK_ULONG len = wrappedKey->len; - CK_MECHANISM mech; - CK_RV crv; - - if (!privSlot || !PK11_DoesMechanism(privSlot, wrapType)) { - /* Figure out a slot that does the mechanism and try to import - * the private key onto that slot. - */ - PK11SlotInfo *int_slot = PK11_GetInternalSlot(); - - privSlot = int_slot; /* The private key has a new home */ - newPrivKey = pk11_loadPrivKey(privSlot,privKey,NULL,PR_FALSE,PR_FALSE); - /* newPrivKey has allocated its own reference to the slot, so it's - * safe until we destroy newPrivkey. - */ - PK11_FreeSlot(int_slot); - if (newPrivKey == NULL) { - return SECFailure; - } - privKey = newPrivKey; - } - - if (privSlot != wrappingKey->slot) { - newSymKey = pk11_CopyToSlot (privSlot, wrapType, CKA_WRAP, - wrappingKey); - wrappingKey = newSymKey; - } - - if (wrappingKey == NULL) { - if (newPrivKey) { - SECKEY_DestroyPrivateKey(newPrivKey); - } - return SECFailure; - } - mech.mechanism = wrapType; - if (!param) { - param = param_free = PK11_ParamFromIV(wrapType, NULL); - } - if (param) { - mech.pParameter = param->data; - mech.ulParameterLen = param->len; - } else { - mech.pParameter = NULL; - mech.ulParameterLen = 0; - } - - PK11_EnterSlotMonitor(privSlot); - crv = PK11_GETTAB(privSlot)->C_WrapKey(privSlot->session, &mech, - wrappingKey->objectID, - privKey->pkcs11ID, - wrappedKey->data, &len); - PK11_ExitSlotMonitor(privSlot); - - if (newSymKey) { - PK11_FreeSymKey(newSymKey); - } - if (newPrivKey) { - SECKEY_DestroyPrivateKey(newPrivKey); - } - if (param_free) { - SECITEM_FreeItem(param_free,PR_TRUE); - } - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return SECFailure; - } - - wrappedKey->len = len; - return SECSuccess; -} - -void -PK11_SetFortezzaHack(PK11SymKey *symKey) { - symKey->origin = PK11_OriginFortezzaHack; -} - -SECItem* -PK11_DEREncodePublicKey(SECKEYPublicKey *pubk) -{ - CERTSubjectPublicKeyInfo *spki=NULL; - SECItem *spkiDER = NULL; - - if( pubk == NULL ) { - return NULL; - } - - /* get the subjectpublickeyinfo */ - spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); - if( spki == NULL ) { - goto finish; - } - - /* DER-encode the subjectpublickeyinfo */ - spkiDER = SEC_ASN1EncodeItem(NULL /*arena*/, NULL/*dest*/, spki, - CERT_SubjectPublicKeyInfoTemplate); - -finish: - return spkiDER; -} - -PK11SymKey* -PK11_CopySymKeyForSigning(PK11SymKey *originalKey, CK_MECHANISM_TYPE mech) -{ - CK_RV crv; - CK_ATTRIBUTE setTemplate; - CK_BBOOL ckTrue = CK_TRUE; - PK11SlotInfo *slot = originalKey->slot; - - /* first just try to set this key up for signing */ - PK11_SETATTRS(&setTemplate, CKA_SIGN, &ckTrue, sizeof(ckTrue)); - pk11_EnterKeyMonitor(originalKey); - crv = PK11_GETTAB(slot)-> C_SetAttributeValue(originalKey->session, - originalKey->objectID, &setTemplate, 1); - pk11_ExitKeyMonitor(originalKey); - if (crv == CKR_OK) { - return PK11_ReferenceSymKey(originalKey); - } - - /* nope, doesn't like it, use the pk11 copy object command */ - return pk11_CopyToSlot(slot, mech, CKA_SIGN, originalKey); -} - -char * -PK11_GetSymKeyNickname(PK11SymKey *symKey) -{ - return PK11_GetObjectNickname(symKey->slot,symKey->objectID); -} - -char * -PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey) -{ - return PK11_GetObjectNickname(privKey->pkcs11Slot,privKey->pkcs11ID); -} - -char * -PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey) -{ - return PK11_GetObjectNickname(pubKey->pkcs11Slot,pubKey->pkcs11ID); -} - -SECStatus -PK11_SetSymKeyNickname(PK11SymKey *symKey, const char *nickname) -{ - return PK11_SetObjectNickname(symKey->slot,symKey->objectID,nickname); -} - -SECStatus -PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, const char *nickname) -{ - return PK11_SetObjectNickname(privKey->pkcs11Slot, - privKey->pkcs11ID,nickname); -} - -SECStatus -PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, const char *nickname) -{ - return PK11_SetObjectNickname(pubKey->pkcs11Slot, - pubKey->pkcs11ID,nickname); -} - -SECKEYPQGParams * -PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey) -{ - CK_ATTRIBUTE pTemplate[] = { - { CKA_PRIME, NULL, 0 }, - { CKA_SUBPRIME, NULL, 0 }, - { CKA_BASE, NULL, 0 }, - }; - int pTemplateLen = sizeof(pTemplate)/sizeof(pTemplate[0]); - PRArenaPool *arena = NULL; - SECKEYPQGParams *params; - CK_RV crv; - - - arena = PORT_NewArena(2048); - if (arena == NULL) { - goto loser; - } - params=(SECKEYPQGParams *)PORT_ArenaZAlloc(arena,sizeof(SECKEYPQGParams)); - if (params == NULL) { - goto loser; - } - - crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, - pTemplate, pTemplateLen); - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - goto loser; - } - - params->arena = arena; - params->prime.data = pTemplate[0].pValue; - params->prime.len = pTemplate[0].ulValueLen; - params->subPrime.data = pTemplate[1].pValue; - params->subPrime.len = pTemplate[1].ulValueLen; - params->base.data = pTemplate[2].pValue; - params->base.len = pTemplate[2].ulValueLen; - - return params; - -loser: - if (arena != NULL) { - PORT_FreeArena(arena,PR_FALSE); - } - return NULL; -} - -PK11SymKey * -PK11_GetNextSymKey(PK11SymKey *symKey) -{ - return symKey ? symKey->next : NULL; -} - - -SECKEYPrivateKey* -PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void* wincx) -{ - PK11SlotInfo* slot = privk->pkcs11Slot; - CK_ATTRIBUTE template[1]; - CK_ATTRIBUTE *attrs = template; - CK_BBOOL cktrue = CK_TRUE; - CK_RV crv; - CK_OBJECT_HANDLE newKeyID; - CK_SESSION_HANDLE rwsession; - - PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; - - PK11_Authenticate(slot, PR_TRUE, wincx); - rwsession = PK11_GetRWSession(slot); - crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, privk->pkcs11ID, - template, 1, &newKeyID); - PK11_RestoreROSession(slot, rwsession); - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return NULL; - } - - return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/, - newKeyID, NULL /*wincx*/); -} - -PK11SymKey* -PK11_ConvertSessionSymKeyToTokenSymKey(PK11SymKey *symk, void *wincx) -{ - PK11SlotInfo* slot = symk->slot; - CK_ATTRIBUTE template[1]; - CK_ATTRIBUTE *attrs = template; - CK_BBOOL cktrue = CK_TRUE; - CK_RV crv; - CK_OBJECT_HANDLE newKeyID; - CK_SESSION_HANDLE rwsession; - - PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; - - PK11_Authenticate(slot, PR_TRUE, wincx); - rwsession = PK11_GetRWSession(slot); - crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, symk->objectID, - template, 1, &newKeyID); - PK11_RestoreROSession(slot, rwsession); - - if (crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return NULL; - } - - return PK11_SymKeyFromHandle(slot, NULL /*parent*/, symk->origin, - symk->type, newKeyID, PR_FALSE /*owner*/, NULL /*wincx*/); -} - - -/* - * return a linked, non-circular list of generic objects. - * If you are only interested - * in one object, just use the first object in the list. To find the - * rest of the list use PK11_GetNextGenericObject() to return the next object. - * - * You can walk the list with the following code: - * firstObj = PK11_FindGenericObjects(slot, objClass); - * for (thisObj=firstObj; thisObj; - * thisObj=PK11_GetNextGenericObject(thisObj)) { - * /* operate on thisObj */ -/* } - * - * If you want a particular object from the list... - * firstObj = PK11_FindGenericObjects(slot, objClass); - * for (thisObj=firstObj; thisObj; - * thisObj=PK11_GetNextGenericObject(thisObj)) { - * if (isMyObj(thisObj)) { - * if ( thisObj == firstObj) { - * /* NOTE: firstObj could be NULL at this point */ -/* firstObj = PK11_GetNextGenericObject(thsObj); - * } - * PK11_UnlinkGenericObject(thisObj); - * myObj = thisObj; - * break; - * } - * - * PK11_DestroyGenericObjects(firstObj); - * - * /* use myObj */ -/* PK11_DestroyGenericObject(myObj); - */ -PK11GenericObject * -PK11_FindGenericObjects(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass) -{ - CK_ATTRIBUTE template[1]; - CK_ATTRIBUTE *attrs = template; - CK_OBJECT_HANDLE *objectIDs = NULL; - PK11GenericObject *lastObj, *obj; - PK11GenericObject *firstObj = NULL; - int i, count = 0; - - - PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass)); attrs++; - - objectIDs = pk11_FindObjectsByTemplate(slot,template,1,&count); - if (objectIDs == NULL) { - return NULL; - } - - /* where we connect our object once we've created it.. */ - for (i=0; i < count; i++) { - obj = PORT_New(PK11GenericObject); - if ( !obj ) { - PK11_DestroyGenericObjects(firstObj); - PORT_Free(objectIDs); - return NULL; - } - /* initialize it */ - obj->slot = PK11_ReferenceSlot(slot); - obj->objectID = objectIDs[i]; - obj->next = NULL; - obj->prev = NULL; - - /* link it in */ - if (firstObj == NULL) { - firstObj = obj; - } else { - PK11_LinkGenericObject(lastObj, obj); - } - lastObj = obj; - } - PORT_Free(objectIDs); - return firstObj; -} - -/* - * get the Next Object in the list. - */ -PK11GenericObject * -PK11_GetNextGenericObject(PK11GenericObject *object) -{ - return object->next; -} - -PK11GenericObject * -PK11_GetPrevGenericObject(PK11GenericObject *object) -{ - return object->prev; -} - -/* - * Link a single object into a new list. - * if the object is already in another list, remove it first. - */ -SECStatus -PK11_LinkGenericObject(PK11GenericObject *list, PK11GenericObject *object) -{ - PK11_UnlinkGenericObject(object); - object->prev = list; - object->next = list->next; - list->next = object; - if (object->next != NULL) { - object->next->prev = object; - } - return SECSuccess; -} - -/* - * remove an object from the list. If the object isn't already in - * a list unlink becomes a noop. - */ -SECStatus -PK11_UnlinkGenericObject(PK11GenericObject *object) -{ - if (object->prev != NULL) { - object->prev->next = object->next; - } - if (object->next != NULL) { - object->next->prev = object->prev; - } - - object->next = NULL; - object->prev = NULL; - return SECSuccess; -} - -/* - * This function removes a single object from the list and destroys it. - * For an already unlinked object there is no difference between - * PK11_DestroyGenericObject and PK11_DestroyGenericObjects - */ -SECStatus -PK11_DestroyGenericObject(PK11GenericObject *object) -{ - if (object == NULL) { - return SECSuccess; - } - - PK11_UnlinkGenericObject(object); - if (object->slot) { - PK11_FreeSlot(object->slot); - } - PORT_Free(object); - return SECSuccess; -} - -/* - * walk down a link list of generic objects destroying them. - * This will destroy all objects in a list that the object is linked into. - * (the list is traversed in both directions). - */ -SECStatus -PK11_DestroyGenericObjects(PK11GenericObject *objects) -{ - PK11GenericObject *nextObject; - PK11GenericObject *prevObject = objects->prev; - - if (objects == NULL) { - return SECSuccess; - } - - nextObject = objects->next; - prevObject = objects->prev; - - /* delete all the objects after it in the list */ - for (; objects; objects = nextObject) { - nextObject = objects->next; - PK11_DestroyGenericObject(objects); - } - /* delete all the objects before it in the list */ - for (objects = prevObject; objects; objects = nextObject) { - prevObject = objects->prev; - PK11_DestroyGenericObject(objects); - } - return SECSuccess; -} - - -SECStatus -PK11_ReadRawAttribute(PK11ObjectType objType, void *objSpec, - CK_ATTRIBUTE_TYPE attrType, SECItem *item) -{ - PK11SlotInfo *slot = NULL; - CK_OBJECT_HANDLE handle; - - switch (objType) { - case PK11_TypeGeneric: - slot = ((PK11GenericObject *)objSpec)->slot; - handle = ((PK11GenericObject *)objSpec)->objectID; - break; - case PK11_TypePrivKey: - slot = ((SECKEYPrivateKey *)objSpec)->pkcs11Slot; - handle = ((SECKEYPrivateKey *)objSpec)->pkcs11ID; - break; - case PK11_TypePubKey: - slot = ((SECKEYPublicKey *)objSpec)->pkcs11Slot; - handle = ((SECKEYPublicKey *)objSpec)->pkcs11ID; - break; - case PK11_TypeSymKey: - slot = ((PK11SymKey *)objSpec)->slot; - handle = ((PK11SymKey *)objSpec)->objectID; - break; - case PK11_TypeCert: /* don't handle cert case for now */ - default: - break; - } - if (slot == NULL) { - PORT_SetError(SEC_ERROR_UNKNOWN_OBJECT_TYPE); - return SECFailure; - } - - return PK11_ReadAttribute(slot, handle, attrType, NULL, item); -} - diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c index 034c346296e..186dfa24fa7 100644 --- a/security/nss/lib/pk11wrap/pk11slot.c +++ b/security/nss/lib/pk11wrap/pk11slot.c @@ -19,7 +19,6 @@ * the Initial Developer. All Rights Reserved. * * Contributor(s): - * Dr Stephen Henson * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the terms of @@ -42,22 +41,14 @@ #include "secmod.h" #include "nssilock.h" #include "secmodi.h" +#include "secmodti.h" #include "pkcs11t.h" #include "pk11func.h" -#include "cert.h" -#include "key.h" #include "secitem.h" -#include "secder.h" -#include "secasn1.h" -#include "secoid.h" -#include "prtime.h" -#include "prlong.h" #include "secerr.h" -/*#include "secpkcs5.h" */ -#include "dev.h" -#include "dev3hack.h" -#include "pki3hack.h" +#include "dev.h" +#include "dev3hack.h" #include "pkim.h" @@ -126,64 +117,6 @@ static PK11SlotList pk11_aesSlotList, pk11_sha256SlotList, pk11_sha512SlotList; /* slots do SHA512 and SHA384 */ -/* - * Tables used for Extended mechanism mapping (currently not used) - */ -typedef struct { - CK_MECHANISM_TYPE keyGen; - CK_KEY_TYPE keyType; - CK_MECHANISM_TYPE type; - int blockSize; - int iv; -} pk11MechanismData; - -static pk11MechanismData pk11_default = - { CKM_GENERIC_SECRET_KEY_GEN, CKK_GENERIC_SECRET, CKM_FAKE_RANDOM, 8, 8 }; -static pk11MechanismData *pk11_MechanismTable = NULL; -static int pk11_MechTableSize = 0; -static int pk11_MechEntrySize = 0; - -/* - * list of mechanisms we're willing to wrap secret keys with. - * This list is ordered by preference. - */ -CK_MECHANISM_TYPE wrapMechanismList[] = { - CKM_DES3_ECB, - CKM_CAST5_ECB, - CKM_AES_ECB, - CKM_CAST5_ECB, - CKM_DES_ECB, - CKM_KEY_WRAP_LYNKS, - CKM_IDEA_ECB, - CKM_CAST3_ECB, - CKM_CAST_ECB, - CKM_RC5_ECB, - CKM_RC2_ECB, - CKM_CDMF_ECB, - CKM_SKIPJACK_WRAP, -}; - -int wrapMechanismCount = sizeof(wrapMechanismList)/sizeof(wrapMechanismList[0]); - -/* - * This structure keeps track of status that spans all the Slots. - * NOTE: This is a global data structure. It semantics expect thread crosstalk - * be very careful when you see it used. - * It's major purpose in life is to allow the user to log in one PER - * Tranaction, even if a transaction spans threads. The problem is the user - * may have to enter a password one just to be able to look at the - * personalities/certificates (s)he can use. Then if Auth every is one, they - * may have to enter the password again to use the card. See PK11_StartTransac - * and PK11_EndTransaction. - */ -static struct PK11GlobalStruct { - int transaction; - PRBool inTransaction; - char *(PR_CALLBACK *getPass)(PK11SlotInfo *,PRBool,void *); - PRBool (PR_CALLBACK *verifyPass)(PK11SlotInfo *,void *); - PRBool (PR_CALLBACK *isLoggedIn)(PK11SlotInfo *,void *); -} PK11_Global = { 1, PR_FALSE, NULL, NULL, NULL }; - /************************************************************ * Generic Slot List and Slot List element manipulations ************************************************************/ @@ -707,227 +640,6 @@ PK11_FindSlotBySerial(char *serial) return slot; } - - - -/*********************************************************** - * Password Utilities - ***********************************************************/ -/* - * Check the user's password. Log into the card if it's correct. - * succeed if the user is already logged in. - */ -SECStatus -pk11_CheckPassword(PK11SlotInfo *slot,char *pw) -{ - int len = PORT_Strlen(pw); - CK_RV crv; - SECStatus rv; - int64 currtime = PR_Now(); - - if (slot->protectedAuthPath) { - len = 0; - pw = NULL; - } - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, - (unsigned char *)pw,len); - slot->lastLoginCheck = 0; - PK11_ExitSlotMonitor(slot); - switch (crv) { - /* if we're already logged in, we're good to go */ - case CKR_OK: - slot->authTransact = PK11_Global.transaction; - case CKR_USER_ALREADY_LOGGED_IN: - slot->authTime = currtime; - rv = SECSuccess; - break; - case CKR_PIN_INCORRECT: - PORT_SetError(SEC_ERROR_BAD_PASSWORD); - rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ - break; - default: - PORT_SetError(PK11_MapError(crv)); - rv = SECFailure; /* some failure we can't fix by retrying */ - } - return rv; -} - -/* - * Check the user's password. Logout before hand to make sure that - * we are really checking the password. - */ -SECStatus -PK11_CheckUserPassword(PK11SlotInfo *slot,char *pw) -{ - int len = PORT_Strlen(pw); - CK_RV crv; - SECStatus rv; - int64 currtime = PR_Now(); - - if (slot->protectedAuthPath) { - len = 0; - pw = NULL; - } - - /* force a logout */ - PK11_EnterSlotMonitor(slot); - PK11_GETTAB(slot)->C_Logout(slot->session); - - crv = PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, - (unsigned char *)pw,len); - slot->lastLoginCheck = 0; - PK11_ExitSlotMonitor(slot); - switch (crv) { - /* if we're already logged in, we're good to go */ - case CKR_OK: - slot->authTransact = PK11_Global.transaction; - slot->authTime = currtime; - rv = SECSuccess; - break; - case CKR_PIN_INCORRECT: - PORT_SetError(SEC_ERROR_BAD_PASSWORD); - rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ - break; - default: - PORT_SetError(PK11_MapError(crv)); - rv = SECFailure; /* some failure we can't fix by retrying */ - } - return rv; -} - -SECStatus -PK11_Logout(PK11SlotInfo *slot) -{ - CK_RV crv; - - /* force a logout */ - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_Logout(slot->session); - slot->lastLoginCheck = 0; - PK11_ExitSlotMonitor(slot); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError(crv)); - return SECFailure; - } - return SECSuccess; -} - -/* - * transaction stuff is for when we test for the need to do every - * time auth to see if we already did it for this slot/transaction - */ -void PK11_StartAuthTransaction(void) -{ -PK11_Global.transaction++; -PK11_Global.inTransaction = PR_TRUE; -} - -void PK11_EndAuthTransaction(void) -{ -PK11_Global.transaction++; -PK11_Global.inTransaction = PR_FALSE; -} - -/* - * before we do a private key op, we check to see if we - * need to reauthenticate. - */ -void -PK11_HandlePasswordCheck(PK11SlotInfo *slot,void *wincx) -{ - int askpw = slot->askpw; - PRBool NeedAuth = PR_FALSE; - - if (!slot->needLogin) return; - - if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { - PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); - - if (def_slot) { - askpw = def_slot->askpw; - PK11_FreeSlot(def_slot); - } - } - - /* timeouts are handled by isLoggedIn */ - if (!PK11_IsLoggedIn(slot,wincx)) { - NeedAuth = PR_TRUE; - } else if (askpw == -1) { - if (!PK11_Global.inTransaction || - (PK11_Global.transaction != slot->authTransact)) { - PK11_EnterSlotMonitor(slot); - PK11_GETTAB(slot)->C_Logout(slot->session); - slot->lastLoginCheck = 0; - PK11_ExitSlotMonitor(slot); - NeedAuth = PR_TRUE; - } - } - if (NeedAuth) PK11_DoPassword(slot,PR_TRUE,wincx); -} - -void -PK11_SlotDBUpdate(PK11SlotInfo *slot) -{ - SECMOD_UpdateModule(slot->module); -} - -/* - * set new askpw and timeout values - */ -void -PK11_SetSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout) -{ - slot->askpw = askpw; - slot->timeout = timeout; - slot->defaultFlags |= PK11_OWN_PW_DEFAULTS; - PK11_SlotDBUpdate(slot); -} - -/* - * Get the askpw and timeout values for this slot - */ -void -PK11_GetSlotPWValues(PK11SlotInfo *slot,int *askpw, int *timeout) -{ - *askpw = slot->askpw; - *timeout = slot->timeout; - - if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { - PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); - - if (def_slot) { - *askpw = def_slot->askpw; - *timeout = def_slot->timeout; - PK11_FreeSlot(def_slot); - } - } -} - -/* - * Returns true if the token is needLogin and isn't logged in. - * This function is used to determine if authentication is needed - * before attempting a potentially privelleged operation. - */ -PRBool -pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx) -{ - return slot->needLogin && !PK11_IsLoggedIn(slot,wincx); -} - -/* - * make sure a slot is authenticated... - * This function only does the authentication if it is needed. - */ -SECStatus -PK11_Authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) { - if (pk11_LoginStillRequired(slot,wincx)) { - return PK11_DoPassword(slot,loadCerts,wincx); - } - return SECSuccess; -} - /* * notification stub. If we ever get interested in any events that * the pkcs11 functions may pass back to use, we can catch them here... @@ -939,7 +651,6 @@ CK_RV pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event, return CKR_OK; } - /* * grab a new RW session * !!! has a side effect of grabbing the Monitor if either the slot's default @@ -1002,277 +713,6 @@ PK11_RestoreROSession(PK11SlotInfo *slot,CK_SESSION_HANDLE rwsession) if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); } -/* - * NOTE: this assumes that we are logged out of the card before hand - */ -SECStatus -PK11_CheckSSOPassword(PK11SlotInfo *slot, char *ssopw) -{ - CK_SESSION_HANDLE rwsession; - CK_RV crv; - SECStatus rv = SECFailure; - int len = PORT_Strlen(ssopw); - - /* get a rwsession */ - rwsession = PK11_GetRWSession(slot); - if (rwsession == CK_INVALID_SESSION) return rv; - - if (slot->protectedAuthPath) { - len = 0; - ssopw = NULL; - } - - /* check the password */ - crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, - (unsigned char *)ssopw,len); - slot->lastLoginCheck = 0; - switch (crv) { - /* if we're already logged in, we're good to go */ - case CKR_OK: - rv = SECSuccess; - break; - case CKR_PIN_INCORRECT: - PORT_SetError(SEC_ERROR_BAD_PASSWORD); - rv = SECWouldBlock; /* everything else is ok, only the pin is bad */ - break; - default: - PORT_SetError(PK11_MapError(crv)); - rv = SECFailure; /* some failure we can't fix by retrying */ - } - PK11_GETTAB(slot)->C_Logout(rwsession); - slot->lastLoginCheck = 0; - - /* release rwsession */ - PK11_RestoreROSession(slot,rwsession); - return rv; -} - -/* - * make sure the password conforms to your token's requirements. - */ -SECStatus -PK11_VerifyPW(PK11SlotInfo *slot,char *pw) -{ - int len = PORT_Strlen(pw); - - if ((slot->minPassword > len) || (slot->maxPassword < len)) { - PORT_SetError(SEC_ERROR_BAD_DATA); - return SECFailure; - } - return SECSuccess; -} - -/* - * initialize a user PIN Value - */ -SECStatus -PK11_InitPin(PK11SlotInfo *slot,char *ssopw, char *userpw) -{ - CK_SESSION_HANDLE rwsession = CK_INVALID_SESSION; - CK_RV crv; - SECStatus rv = SECFailure; - int len; - int ssolen; - - if (userpw == NULL) userpw = ""; - if (ssopw == NULL) ssopw = ""; - - len = PORT_Strlen(userpw); - ssolen = PORT_Strlen(ssopw); - - /* get a rwsession */ - rwsession = PK11_GetRWSession(slot); - if (rwsession == CK_INVALID_SESSION) goto done; - - if (slot->protectedAuthPath) { - len = 0; - ssolen = 0; - ssopw = NULL; - userpw = NULL; - } - - /* check the password */ - crv = PK11_GETTAB(slot)->C_Login(rwsession,CKU_SO, - (unsigned char *)ssopw,ssolen); - slot->lastLoginCheck = 0; - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError(crv)); - goto done; - } - - crv = PK11_GETTAB(slot)->C_InitPIN(rwsession,(unsigned char *)userpw,len); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError(crv)); - } else { - rv = SECSuccess; - } - -done: - PK11_GETTAB(slot)->C_Logout(rwsession); - slot->lastLoginCheck = 0; - PK11_RestoreROSession(slot,rwsession); - if (rv == SECSuccess) { - /* update our view of the world */ - PK11_InitToken(slot,PR_TRUE); - PK11_EnterSlotMonitor(slot); - PK11_GETTAB(slot)->C_Login(slot->session,CKU_USER, - (unsigned char *)userpw,len); - slot->lastLoginCheck = 0; - PK11_ExitSlotMonitor(slot); - } - return rv; -} - -/* - * Change an existing user password - */ -SECStatus -PK11_ChangePW(PK11SlotInfo *slot,char *oldpw, char *newpw) -{ - CK_RV crv; - SECStatus rv = SECFailure; - int newLen; - int oldLen; - CK_SESSION_HANDLE rwsession; - - if (newpw == NULL) newpw = ""; - if (oldpw == NULL) oldpw = ""; - newLen = PORT_Strlen(newpw); - oldLen = PORT_Strlen(oldpw); - - /* get a rwsession */ - rwsession = PK11_GetRWSession(slot); - - crv = PK11_GETTAB(slot)->C_SetPIN(rwsession, - (unsigned char *)oldpw,oldLen,(unsigned char *)newpw,newLen); - if (crv == CKR_OK) { - rv = SECSuccess; - } else { - PORT_SetError(PK11_MapError(crv)); - } - - PK11_RestoreROSession(slot,rwsession); - - /* update our view of the world */ - PK11_InitToken(slot,PR_TRUE); - return rv; -} - -static char * -pk11_GetPassword(PK11SlotInfo *slot, PRBool retry, void * wincx) -{ - if (PK11_Global.getPass == NULL) return NULL; - return (*PK11_Global.getPass)(slot, retry, wincx); -} - -void -PK11_SetPasswordFunc(PK11PasswordFunc func) -{ - PK11_Global.getPass = func; -} - -void -PK11_SetVerifyPasswordFunc(PK11VerifyPasswordFunc func) -{ - PK11_Global.verifyPass = func; -} - -void -PK11_SetIsLoggedInFunc(PK11IsLoggedInFunc func) -{ - PK11_Global.isLoggedIn = func; -} - - -/* - * authenticate to a slot. This loops until we can't recover, the user - * gives up, or we succeed. If we're already logged in and this function - * is called we will still prompt for a password, but we will probably - * succeed no matter what the password was (depending on the implementation - * of the PKCS 11 module. - */ -SECStatus -PK11_DoPassword(PK11SlotInfo *slot, PRBool loadCerts, void *wincx) -{ - SECStatus rv = SECFailure; - char * password; - PRBool attempt = PR_FALSE; - - if (PK11_NeedUserInit(slot)) { - PORT_SetError(SEC_ERROR_IO); - return SECFailure; - } - - - /* - * Central server type applications which control access to multiple - * slave applications to single crypto devices need to virtuallize the - * login state. This is done by a callback out of PK11_IsLoggedIn and - * here. If we are actually logged in, then we got here because the - * higher level code told us that the particular client application may - * still need to be logged in. If that is the case, we simply tell the - * server code that it should now verify the clients password and tell us - * the results. - */ - if (PK11_IsLoggedIn(slot,NULL) && - (PK11_Global.verifyPass != NULL)) { - if (!PK11_Global.verifyPass(slot,wincx)) { - PORT_SetError(SEC_ERROR_BAD_PASSWORD); - return SECFailure; - } - return SECSuccess; - } - - /* get the password. This can drop out of the while loop - * for the following reasons: - * (1) the user refused to enter a password. - * (return error to caller) - * (2) the token user password is disabled [usually due to - * too many failed authentication attempts]. - * (return error to caller) - * (3) the password was successful. - */ - while ((password = pk11_GetPassword(slot, attempt, wincx)) != NULL) { - attempt = PR_TRUE; - rv = pk11_CheckPassword(slot,password); - PORT_Memset(password, 0, PORT_Strlen(password)); - PORT_Free(password); - if (rv != SECWouldBlock) break; - } - if (rv == SECSuccess) { - rv = pk11_CheckVerifyTest(slot); - if (!PK11_IsFriendly(slot)) { - nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain, - slot->nssToken); - } - } else if (!attempt) PORT_SetError(SEC_ERROR_BAD_PASSWORD); - return rv; -} - -void PK11_LogoutAll(void) -{ - SECMODListLock *lock = SECMOD_GetDefaultModuleListLock(); - SECMODModuleList *modList = SECMOD_GetDefaultModuleList(); - SECMODModuleList *mlp = NULL; - int i; - - SECMOD_GetReadLock(lock); - /* find the number of entries */ - for (mlp = modList; mlp != NULL; mlp = mlp->next) { - for (i=0; i < mlp->module->slotCount; i++) { - PK11_Logout(mlp->module->slots[i]); - } - } - - SECMOD_ReleaseReadLock(lock); -} - -int -PK11_GetMinimumPwdLength(PK11SlotInfo *slot) -{ - return ((int)slot->minPassword); -} - /************************************************************ * Manage the built-In Slot Lists ************************************************************/ @@ -2219,38 +1659,6 @@ PK11_GetDefaultFlags(PK11SlotInfo *slot) return slot->defaultFlags; } -/* Does this slot have a protected pin path? */ -PRBool -PK11_ProtectedAuthenticationPath(PK11SlotInfo *slot) -{ - return slot->protectedAuthPath; -} - -/* - * we can initialize the password if 1) The toke is not inited - * (need login == true and see need UserInit) or 2) the token has - * a NULL password. (slot->needLogin = false & need user Init = false). - */ -PRBool PK11_NeedPWInitForSlot(PK11SlotInfo *slot) -{ - if (slot->needLogin && PK11_NeedUserInit(slot)) { - return PR_TRUE; - } - if (!slot->needLogin && !PK11_NeedUserInit(slot)) { - return PR_TRUE; - } - return PR_FALSE; -} - -PRBool PK11_NeedPWInit() -{ - PK11SlotInfo *slot = PK11_GetInternalKeySlot(); - PRBool ret = PK11_NeedPWInitForSlot(slot); - - PK11_FreeSlot(slot); - return ret; -} - /* * The following wrapper functions allow us to export an opaque slot * function to the rest of libsec and the world... */ @@ -2442,102 +1850,6 @@ PK11_GetInternalSlot(void) return PK11_ReferenceSlot(mod->slots[0]); } -PRBool -pk11_InDelayPeriod(PRIntervalTime lastTime, PRIntervalTime delayTime, - PRIntervalTime *retTime) -{ - PRIntervalTime time; - - *retTime = time = PR_IntervalNow(); - return (PRBool) (lastTime) && ((time-lastTime) < delayTime); -} - -/* - * Determine if the token is logged in. We have to actually query the token, - * because it's state can change without intervention from us. - */ -PRBool -PK11_IsLoggedIn(PK11SlotInfo *slot,void *wincx) -{ - CK_SESSION_INFO sessionInfo; - int askpw = slot->askpw; - int timeout = slot->timeout; - CK_RV crv; - PRIntervalTime curTime; - static PRIntervalTime login_delay_time = 0; - - if (login_delay_time == 0) { - login_delay_time = PR_SecondsToInterval(1); - } - - /* If we don't have our own password default values, use the system - * ones */ - if ((slot->defaultFlags & PK11_OWN_PW_DEFAULTS) == 0) { - PK11SlotInfo *def_slot = PK11_GetInternalKeySlot(); - - if (def_slot) { - askpw = def_slot->askpw; - timeout = def_slot->timeout; - PK11_FreeSlot(def_slot); - } - } - - if ((wincx != NULL) && (PK11_Global.isLoggedIn != NULL) && - (*PK11_Global.isLoggedIn)(slot, wincx) == PR_FALSE) { return PR_FALSE; } - - - /* forget the password if we've been inactive too long */ - if (askpw == 1) { - int64 currtime = PR_Now(); - int64 result; - int64 mult; - - LL_I2L(result, timeout); - LL_I2L(mult, 60*1000*1000); - LL_MUL(result,result,mult); - LL_ADD(result, result, slot->authTime); - if (LL_CMP(result, <, currtime) ) { - PK11_EnterSlotMonitor(slot); - PK11_GETTAB(slot)->C_Logout(slot->session); - slot->lastLoginCheck = 0; - PK11_ExitSlotMonitor(slot); - } else { - slot->authTime = currtime; - } - } - - PK11_EnterSlotMonitor(slot); - if (pk11_InDelayPeriod(slot->lastLoginCheck,login_delay_time, &curTime)) { - sessionInfo.state = slot->lastState; - crv = CKR_OK; - } else { - crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session,&sessionInfo); - if (crv == CKR_OK) { - slot->lastState = sessionInfo.state; - slot->lastLoginCheck = curTime; - } - } - PK11_ExitSlotMonitor(slot); - /* if we can't get session info, something is really wrong */ - if (crv != CKR_OK) { - slot->session = CK_INVALID_SESSION; - return PR_FALSE; - } - - switch (sessionInfo.state) { - case CKS_RW_PUBLIC_SESSION: - case CKS_RO_PUBLIC_SESSION: - default: - break; /* fail */ - case CKS_RW_USER_FUNCTIONS: - case CKS_RW_SO_FUNCTIONS: - case CKS_RO_USER_FUNCTIONS: - return PR_TRUE; - } - return PR_FALSE; -} - - /* * check if a given slot supports the requested mechanism */ @@ -2789,21 +2101,6 @@ PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx) return PK11_GetBestSlotMultiple(&type, 1, wincx); } -/* - * find the best key wrap mechanism for this slot. - */ -CK_MECHANISM_TYPE -PK11_GetBestWrapMechanism(PK11SlotInfo *slot) -{ - int i; - for (i=0; i < wrapMechanismCount; i++) { - if (PK11_DoesMechanism(slot,wrapMechanismList[i])) { - return wrapMechanismList[i]; - } - } - return CKM_INVALID_MECHANISM; -} - int PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism) { @@ -2821,1162 +2118,6 @@ PK11_GetBestKeyLength(PK11SlotInfo *slot,CK_MECHANISM_TYPE mechanism) return mechanism_info.ulMaxKeySize; } - -/********************************************************************* - * Mechanism Mapping functions - *********************************************************************/ - -/* - * lookup an entry in the mechanism table. If none found, return the - * default structure. - */ -static pk11MechanismData * -pk11_lookup(CK_MECHANISM_TYPE type) -{ - int i; - for (i=0; i < pk11_MechEntrySize; i++) { - if (pk11_MechanismTable[i].type == type) { - return (&pk11_MechanismTable[i]); - } - } - return &pk11_default; -} - -/* - * NOTE: This is not thread safe. Called at init time, and when loading - * a new Entry. It is reasonably safe as long as it is not re-entered - * (readers will always see a consistant table) - * - * This routine is called to add entries to the mechanism table, once there, - * they can not be removed. - */ -void -PK11_AddMechanismEntry(CK_MECHANISM_TYPE type, CK_KEY_TYPE key, - CK_MECHANISM_TYPE keyGen, int ivLen, int blockSize) -{ - int tableSize = pk11_MechTableSize; - int size = pk11_MechEntrySize; - int entry = size++; - pk11MechanismData *old = pk11_MechanismTable; - pk11MechanismData *newt = pk11_MechanismTable; - - - if (size > tableSize) { - int oldTableSize = tableSize; - tableSize += 10; - newt = PORT_NewArray(pk11MechanismData, tableSize); - if (newt == NULL) return; - - if (old) PORT_Memcpy(newt, old, oldTableSize*sizeof(*newt)); - } else old = NULL; - - newt[entry].type = type; - newt[entry].keyType = key; - newt[entry].keyGen = keyGen; - newt[entry].iv = ivLen; - newt[entry].blockSize = blockSize; - - pk11_MechanismTable = newt; - pk11_MechTableSize = tableSize; - pk11_MechEntrySize = size; - if (old) PORT_Free(old); -} - -/* - * Get the key type needed for the given mechanism - */ -CK_MECHANISM_TYPE -PK11_GetKeyMechanism(CK_KEY_TYPE type) -{ - switch (type) { - case CKK_AES: - return CKM_AES_CBC; - case CKK_DES: - return CKM_DES_CBC; - case CKK_DES3: - return CKM_DES3_KEY_GEN; - case CKK_DES2: - return CKM_DES2_KEY_GEN; - case CKK_CDMF: - return CKM_CDMF_CBC; - case CKK_RC2: - return CKM_RC2_CBC; - case CKK_RC4: - return CKM_RC4; - case CKK_RC5: - return CKM_RC5_CBC; - case CKK_SKIPJACK: - return CKM_SKIPJACK_CBC64; - case CKK_BATON: - return CKM_BATON_CBC128; - case CKK_JUNIPER: - return CKM_JUNIPER_CBC128; - case CKK_IDEA: - return CKM_IDEA_CBC; - case CKK_CAST: - return CKM_CAST_CBC; - case CKK_CAST3: - return CKM_CAST3_CBC; - case CKK_CAST5: - return CKM_CAST5_CBC; - case CKK_RSA: - return CKM_RSA_PKCS; - case CKK_DSA: - return CKM_DSA; - case CKK_DH: - return CKM_DH_PKCS_DERIVE; - case CKK_KEA: - return CKM_KEA_KEY_DERIVE; - case CKK_EC: /* CKK_ECDSA is deprecated */ - return CKM_ECDSA; - case CKK_GENERIC_SECRET: - default: - return CKM_SHA_1_HMAC; - } -} -/* - * Get the key type needed for the given mechanism - */ -CK_MECHANISM_TYPE -PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len) -{ - switch (type) { - case CKM_AES_ECB: - case CKM_AES_CBC: - case CKM_AES_MAC: - case CKM_AES_MAC_GENERAL: - case CKM_AES_CBC_PAD: - case CKM_AES_KEY_GEN: - case CKM_NETSCAPE_AES_KEY_WRAP: - case CKM_NETSCAPE_AES_KEY_WRAP_PAD: - return CKK_AES; - case CKM_DES_ECB: - case CKM_DES_CBC: - case CKM_DES_MAC: - case CKM_DES_MAC_GENERAL: - case CKM_DES_CBC_PAD: - case CKM_DES_KEY_GEN: - case CKM_KEY_WRAP_LYNKS: - case CKM_PBE_MD2_DES_CBC: - case CKM_PBE_MD5_DES_CBC: - return CKK_DES; - case CKM_DES3_ECB: - case CKM_DES3_CBC: - case CKM_DES3_MAC: - case CKM_DES3_MAC_GENERAL: - case CKM_DES3_CBC_PAD: - return (len == 16) ? CKK_DES2 : CKK_DES3; - case CKM_DES2_KEY_GEN: - case CKM_PBE_SHA1_DES2_EDE_CBC: - return CKK_DES2; - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_DES3_KEY_GEN: - return CKK_DES3; - case CKM_CDMF_ECB: - case CKM_CDMF_CBC: - case CKM_CDMF_MAC: - case CKM_CDMF_MAC_GENERAL: - case CKM_CDMF_CBC_PAD: - case CKM_CDMF_KEY_GEN: - return CKK_CDMF; - case CKM_RC2_ECB: - case CKM_RC2_CBC: - case CKM_RC2_MAC: - case CKM_RC2_MAC_GENERAL: - case CKM_RC2_CBC_PAD: - case CKM_RC2_KEY_GEN: - case CKM_PBE_SHA1_RC2_128_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - return CKK_RC2; - case CKM_RC4: - case CKM_RC4_KEY_GEN: - return CKK_RC4; - case CKM_RC5_ECB: - case CKM_RC5_CBC: - case CKM_RC5_MAC: - case CKM_RC5_MAC_GENERAL: - case CKM_RC5_CBC_PAD: - case CKM_RC5_KEY_GEN: - return CKK_RC5; - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_SKIPJACK_KEY_GEN: - case CKM_SKIPJACK_WRAP: - case CKM_SKIPJACK_PRIVATE_WRAP: - return CKK_SKIPJACK; - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_BATON_WRAP: - case CKM_BATON_KEY_GEN: - return CKK_BATON; - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - case CKM_JUNIPER_WRAP: - case CKM_JUNIPER_KEY_GEN: - return CKK_JUNIPER; - case CKM_IDEA_CBC: - case CKM_IDEA_ECB: - case CKM_IDEA_MAC: - case CKM_IDEA_MAC_GENERAL: - case CKM_IDEA_CBC_PAD: - case CKM_IDEA_KEY_GEN: - return CKK_IDEA; - case CKM_CAST_ECB: - case CKM_CAST_CBC: - case CKM_CAST_MAC: - case CKM_CAST_MAC_GENERAL: - case CKM_CAST_CBC_PAD: - case CKM_CAST_KEY_GEN: - case CKM_PBE_MD5_CAST_CBC: - return CKK_CAST; - case CKM_CAST3_ECB: - case CKM_CAST3_CBC: - case CKM_CAST3_MAC: - case CKM_CAST3_MAC_GENERAL: - case CKM_CAST3_CBC_PAD: - case CKM_CAST3_KEY_GEN: - case CKM_PBE_MD5_CAST3_CBC: - return CKK_CAST3; - case CKM_CAST5_ECB: - case CKM_CAST5_CBC: - case CKM_CAST5_MAC: - case CKM_CAST5_MAC_GENERAL: - case CKM_CAST5_CBC_PAD: - case CKM_CAST5_KEY_GEN: - case CKM_PBE_MD5_CAST5_CBC: - return CKK_CAST5; - case CKM_RSA_PKCS: - case CKM_RSA_9796: - case CKM_RSA_X_509: - case CKM_MD2_RSA_PKCS: - case CKM_MD5_RSA_PKCS: - case CKM_SHA1_RSA_PKCS: - case CKM_SHA256_RSA_PKCS: - case CKM_SHA384_RSA_PKCS: - case CKM_SHA512_RSA_PKCS: - case CKM_KEY_WRAP_SET_OAEP: - case CKM_RSA_PKCS_KEY_PAIR_GEN: - return CKK_RSA; - case CKM_DSA: - case CKM_DSA_SHA1: - case CKM_DSA_KEY_PAIR_GEN: - return CKK_DSA; - case CKM_DH_PKCS_DERIVE: - case CKM_DH_PKCS_KEY_PAIR_GEN: - return CKK_DH; - case CKM_KEA_KEY_DERIVE: - case CKM_KEA_KEY_PAIR_GEN: - return CKK_KEA; - case CKM_ECDSA: - case CKM_ECDSA_SHA1: - case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ - case CKM_ECDH1_DERIVE: - return CKK_EC; /* CKK_ECDSA is deprecated */ - 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_TLS_MASTER_KEY_DERIVE_DH: - case CKM_TLS_KEY_AND_MAC_DERIVE: - case CKM_SHA_1_HMAC: - case CKM_SHA_1_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: - return CKK_GENERIC_SECRET; - default: - return pk11_lookup(type)->keyType; - } -} - -/* - * Get the Key Gen Mechanism needed for the given - * crypto mechanism - */ -CK_MECHANISM_TYPE -PK11_GetKeyGen(CK_MECHANISM_TYPE type) -{ - return PK11_GetKeyGenWithSize(type, 0); -} - -CK_MECHANISM_TYPE -PK11_GetKeyGenWithSize(CK_MECHANISM_TYPE type, int size) -{ - switch (type) { - case CKM_AES_ECB: - case CKM_AES_CBC: - case CKM_AES_MAC: - case CKM_AES_MAC_GENERAL: - case CKM_AES_CBC_PAD: - case CKM_AES_KEY_GEN: - return CKM_AES_KEY_GEN; - case CKM_DES_ECB: - case CKM_DES_CBC: - case CKM_DES_MAC: - case CKM_DES_MAC_GENERAL: - case CKM_KEY_WRAP_LYNKS: - case CKM_DES_CBC_PAD: - case CKM_DES_KEY_GEN: - return CKM_DES_KEY_GEN; - case CKM_DES3_ECB: - case CKM_DES3_CBC: - case CKM_DES3_MAC: - case CKM_DES3_MAC_GENERAL: - case CKM_DES3_CBC_PAD: - return (size == 16) ? CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN; - case CKM_DES3_KEY_GEN: - return CKM_DES3_KEY_GEN; - case CKM_DES2_KEY_GEN: - return CKM_DES2_KEY_GEN; - case CKM_CDMF_ECB: - case CKM_CDMF_CBC: - case CKM_CDMF_MAC: - case CKM_CDMF_MAC_GENERAL: - case CKM_CDMF_CBC_PAD: - case CKM_CDMF_KEY_GEN: - return CKM_CDMF_KEY_GEN; - case CKM_RC2_ECB: - case CKM_RC2_CBC: - case CKM_RC2_MAC: - case CKM_RC2_MAC_GENERAL: - case CKM_RC2_CBC_PAD: - case CKM_RC2_KEY_GEN: - return CKM_RC2_KEY_GEN; - case CKM_RC4: - case CKM_RC4_KEY_GEN: - return CKM_RC4_KEY_GEN; - case CKM_RC5_ECB: - case CKM_RC5_CBC: - case CKM_RC5_MAC: - case CKM_RC5_MAC_GENERAL: - case CKM_RC5_CBC_PAD: - case CKM_RC5_KEY_GEN: - return CKM_RC5_KEY_GEN; - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_SKIPJACK_WRAP: - case CKM_SKIPJACK_KEY_GEN: - return CKM_SKIPJACK_KEY_GEN; - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_BATON_WRAP: - case CKM_BATON_KEY_GEN: - return CKM_BATON_KEY_GEN; - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - case CKM_JUNIPER_WRAP: - case CKM_JUNIPER_KEY_GEN: - return CKM_JUNIPER_KEY_GEN; - case CKM_IDEA_CBC: - case CKM_IDEA_ECB: - case CKM_IDEA_MAC: - case CKM_IDEA_MAC_GENERAL: - case CKM_IDEA_CBC_PAD: - case CKM_IDEA_KEY_GEN: - return CKM_IDEA_KEY_GEN; - case CKM_CAST_ECB: - case CKM_CAST_CBC: - case CKM_CAST_MAC: - case CKM_CAST_MAC_GENERAL: - case CKM_CAST_CBC_PAD: - case CKM_CAST_KEY_GEN: - return CKM_CAST_KEY_GEN; - case CKM_CAST3_ECB: - case CKM_CAST3_CBC: - case CKM_CAST3_MAC: - case CKM_CAST3_MAC_GENERAL: - case CKM_CAST3_CBC_PAD: - case CKM_CAST3_KEY_GEN: - return CKM_CAST3_KEY_GEN; - case CKM_CAST5_ECB: - case CKM_CAST5_CBC: - case CKM_CAST5_MAC: - case CKM_CAST5_MAC_GENERAL: - case CKM_CAST5_CBC_PAD: - case CKM_CAST5_KEY_GEN: - return CKM_CAST5_KEY_GEN; - case CKM_RSA_PKCS: - case CKM_RSA_9796: - case CKM_RSA_X_509: - case CKM_MD2_RSA_PKCS: - case CKM_MD5_RSA_PKCS: - case CKM_SHA1_RSA_PKCS: - case CKM_SHA256_RSA_PKCS: - case CKM_SHA384_RSA_PKCS: - case CKM_SHA512_RSA_PKCS: - case CKM_KEY_WRAP_SET_OAEP: - case CKM_RSA_PKCS_KEY_PAIR_GEN: - return CKM_RSA_PKCS_KEY_PAIR_GEN; - case CKM_DSA: - case CKM_DSA_SHA1: - case CKM_DSA_KEY_PAIR_GEN: - return CKM_DSA_KEY_PAIR_GEN; - case CKM_DH_PKCS_DERIVE: - case CKM_DH_PKCS_KEY_PAIR_GEN: - return CKM_DH_PKCS_KEY_PAIR_GEN; - case CKM_KEA_KEY_DERIVE: - case CKM_KEA_KEY_PAIR_GEN: - return CKM_KEA_KEY_PAIR_GEN; - case CKM_ECDSA: - case CKM_ECDSA_SHA1: - case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ - case CKM_ECDH1_DERIVE: - 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: - return CKM_SSL3_PRE_MASTER_KEY_GEN; - case CKM_SHA_1_HMAC: - case CKM_SHA_1_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_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: - 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: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - case CKM_PBE_SHA1_RC2_128_CBC: - case CKM_PBE_SHA1_RC4_40: - case CKM_PBE_SHA1_RC4_128: - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_PBE_SHA1_DES2_EDE_CBC: - return type; - default: - return pk11_lookup(type)->keyGen; - } -} - -/* - * get the mechanism block size - */ -int -PK11_GetBlockSize(CK_MECHANISM_TYPE type,SECItem *params) -{ - CK_RC5_PARAMS *rc5_params; - CK_RC5_CBC_PARAMS *rc5_cbc_params; - switch (type) { - case CKM_RC5_ECB: - if ((params) && (params->data)) { - rc5_params = (CK_RC5_PARAMS *) params->data; - return (rc5_params->ulWordsize)*2; - } - return 8; - case CKM_RC5_CBC: - case CKM_RC5_CBC_PAD: - if ((params) && (params->data)) { - rc5_cbc_params = (CK_RC5_CBC_PARAMS *) params->data; - return (rc5_cbc_params->ulWordsize)*2; - } - return 8; - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_RC2_ECB: - case CKM_IDEA_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - case CKM_RC2_CBC: - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_RC2_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - case CKM_PBE_MD2_DES_CBC: - case CKM_PBE_MD5_DES_CBC: - 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: - case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - case CKM_PBE_SHA1_RC2_128_CBC: - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_PBE_SHA1_DES2_EDE_CBC: - return 8; - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - return 4; - case CKM_AES_ECB: - case CKM_AES_CBC: - case CKM_AES_CBC_PAD: - case CKM_BATON_ECB128: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - return 16; - case CKM_BATON_ECB96: - return 12; - case CKM_RC4: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: - case CKM_PBE_SHA1_RC4_40: - case CKM_PBE_SHA1_RC4_128: - return 0; - case CKM_RSA_PKCS: - case CKM_RSA_9796: - case CKM_RSA_X_509: - /*actually it's the modulus length of the key!*/ - return -1; /* failure */ - default: - return pk11_lookup(type)->blockSize; - } -} - -/* - * get the iv length - */ -int -PK11_GetIVLength(CK_MECHANISM_TYPE type) -{ - switch (type) { - case CKM_AES_ECB: - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_RC2_ECB: - case CKM_IDEA_ECB: - case CKM_SKIPJACK_WRAP: - case CKM_BATON_WRAP: - case CKM_RC5_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - return 0; - case CKM_RC2_CBC: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_PBE_MD2_DES_CBC: - case CKM_PBE_MD5_DES_CBC: - 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: - case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - case CKM_PBE_SHA1_RC2_128_CBC: - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_PBE_SHA1_DES2_EDE_CBC: - case CKM_RC5_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_RC2_CBC_PAD: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_RC5_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - return 8; - case CKM_AES_CBC: - case CKM_AES_CBC_PAD: - return 16; - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - return 24; - case CKM_RC4: - case CKM_RSA_PKCS: - case CKM_RSA_9796: - case CKM_RSA_X_509: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: - case CKM_PBE_SHA1_RC4_40: - case CKM_PBE_SHA1_RC4_128: - return 0; - default: - return pk11_lookup(type)->iv; - } -} - - -/* These next two utilities are here to help facilitate future - * Dynamic Encrypt/Decrypt symetric key mechanisms, and to allow functions - * like SSL and S-MIME to automatically add them. - */ -SECItem * -PK11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv) -{ - CK_RC2_CBC_PARAMS *rc2_params = NULL; - CK_RC2_PARAMS *rc2_ecb_params = NULL; - CK_RC5_PARAMS *rc5_params = NULL; - CK_RC5_CBC_PARAMS *rc5_cbc_params = NULL; - SECItem *param; - - param = (SECItem *)PORT_Alloc(sizeof(SECItem)); - if (param == NULL) return NULL; - param->data = NULL; - param->len = 0; - param->type = 0; - switch (type) { - case CKM_AES_ECB: - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_RSA_PKCS: - case CKM_RSA_X_509: - case CKM_RSA_9796: - case CKM_IDEA_ECB: - case CKM_CDMF_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - case CKM_RC4: - break; - case CKM_RC2_ECB: - rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); - if (rc2_ecb_params == NULL) break; - /* Maybe we should pass the key size in too to get this value? */ - *rc2_ecb_params = 128; - param->data = (unsigned char *) rc2_ecb_params; - param->len = sizeof(CK_RC2_PARAMS); - break; - case CKM_RC2_CBC: - case CKM_RC2_CBC_PAD: - rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); - if (rc2_params == NULL) break; - /* Maybe we should pass the key size in too to get this value? */ - rc2_params->ulEffectiveBits = 128; - if (iv && iv->data) - PORT_Memcpy(rc2_params->iv,iv->data,sizeof(rc2_params->iv)); - param->data = (unsigned char *) rc2_params; - param->len = sizeof(CK_RC2_CBC_PARAMS); - break; - case CKM_RC5_CBC: - case CKM_RC5_CBC_PAD: - rc5_cbc_params = (CK_RC5_CBC_PARAMS *) - PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + ((iv) ? iv->len : 0)); - if (rc5_cbc_params == NULL) break; - if (iv && iv->data) { - rc5_cbc_params->pIv = ((CK_BYTE_PTR) rc5_cbc_params) - + sizeof(CK_RC5_CBC_PARAMS); - PORT_Memcpy(rc5_cbc_params->pIv,iv->data,iv->len); - rc5_cbc_params->ulIvLen = iv->len; - rc5_cbc_params->ulWordsize = iv->len/2; - } else { - rc5_cbc_params->ulWordsize = 4; - rc5_cbc_params->pIv = NULL; - rc5_cbc_params->ulIvLen = iv->len; - } - rc5_cbc_params->ulRounds = 16; - param->data = (unsigned char *) rc5_cbc_params; - param->len = sizeof(CK_RC5_CBC_PARAMS); - break; - case CKM_RC5_ECB: - rc5_params = (CK_RC5_PARAMS *)PORT_Alloc(sizeof(CK_RC5_PARAMS)); - if (rc5_params == NULL) break; - if (iv && iv->data && iv->len) { - rc5_params->ulWordsize = iv->len/2; - } else { - rc5_params->ulWordsize = 4; - } - rc5_params->ulRounds = 16; - param->data = (unsigned char *) rc5_params; - param->len = sizeof(CK_RC5_PARAMS); - break; - case CKM_AES_CBC: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_CDMF_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_AES_CBC_PAD: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_CDMF_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - if ((iv == NULL) || (iv->data == NULL)) break; - param->data = (unsigned char*)PORT_Alloc(iv->len); - if (param->data != NULL) { - PORT_Memcpy(param->data,iv->data,iv->len); - param->len = iv->len; - } - break; - /* unknown mechanism, pass IV in if it's there */ - default: - if (pk11_lookup(type)->iv == 0) { - break; - } - if ((iv == NULL) || (iv->data == NULL)) { - break; - } - param->data = (unsigned char*)PORT_Alloc(iv->len); - if (param->data != NULL) { - PORT_Memcpy(param->data,iv->data,iv->len); - param->len = iv->len; - } - break; - } - return param; -} - -unsigned char * -PK11_IVFromParam(CK_MECHANISM_TYPE type,SECItem *param,int *len) -{ - CK_RC2_CBC_PARAMS *rc2_params; - CK_RC5_CBC_PARAMS *rc5_cbc_params; - - *len = 0; - switch (type) { - case CKM_AES_ECB: - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_RSA_PKCS: - case CKM_RSA_X_509: - case CKM_RSA_9796: - case CKM_IDEA_ECB: - case CKM_CDMF_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - case CKM_RC4: - return NULL; - case CKM_RC2_ECB: - return NULL; - case CKM_RC2_CBC: - case CKM_RC2_CBC_PAD: - rc2_params = (CK_RC2_CBC_PARAMS *)param->data; - *len = sizeof(rc2_params->iv); - return &rc2_params->iv[0]; - case CKM_RC5_CBC: - case CKM_RC5_CBC_PAD: - rc5_cbc_params = (CK_RC5_CBC_PARAMS *) param->data; - *len = rc5_cbc_params->ulIvLen; - return rc5_cbc_params->pIv; - case CKM_AES_CBC: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_CDMF_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_CDMF_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - break; - /* unknown mechanism, pass IV in if it's there */ - default: - break; - } - if (param->data) { - *len = param->len; - } - return param->data; -} - -typedef struct sec_rc5cbcParameterStr { - SECItem version; - SECItem rounds; - SECItem blockSizeInBits; - SECItem iv; -} sec_rc5cbcParameter; - -static const SEC_ASN1Template sec_rc5ecb_parameter_template[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(sec_rc5cbcParameter) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc5cbcParameter,version) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc5cbcParameter,rounds) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc5cbcParameter,blockSizeInBits) }, - { 0 } -}; - -static const SEC_ASN1Template sec_rc5cbc_parameter_template[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(sec_rc5cbcParameter) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc5cbcParameter,version) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc5cbcParameter,rounds) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc5cbcParameter,blockSizeInBits) }, - { SEC_ASN1_OCTET_STRING, - offsetof(sec_rc5cbcParameter,iv) }, - { 0 } -}; - -typedef struct sec_rc2cbcParameterStr { - SECItem rc2ParameterVersion; - SECItem iv; -} sec_rc2cbcParameter; - -static const SEC_ASN1Template sec_rc2cbc_parameter_template[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(sec_rc2cbcParameter) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, - { SEC_ASN1_OCTET_STRING, - offsetof(sec_rc2cbcParameter,iv) }, - { 0 } -}; - -static const SEC_ASN1Template sec_rc2ecb_parameter_template[] = { - { SEC_ASN1_SEQUENCE, - 0, NULL, sizeof(sec_rc2cbcParameter) }, - { SEC_ASN1_INTEGER, - offsetof(sec_rc2cbcParameter,rc2ParameterVersion) }, - { 0 } -}; - -/* S/MIME picked id values to represent differnt keysizes */ -/* I do have a formula, but it ain't pretty, and it only works because you - * can always match three points to a parabola:) */ -static unsigned char rc2_map(SECItem *version) -{ - long x; - - x = DER_GetInteger(version); - - switch (x) { - case 58: return 128; - case 120: return 64; - case 160: return 40; - } - return 128; -} - -static unsigned long rc2_unmap(unsigned long x) -{ - switch (x) { - case 128: return 58; - case 64: return 120; - case 40: return 160; - } - return 58; -} - - - -/* Generate a mechaism param from a type, and iv. */ -SECItem * -PK11_ParamFromAlgid(SECAlgorithmID *algid) -{ - CK_RC2_CBC_PARAMS * rc2_cbc_params = NULL; - CK_RC2_PARAMS * rc2_ecb_params = NULL; - CK_RC5_CBC_PARAMS * rc5_cbc_params = NULL; - CK_RC5_PARAMS * rc5_ecb_params = NULL; - PRArenaPool * arena = NULL; - SECItem * mech = NULL; - SECOidTag algtag; - SECStatus rv; - CK_MECHANISM_TYPE type; - /* initialize these to prevent UMRs in the ASN1 decoder. */ - SECItem iv = {siBuffer, NULL, 0}; - sec_rc2cbcParameter rc2 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; - sec_rc5cbcParameter rc5 = { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}, - {siBuffer, NULL, 0}, {siBuffer, NULL, 0} }; - - algtag = SECOID_GetAlgorithmTag(algid); - type = PK11_AlgtagToMechanism(algtag); - - mech = PORT_New(SECItem); - if (mech == NULL) { - return NULL; - } - mech->type = siBuffer; - mech->data = NULL; - mech->len = 0; - - arena = PORT_NewArena(1024); - if (!arena) { - goto loser; - } - - /* handle the complicated cases */ - switch (type) { - case CKM_RC2_ECB: - rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2ecb_parameter_template, - &(algid->parameters)); - if (rv != SECSuccess) { - goto loser; - } - rc2_ecb_params = PORT_New(CK_RC2_PARAMS); - if (rc2_ecb_params == NULL) { - goto loser; - } - *rc2_ecb_params = rc2_map(&rc2.rc2ParameterVersion); - mech->data = (unsigned char *) rc2_ecb_params; - mech->len = sizeof *rc2_ecb_params; - break; - case CKM_RC2_CBC: - case CKM_RC2_CBC_PAD: - rv = SEC_ASN1DecodeItem(arena, &rc2 ,sec_rc2cbc_parameter_template, - &(algid->parameters)); - if (rv != SECSuccess) { - goto loser; - } - rc2_cbc_params = PORT_New(CK_RC2_CBC_PARAMS); - if (rc2_cbc_params == NULL) { - goto loser; - } - mech->data = (unsigned char *) rc2_cbc_params; - mech->len = sizeof *rc2_cbc_params; - rc2_cbc_params->ulEffectiveBits = rc2_map(&rc2.rc2ParameterVersion); - if (rc2.iv.len != sizeof rc2_cbc_params->iv) { - PORT_SetError(SEC_ERROR_INPUT_LEN); - goto loser; - } - PORT_Memcpy(rc2_cbc_params->iv, rc2.iv.data, rc2.iv.len); - break; - case CKM_RC5_ECB: - rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5ecb_parameter_template, - &(algid->parameters)); - if (rv != SECSuccess) { - goto loser; - } - rc5_ecb_params = PORT_New(CK_RC5_PARAMS); - if (rc5_ecb_params == NULL) { - goto loser; - } - rc5_ecb_params->ulRounds = DER_GetInteger(&rc5.rounds); - rc5_ecb_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; - mech->data = (unsigned char *) rc5_ecb_params; - mech->len = sizeof *rc5_ecb_params; - break; - case CKM_RC5_CBC: - case CKM_RC5_CBC_PAD: - rv = SEC_ASN1DecodeItem(arena, &rc5 ,sec_rc5cbc_parameter_template, - &(algid->parameters)); - if (rv != SECSuccess) { - goto loser; - } - rc5_cbc_params = (CK_RC5_CBC_PARAMS *) - PORT_Alloc(sizeof(CK_RC5_CBC_PARAMS) + rc5.iv.len); - if (rc5_cbc_params == NULL) { - goto loser; - } - mech->data = (unsigned char *) rc5_cbc_params; - mech->len = sizeof *rc5_cbc_params; - rc5_cbc_params->ulRounds = DER_GetInteger(&rc5.rounds); - rc5_cbc_params->ulWordsize = DER_GetInteger(&rc5.blockSizeInBits)/8; - rc5_cbc_params->pIv = ((CK_BYTE_PTR)rc5_cbc_params) - + sizeof(CK_RC5_CBC_PARAMS); - rc5_cbc_params->ulIvLen = rc5.iv.len; - PORT_Memcpy(rc5_cbc_params->pIv, rc5.iv.data, rc5.iv.len); - break; - case CKM_PBE_MD2_DES_CBC: - case CKM_PBE_MD5_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: - case CKM_PBE_SHA1_DES2_EDE_CBC: - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - case CKM_PBE_SHA1_RC2_128_CBC: - case CKM_PBE_SHA1_RC4_40: - case CKM_PBE_SHA1_RC4_128: - rv = pbe_PK11AlgidToParam(algid,mech); - if (rv != SECSuccess) { - goto loser; - } - break; - case CKM_RC4: - case CKM_AES_ECB: - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_IDEA_ECB: - case CKM_CDMF_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - break; - - default: - if (pk11_lookup(type)->iv == 0) { - break; - } - /* FALL THROUGH */ - case CKM_AES_CBC: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_CDMF_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_AES_CBC_PAD: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_CDMF_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - /* simple cases are simply octet string encoded IVs */ - rv = SEC_ASN1DecodeItem(arena, &iv, SEC_OctetStringTemplate, - &(algid->parameters)); - if (rv != SECSuccess || iv.data == NULL) { - goto loser; - } - /* XXX Should be some IV length sanity check here. */ - mech->data = (unsigned char*)PORT_Alloc(iv.len); - if (mech->data == NULL) { - goto loser; - } - PORT_Memcpy(mech->data, iv.data, iv.len); - mech->len = iv.len; - break; - } - PORT_FreeArena(arena, PR_FALSE); - return mech; - -loser: - if (arena) - PORT_FreeArena(arena, PR_FALSE); - SECITEM_FreeItem(mech,PR_TRUE); - return NULL; -} - SECStatus PK11_SeedRandom(PK11SlotInfo *slot, unsigned char *data, int len) { CK_RV crv; @@ -4036,595 +2177,6 @@ PK11_GenerateRandom(unsigned char *data,int len) { return (crv != CKR_OK) ? SECFailure : SECSuccess; } -/* - * Generate an IV for the given mechanism - */ -static SECStatus -pk11_GenIV(CK_MECHANISM_TYPE type, SECItem *iv) { - int iv_size = PK11_GetIVLength(type); - SECStatus rv; - - iv->len = iv_size; - if (iv_size == 0) { - iv->data = NULL; - return SECSuccess; - } - - iv->data = (unsigned char *) PORT_Alloc(iv_size); - if (iv->data == NULL) { - iv->len = 0; - return SECFailure; - } - - rv = PK11_GenerateRandom(iv->data,iv->len); - if (rv != SECSuccess) { - PORT_Free(iv->data); - iv->data = NULL; iv->len = 0; - return SECFailure; - } - return SECSuccess; -} - - -/* - * create a new paramter block from the passed in MECHANISM and the - * key. Use Netscape's S/MIME Rules for the New param block. - */ -SECItem * -PK11_GenerateNewParam(CK_MECHANISM_TYPE type, PK11SymKey *key) { - CK_RC2_CBC_PARAMS *rc2_params; - CK_RC2_PARAMS *rc2_ecb_params; - SECItem *mech; - SECItem iv; - SECStatus rv; - - - mech = (SECItem *) PORT_Alloc(sizeof(SECItem)); - if (mech == NULL) return NULL; - - rv = SECSuccess; - mech->type = siBuffer; - switch (type) { - case CKM_RC4: - case CKM_AES_ECB: - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_IDEA_ECB: - case CKM_CDMF_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - mech->data = NULL; - mech->len = 0; - break; - case CKM_RC2_ECB: - rc2_ecb_params = (CK_RC2_PARAMS *)PORT_Alloc(sizeof(CK_RC2_PARAMS)); - if (rc2_ecb_params == NULL) { - rv = SECFailure; - break; - } - /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, - * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ - *rc2_ecb_params = PK11_GetKeyLength(key)*8; - mech->data = (unsigned char *) rc2_ecb_params; - mech->len = sizeof(CK_RC2_PARAMS); - break; - case CKM_RC2_CBC: - case CKM_RC2_CBC_PAD: - rv = pk11_GenIV(type,&iv); - if (rv != SECSuccess) { - break; - } - rc2_params = (CK_RC2_CBC_PARAMS *)PORT_Alloc(sizeof(CK_RC2_CBC_PARAMS)); - if (rc2_params == NULL) { - PORT_Free(iv.data); - rv = SECFailure; - break; - } - /* NOTE PK11_GetKeyLength can return -1 if the key isn't and RC2, RC5, - * or RC4 key. Of course that wouldn't happen here doing RC2:).*/ - rc2_params->ulEffectiveBits = PK11_GetKeyLength(key)*8; - if (iv.data) - PORT_Memcpy(rc2_params->iv,iv.data,sizeof(rc2_params->iv)); - mech->data = (unsigned char *) rc2_params; - mech->len = sizeof(CK_RC2_CBC_PARAMS); - PORT_Free(iv.data); - break; - case CKM_RC5_ECB: - PORT_Free(mech); - return PK11_ParamFromIV(type,NULL); - case CKM_RC5_CBC: - case CKM_RC5_CBC_PAD: - rv = pk11_GenIV(type,&iv); - if (rv != SECSuccess) { - break; - } - PORT_Free(mech); - return PK11_ParamFromIV(type,&iv); - default: - if (pk11_lookup(type)->iv == 0) { - mech->data = NULL; - mech->len = 0; - break; - } - case CKM_AES_CBC: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_CDMF_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_CDMF_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - rv = pk11_GenIV(type,&iv); - if (rv != SECSuccess) { - break; - } - mech->data = (unsigned char*)PORT_Alloc(iv.len); - if (mech->data == NULL) { - PORT_Free(iv.data); - rv = SECFailure; - break; - } - PORT_Memcpy(mech->data,iv.data,iv.len); - mech->len = iv.len; - PORT_Free(iv.data); - break; - } - if (rv != SECSuccess) { - SECITEM_FreeItem(mech,PR_TRUE); - return NULL; - } - return mech; - -} - -#define RC5_V10 0x10 - -/* turn a PKCS #11 parameter into a DER Encoded Algorithm ID */ -SECStatus -PK11_ParamToAlgid(SECOidTag algTag, SECItem *param, - PRArenaPool *arena, SECAlgorithmID *algid) { - CK_RC2_CBC_PARAMS *rc2_params; - sec_rc2cbcParameter rc2; - CK_RC5_CBC_PARAMS *rc5_params; - sec_rc5cbcParameter rc5; - CK_MECHANISM_TYPE type = PK11_AlgtagToMechanism(algTag); - SECItem *newParams = NULL; - SECStatus rv = SECFailure; - unsigned long rc2version; - - rv = SECSuccess; - switch (type) { - case CKM_RC4: - case CKM_AES_ECB: - case CKM_DES_ECB: - case CKM_DES3_ECB: - case CKM_IDEA_ECB: - case CKM_CDMF_ECB: - case CKM_CAST_ECB: - case CKM_CAST3_ECB: - case CKM_CAST5_ECB: - newParams = NULL; - rv = SECSuccess; - break; - case CKM_RC2_ECB: - break; - case CKM_RC2_CBC: - case CKM_RC2_CBC_PAD: - rc2_params = (CK_RC2_CBC_PARAMS *)param->data; - rc2version = rc2_unmap(rc2_params->ulEffectiveBits); - if (SEC_ASN1EncodeUnsignedInteger (NULL, &(rc2.rc2ParameterVersion), - rc2version) == NULL) - break; - rc2.iv.data = rc2_params->iv; - rc2.iv.len = sizeof(rc2_params->iv); - newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc2, - sec_rc2cbc_parameter_template); - PORT_Free(rc2.rc2ParameterVersion.data); - if (newParams == NULL) - break; - rv = SECSuccess; - break; - - case CKM_RC5_ECB: /* well not really... */ - break; - case CKM_RC5_CBC: - case CKM_RC5_CBC_PAD: - rc5_params = (CK_RC5_CBC_PARAMS *)param->data; - if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.version, RC5_V10) == NULL) - break; - if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.blockSizeInBits, - rc5_params->ulWordsize*8) == NULL) { - PORT_Free(rc5.version.data); - break; - } - if (SEC_ASN1EncodeUnsignedInteger (NULL, &rc5.rounds, - rc5_params->ulWordsize*8) == NULL) { - PORT_Free(rc5.blockSizeInBits.data); - PORT_Free(rc5.version.data); - break; - } - rc5.iv.data = rc5_params->pIv; - rc5.iv.len = rc5_params->ulIvLen; - newParams = SEC_ASN1EncodeItem (NULL, NULL, &rc5, - sec_rc5cbc_parameter_template); - PORT_Free(rc5.version.data); - PORT_Free(rc5.blockSizeInBits.data); - PORT_Free(rc5.rounds.data); - if (newParams == NULL) - break; - rv = SECSuccess; - break; - case CKM_PBE_MD2_DES_CBC: - case CKM_PBE_MD5_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_PBE_SHA1_DES2_EDE_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - case CKM_PBE_SHA1_RC2_128_CBC: - case CKM_PBE_SHA1_RC4_40: - case CKM_PBE_SHA1_RC4_128: - return PBE_PK11ParamToAlgid(algTag, param, arena, algid); - default: - if (pk11_lookup(type)->iv == 0) { - rv = SECSuccess; - newParams = NULL; - break; - } - case CKM_AES_CBC: - case CKM_DES_CBC: - case CKM_DES3_CBC: - case CKM_IDEA_CBC: - case CKM_CDMF_CBC: - case CKM_CAST_CBC: - case CKM_CAST3_CBC: - case CKM_CAST5_CBC: - case CKM_DES_CBC_PAD: - case CKM_DES3_CBC_PAD: - case CKM_IDEA_CBC_PAD: - case CKM_CDMF_CBC_PAD: - case CKM_CAST_CBC_PAD: - case CKM_CAST3_CBC_PAD: - case CKM_CAST5_CBC_PAD: - case CKM_SKIPJACK_CBC64: - case CKM_SKIPJACK_ECB64: - case CKM_SKIPJACK_OFB64: - case CKM_SKIPJACK_CFB64: - case CKM_SKIPJACK_CFB32: - case CKM_SKIPJACK_CFB16: - case CKM_SKIPJACK_CFB8: - case CKM_BATON_ECB128: - case CKM_BATON_ECB96: - case CKM_BATON_CBC128: - case CKM_BATON_COUNTER: - case CKM_BATON_SHUFFLE: - case CKM_JUNIPER_ECB128: - case CKM_JUNIPER_CBC128: - case CKM_JUNIPER_COUNTER: - case CKM_JUNIPER_SHUFFLE: - newParams = SEC_ASN1EncodeItem(NULL,NULL,param, - SEC_OctetStringTemplate); - rv = SECSuccess; - break; - } - - if (rv != SECSuccess) { - if (newParams) SECITEM_FreeItem(newParams,PR_TRUE); - return rv; - } - - rv = SECOID_SetAlgorithmID(arena, algid, algTag, newParams); - SECITEM_FreeItem(newParams,PR_TRUE); - return rv; -} - -/* turn an OID algorithm tag into a PKCS #11 mechanism. This allows us to - * map OID's directly into the PKCS #11 mechanism we want to call. We find - * this mapping in our standard OID table */ -CK_MECHANISM_TYPE -PK11_AlgtagToMechanism(SECOidTag algTag) { - SECOidData *oid = SECOID_FindOIDByTag(algTag); - - if (oid) return (CK_MECHANISM_TYPE) oid->mechanism; - return CKM_INVALID_MECHANISM; -} - -/* turn a mechanism into an oid. */ -SECOidTag -PK11_MechanismToAlgtag(CK_MECHANISM_TYPE type) { - SECOidData *oid = SECOID_FindOIDByMechanism((unsigned long)type); - - if (oid) return oid->offset; - return SEC_OID_UNKNOWN; -} - -/* Determine appropriate blocking mechanism, used when wrapping private keys - * which require PKCS padding. If the mechanism does not map to a padding - * mechanism, we simply return the mechanism. - */ -CK_MECHANISM_TYPE -PK11_GetPadMechanism(CK_MECHANISM_TYPE type) { - switch(type) { - case CKM_AES_CBC: - return CKM_AES_CBC_PAD; - case CKM_DES_CBC: - return CKM_DES_CBC_PAD; - case CKM_DES3_CBC: - return CKM_DES3_CBC_PAD; - case CKM_RC2_CBC: - return CKM_RC2_CBC_PAD; - case CKM_CDMF_CBC: - return CKM_CDMF_CBC_PAD; - case CKM_CAST_CBC: - return CKM_CAST_CBC_PAD; - case CKM_CAST3_CBC: - return CKM_CAST3_CBC_PAD; - case CKM_CAST5_CBC: - return CKM_CAST5_CBC_PAD; - case CKM_RC5_CBC: - return CKM_RC5_CBC_PAD; - case CKM_IDEA_CBC: - return CKM_IDEA_CBC_PAD; - default: - break; - } - - return type; -} - -/* - * Build a block big enough to hold the data - */ -SECItem * -PK11_BlockData(SECItem *data,unsigned long size) { - SECItem *newData; - - newData = (SECItem *)PORT_Alloc(sizeof(SECItem)); - if (newData == NULL) return NULL; - - newData->len = (data->len + (size-1))/size; - newData->len *= size; - - newData->data = (unsigned char *) PORT_ZAlloc(newData->len); - if (newData->data == NULL) { - PORT_Free(newData); - return NULL; - } - PORT_Memset(newData->data,newData->len-data->len,newData->len); - PORT_Memcpy(newData->data,data->data,data->len); - return newData; -} - - -SECStatus -PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { - CK_RV crv; - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_DestroyObject(slot->session,object); - PK11_ExitSlotMonitor(slot); - if (crv != CKR_OK) { - return SECFailure; - } - return SECSuccess; -} - -SECStatus -PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object) { - CK_RV crv; - SECStatus rv = SECSuccess; - CK_SESSION_HANDLE rwsession; - - - rwsession = PK11_GetRWSession(slot); - - crv = PK11_GETTAB(slot)->C_DestroyObject(rwsession,object); - if (crv != CKR_OK) { - rv = SECFailure; - PORT_SetError(PK11_MapError(crv)); - } - PK11_RestoreROSession(slot,rwsession); - return rv; -} - -/* - * Read in a single attribute into a SECItem. Allocate space for it with - * PORT_Alloc unless an arena is supplied. In the latter case use the arena - * to allocate the space. - */ -SECStatus -PK11_ReadAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - CK_ATTRIBUTE_TYPE type, PRArenaPool *arena, SECItem *result) { - CK_ATTRIBUTE attr = { 0, NULL, 0 }; - CK_RV crv; - - attr.type = type; - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); - if (crv != CKR_OK) { - PK11_ExitSlotMonitor(slot); - PORT_SetError(PK11_MapError(crv)); - return SECFailure; - } - if (arena) { - attr.pValue = PORT_ArenaAlloc(arena,attr.ulValueLen); - } else { - attr.pValue = PORT_Alloc(attr.ulValueLen); - } - if (attr.pValue == NULL) { - PK11_ExitSlotMonitor(slot); - return SECFailure; - } - crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); - PK11_ExitSlotMonitor(slot); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError(crv)); - if (!arena) PORT_Free(attr.pValue); - return SECFailure; - } - - result->data = (unsigned char*)attr.pValue; - result->len = attr.ulValueLen; - - return SECSuccess; -} - -/* - * Read in a single attribute into As a Ulong. - */ -CK_ULONG -PK11_ReadULongAttribute(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - CK_ATTRIBUTE_TYPE type) { - CK_ATTRIBUTE attr; - CK_ULONG value = CK_UNAVAILABLE_INFORMATION; - CK_RV crv; - - PK11_SETATTRS(&attr,type,&value,sizeof(value)); - - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,id,&attr,1); - PK11_ExitSlotMonitor(slot); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError(crv)); - } - return value; -} - -/* - * check to see if a bool has been set. - */ -CK_BBOOL -PK11_HasAttributeSet( PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - CK_ATTRIBUTE_TYPE type ) -{ - CK_BBOOL ckvalue = CK_FALSE; - CK_ATTRIBUTE theTemplate; - CK_RV crv; - - /* Prepare to retrieve the attribute. */ - PK11_SETATTRS( &theTemplate, type, &ckvalue, sizeof( CK_BBOOL ) ); - - /* Retrieve attribute value. */ - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB( slot )->C_GetAttributeValue( slot->session, id, - &theTemplate, 1 ); - PK11_ExitSlotMonitor(slot); - if( crv != CKR_OK ) { - PORT_SetError( PK11_MapError( crv ) ); - return CK_FALSE; - } - - return ckvalue; -} - -/* - * returns a full list of attributes. Allocate space for them. If an arena is - * provided, allocate space out of the arena. - */ -CK_RV -PK11_GetAttributes(PRArenaPool *arena,PK11SlotInfo *slot, - CK_OBJECT_HANDLE obj,CK_ATTRIBUTE *attr, int count) -{ - int i; - /* make pedantic happy... note that it's only used arena != NULL */ - void *mark = NULL; - CK_RV crv; - - /* - * first get all the lengths of the parameters. - */ - PK11_EnterSlotMonitor(slot); - crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); - if (crv != CKR_OK) { - PK11_ExitSlotMonitor(slot); - return crv; - } - - if (arena) { - mark = PORT_ArenaMark(arena); - if (mark == NULL) return CKR_HOST_MEMORY; - } - - /* - * now allocate space to store the results. - */ - for (i=0; i < count; i++) { - if (arena) { - attr[i].pValue = PORT_ArenaAlloc(arena,attr[i].ulValueLen); - if (attr[i].pValue == NULL) { - /* arena failures, just release the mark */ - PORT_ArenaRelease(arena,mark); - PK11_ExitSlotMonitor(slot); - return CKR_HOST_MEMORY; - } - } else { - attr[i].pValue = PORT_Alloc(attr[i].ulValueLen); - if (attr[i].pValue == NULL) { - /* Separate malloc failures, loop to release what we have - * so far */ - int j; - for (j= 0; j < i; j++) { - PORT_Free(attr[j].pValue); - /* don't give the caller pointers to freed memory */ - attr[j].pValue = NULL; - } - PK11_ExitSlotMonitor(slot); - return CKR_HOST_MEMORY; - } - } - } - - /* - * finally get the results. - */ - crv = PK11_GETTAB(slot)->C_GetAttributeValue(slot->session,obj,attr,count); - PK11_ExitSlotMonitor(slot); - if (crv != CKR_OK) { - if (arena) { - PORT_ArenaRelease(arena,mark); - } else { - for (i= 0; i < count; i++) { - PORT_Free(attr[i].pValue); - /* don't give the caller pointers to freed memory */ - attr[i].pValue = NULL; - } - } - } else if (arena && mark) { - PORT_ArenaUnmark(arena,mark); - } - return crv; -} - /* * Reset the token to it's initial state. For the internal module, this will * Purge your keydb, and reset your cert db certs to USER_INIT. @@ -4670,165 +2222,16 @@ PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd) slot->nssToken); return SECSuccess; } - -static PRBool -pk11_isAllZero(unsigned char *data,int len) { - while (len--) { - if (*data++) { - return PR_FALSE; - } - } - return PR_TRUE; +void +PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst) +{ + sl->nssToken = nsst; } -CK_RV -PK11_MapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism, - CK_MECHANISM_PTR pCryptoMechanism, - SECItem *pbe_pwd, PRBool faulty3DES) +NSSToken * +PK11Slot_GetNSSToken(PK11SlotInfo *sl) { - int iv_len = 0; - CK_PBE_PARAMS_PTR pPBEparams; - CK_RC2_CBC_PARAMS_PTR rc2_params; - CK_ULONG rc2_key_len; - - if((pPBEMechanism == CK_NULL_PTR) || (pCryptoMechanism == CK_NULL_PTR)) { - return CKR_HOST_MEMORY; - } - - pPBEparams = (CK_PBE_PARAMS_PTR)pPBEMechanism->pParameter; - iv_len = PK11_GetIVLength(pPBEMechanism->mechanism); - - if (iv_len) { - if (pk11_isAllZero(pPBEparams->pInitVector,iv_len)) { - SECItem param; - PK11SymKey *symKey; - PK11SlotInfo *intSlot = PK11_GetInternalSlot(); - - if (intSlot == NULL) { - return CKR_DEVICE_ERROR; - } - - param.data = pPBEMechanism->pParameter; - param.len = pPBEMechanism->ulParameterLen; - - symKey = PK11_RawPBEKeyGen(intSlot, - pPBEMechanism->mechanism, ¶m, pbe_pwd, faulty3DES, NULL); - PK11_FreeSlot(intSlot); - if (symKey== NULL) { - return CKR_DEVICE_ERROR; /* sigh */ - } - PK11_FreeSymKey(symKey); - } - } - - switch(pPBEMechanism->mechanism) { - case CKM_PBE_MD2_DES_CBC: - case CKM_PBE_MD5_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_DES_CBC: - pCryptoMechanism->mechanism = CKM_DES_CBC; - goto have_crypto_mechanism; - case CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC: - case CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC: - case CKM_PBE_SHA1_DES3_EDE_CBC: - case CKM_PBE_SHA1_DES2_EDE_CBC: - pCryptoMechanism->mechanism = CKM_DES3_CBC; -have_crypto_mechanism: - pCryptoMechanism->pParameter = PORT_Alloc(iv_len); - pCryptoMechanism->ulParameterLen = (CK_ULONG)iv_len; - if(pCryptoMechanism->pParameter == NULL) { - return CKR_HOST_MEMORY; - } - PORT_Memcpy((unsigned char *)(pCryptoMechanism->pParameter), - (unsigned char *)(pPBEparams->pInitVector), - iv_len); - break; - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4: - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4: - case CKM_PBE_SHA1_RC4_40: - case CKM_PBE_SHA1_RC4_128: - pCryptoMechanism->mechanism = CKM_RC4; - pCryptoMechanism->ulParameterLen = 0; - pCryptoMechanism->pParameter = CK_NULL_PTR; - break; - case CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC: - case CKM_PBE_SHA1_RC2_40_CBC: - rc2_key_len = 40; - goto have_key_len; - case CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC: - rc2_key_len = 128; -have_key_len: - pCryptoMechanism->mechanism = CKM_RC2_CBC; - pCryptoMechanism->ulParameterLen = (CK_ULONG) - sizeof(CK_RC2_CBC_PARAMS); - pCryptoMechanism->pParameter = (CK_RC2_CBC_PARAMS_PTR) - PORT_ZAlloc(sizeof(CK_RC2_CBC_PARAMS)); - if(pCryptoMechanism->pParameter == NULL) { - return CKR_HOST_MEMORY; - } - rc2_params = (CK_RC2_CBC_PARAMS_PTR)pCryptoMechanism->pParameter; - PORT_Memcpy((unsigned char *)rc2_params->iv, - (unsigned char *)pPBEparams->pInitVector, - iv_len); - rc2_params->ulEffectiveBits = rc2_key_len; - break; - default: - return CKR_MECHANISM_INVALID; - } - - return CKR_OK; -} - -PRBool -PK11_IsPermObject(PK11SlotInfo *slot, CK_OBJECT_HANDLE handle) -{ - return (PRBool) PK11_HasAttributeSet(slot, handle, CKA_TOKEN); -} - -char * -PK11_GetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id) -{ - char *nickname = NULL; - SECItem result; - SECStatus rv; - - rv = PK11_ReadAttribute(slot,id,CKA_LABEL,NULL,&result); - if (rv != SECSuccess) { - return NULL; - } - - nickname = PORT_ZAlloc(result.len+1); - if (nickname == NULL) { - PORT_Free(result.data); - return NULL; - } - PORT_Memcpy(nickname, result.data, result.len); - PORT_Free(result.data); - return nickname; -} - -SECStatus -PK11_SetObjectNickname(PK11SlotInfo *slot, CK_OBJECT_HANDLE id, - const char *nickname) -{ - int len = PORT_Strlen(nickname); - CK_ATTRIBUTE setTemplate; - CK_RV crv; - CK_SESSION_HANDLE rwsession; - - if (len < 0) { - return SECFailure; - } - - PK11_SETATTRS(&setTemplate, CKA_LABEL, (CK_CHAR *) nickname, len); - rwsession = PK11_GetRWSession(slot); - crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession, id, - &setTemplate, 1); - PK11_RestoreROSession(slot, rwsession); - if (crv != CKR_OK) { - PORT_SetError(PK11_MapError(crv)); - return SECFailure; - } - return SECSuccess; + return sl->nssToken; } /* @@ -4877,4 +2280,3 @@ PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event, } return waitForRemoval ? PK11TokenRemoved : PK11TokenPresent; } - diff --git a/security/nss/lib/pk11wrap/pk11util.c b/security/nss/lib/pk11wrap/pk11util.c index aead3402a39..5b40d5692d0 100644 --- a/security/nss/lib/pk11wrap/pk11util.c +++ b/security/nss/lib/pk11wrap/pk11util.c @@ -40,6 +40,7 @@ #include "secmod.h" #include "nssilock.h" #include "secmodi.h" +#include "secmodti.h" #include "pk11func.h" #include "pki3hack.h" #include "secerr.h" diff --git a/security/nss/lib/pk11wrap/secmod.h b/security/nss/lib/pk11wrap/secmod.h index d8a89baeda4..82ba316a489 100644 --- a/security/nss/lib/pk11wrap/secmod.h +++ b/security/nss/lib/pk11wrap/secmod.h @@ -91,8 +91,6 @@ SECStatus SECMOD_UnloadUserModule(SECMODModule *mod); SECMODModule * SECMOD_CreateModule(const char *lib, const char *name, const char *param, const char *nss); -extern SECStatus SECMOD_Shutdown(void); -void nss_DumpModuleLog(void); /* Module Management */ @@ -114,12 +112,8 @@ extern SECMODListLock *SECMOD_GetDefaultModuleListLock(void); extern SECStatus SECMOD_UpdateModule(SECMODModule *module); /* lock management */ -extern SECMODListLock *SECMOD_NewListLock(void); -extern void SECMOD_DestroyListLock(SECMODListLock *); extern void SECMOD_GetReadLock(SECMODListLock *); extern void SECMOD_ReleaseReadLock(SECMODListLock *); -extern void SECMOD_GetWriteLock(SECMODListLock *); -extern void SECMOD_ReleaseWriteLock(SECMODListLock *); /* Operate on modules by name */ extern SECMODModule *SECMOD_FindModule(const char *name); @@ -152,10 +146,7 @@ PRBool SECMOD_IsModulePresent( unsigned long int pubCipherEnableFlags ); /* Functions used to convert between internal & public representation * of Mechanism Flags and Cipher Enable Flags */ extern unsigned long SECMOD_PubMechFlagstoInternal(unsigned long publicFlags); -extern unsigned long SECMOD_InternaltoPubMechFlags(unsigned long internalFlags); - extern unsigned long SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags); -extern unsigned long SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags); SEC_END_PROTOS diff --git a/security/nss/lib/pk11wrap/secmodi.h b/security/nss/lib/pk11wrap/secmodi.h index 1bfefaba0a6..e9a5d3103fb 100644 --- a/security/nss/lib/pk11wrap/secmodi.h +++ b/security/nss/lib/pk11wrap/secmodi.h @@ -46,7 +46,7 @@ #include "secdert.h" #include "certt.h" #include "secmodt.h" -#include "secmodti.h" +#include "keyt.h" #ifdef PKCS11_USE_THREADS #define PK11_USE_THREADS(x) x @@ -59,6 +59,8 @@ SEC_BEGIN_PROTOS /* proto-types */ extern SECStatus SECMOD_DeletePermDB(SECMODModule *module); extern SECStatus SECMOD_AddPermDB(SECMODModule *module); +extern SECStatus SECMOD_Shutdown(void); +void nss_DumpModuleLog(void); extern int secmod_PrivateModuleCount; @@ -70,6 +72,10 @@ extern SECStatus SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule); extern SECStatus SECMOD_AddModuleToUnloadList(SECMODModule *newModule); extern void SECMOD_RemoveList(SECMODModuleList **,SECMODModuleList *); extern void SECMOD_AddList(SECMODModuleList *,SECMODModuleList *,SECMODListLock *); +extern SECMODListLock *SECMOD_NewListLock(void); +extern void SECMOD_DestroyListLock(SECMODListLock *); +extern void SECMOD_GetWriteLock(SECMODListLock *); +extern void SECMOD_ReleaseWriteLock(SECMODListLock *); /* Operate on modules by name */ extern SECMODModule *SECMOD_FindModuleByID(SECMODModuleID); @@ -81,7 +87,7 @@ extern void SECMOD_DestroyModuleList(SECMODModuleList *); extern SECStatus SECMOD_AddModule(SECMODModule *newModule); SECStatus SECMOD_DeleteModuleEx(const char * name, SECMODModule *mod, int *type, PRBool permdb); -extern unsigned long SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags); +extern unsigned long SECMOD_InternaltoPubMechFlags(unsigned long internalFlags); extern unsigned long SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags); /* Library functions */ @@ -114,8 +120,39 @@ SECStatus PBE_PK11ParamToAlgid(SECOidTag algTag, SECItem *param, extern void pk11sdr_Init(void); extern void pk11sdr_Shutdown(void); -PRBool pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx); +/* + * Private to pk11wrap. + */ +PRBool pk11_LoginStillRequired(PK11SlotInfo *slot, void *wincx); +CK_SESSION_HANDLE pk11_GetNewSession(PK11SlotInfo *slot, PRBool *owner); +void pk11_CloseSession(PK11SlotInfo *slot, CK_SESSION_HANDLE sess, PRBool own); +PK11SymKey *pk11_ForceSlot(PK11SymKey *symKey, CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation); +unsigned int pk11_FlagsToAttributes(CK_FLAGS flags, + CK_ATTRIBUTE *attrs, CK_BBOOL *ckTrue); +PRBool pk11_FindAttrInTemplate(CK_ATTRIBUTE *attr, unsigned int numAttrs, + CK_ATTRIBUTE_TYPE target); + +CK_MECHANISM_TYPE pk11_mapSignKeyType(KeyType keyType); +CK_MECHANISM_TYPE pk11_mapWrapKeyType(KeyType keyType); +PK11SymKey *pk11_KeyExchange(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, + CK_ATTRIBUTE_TYPE operation, CK_FLAGS flags, PRBool isPerm, + PK11SymKey *symKey); + +PRBool pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, + CERTCertTrust *trust); +CK_OBJECT_HANDLE pk11_FindPubKeyByAnyCert(CERTCertificate *cert, + PK11SlotInfo **slot, void *wincx); +SECStatus pk11_AuthenticateUnfriendly(PK11SlotInfo *slot, PRBool loadCerts, + void *wincx); +int PK11_NumberObjectsFor(PK11SlotInfo *slot, CK_ATTRIBUTE *findTemplate, + int templateCount); +SECItem *pk11_GetLowLevelKeyFromHandle(PK11SlotInfo *slot, + CK_OBJECT_HANDLE handle); +SECStatus PK11_TraverseSlot(PK11SlotInfo *slot, void *arg); +CK_OBJECT_HANDLE pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, + SECItem *keyID); SEC_END_PROTOS #endif diff --git a/security/nss/lib/pk11wrap/secmodt.h b/security/nss/lib/pk11wrap/secmodt.h index c2c7251f24a..987bb458231 100644 --- a/security/nss/lib/pk11wrap/secmodt.h +++ b/security/nss/lib/pk11wrap/secmodt.h @@ -281,4 +281,10 @@ typedef enum { PK11TokenPresentEvent = 1 } PK11TokenEvent; +/* + * CRL Import Flags + */ +#define CRL_IMPORT_DEFAULT_OPTIONS 0x00000000 +#define CRL_IMPORT_BYPASS_CHECKS 0x00000001 + #endif /*_SECMODT_H_ */ diff --git a/security/nss/lib/pk11wrap/secmodti.h b/security/nss/lib/pk11wrap/secmodti.h index c66d977ccc7..156d2333885 100644 --- a/security/nss/lib/pk11wrap/secmodti.h +++ b/security/nss/lib/pk11wrap/secmodti.h @@ -54,6 +54,15 @@ /* internal data structures */ +/* Traverse slots callback */ +typedef struct pk11TraverseSlotStr { + SECStatus (*callback)(PK11SlotInfo *,CK_OBJECT_HANDLE, void *); + void *callbackArg; + CK_ATTRIBUTE *findTemplate; + int templateCount; +} pk11TraverseSlot; + + /* structure to allow us to implement the read/write locks for our * module lists */ struct SECMODListLockStr { @@ -204,4 +213,11 @@ struct PK11GenericObjectStr { CK_OBJECT_HANDLE objectID; }; + +#define MAX_TEMPL_ATTRS 16 /* maximum attributes in template */ + +/* This mask includes all CK_FLAGs with an equivalent CKA_ attribute. */ +#define CKF_KEY_OPERATION_FLAGS 0x000e7b00UL + + #endif /* _SECMODTI_H_ */