gecko-dev/security/nss/lib/pk11wrap/pk11cert.c
2000-03-31 19:16:26 +00:00

2257 lines
60 KiB
C

/*
* 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 Netscape are
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
/*
* This file implements the Symkey wrapper and the PKCS context
* Interfaces.
*/
#include "seccomon.h"
#include "secmod.h"
#include "prlock.h"
#include "secmodi.h"
#include "pkcs11.h"
#include "pk11func.h"
#include "cert.h"
#include "secitem.h"
#include "key.h"
#include "hasht.h"
#include "secoid.h"
#include "pkcs7t.h"
#include "certdb.h"
#include "secerr.h"
#include "sslerr.h"
#define PK11_SEARCH_CHUNKSIZE 10
CK_OBJECT_HANDLE
pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx);
/*
* 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.
*/
static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); }
#define MAX_CERT_ID 4
#define DEFAULT_STRING "Cert ID "
static char *
pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label,
CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
{
int prefixLen = PORT_Strlen(slot->token_name);
int suffixLen = 0;
char *suffix = NULL;
char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2];
char *next,*nickname;
if (slot->isInternal) {
return NULL;
}
if ((cert_label) && (cert_label->pValue)) {
suffixLen = cert_label->ulValueLen;
suffix = (char*)cert_label->pValue;
} else if (key_label && (key_label->pValue)) {
suffixLen = key_label->ulValueLen;
suffix = (char*)key_label->pValue;
} else if ((cert_id) && cert_id->pValue) {
int i,first = cert_id->ulValueLen - MAX_CERT_ID;
int offset = sizeof(DEFAULT_STRING);
char *idValue = (char *)cert_id->pValue;
PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1);
next = buildNew + offset;
if (first < 0) first = 0;
for (i=first; i < (int) cert_id->ulValueLen; i++) {
*next++ = toHex((idValue[i] >> 4) & 0xf);
*next++ = toHex(idValue[i] & 0xf);
}
*next++ = 0;
suffix = buildNew;
suffixLen = PORT_Strlen(buildNew);
} else {
PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );
return NULL;
}
next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1);
if (nickname == NULL) return NULL;
PORT_Memcpy(next,slot->token_name,prefixLen);
next += prefixLen;
*next++ = ':';
PORT_Memcpy(next,suffix,suffixLen);
next += suffixLen;
*next++ = 0;
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_KEY;
}
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_KEY;
}
/* blow up if the PKCS #11 module returns us and invalid object handle */
PORT_Assert(object != CK_INVALID_KEY);
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_KEY;
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_KEY;
}
/*
* 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)
{
CK_OBJECT_CLASS theClass;
if (slot == NULL) return PR_FALSE;
if (cert == NULL) return PR_FALSE;
theClass = CKO_PRIVATE_KEY;
if (!PK11_IsLoggedIn(slot,NULL) && PK11_NeedLogin(slot)) {
theClass = CKO_PUBLIC_KEY;
}
if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_KEY) {
return PR_TRUE;
}
if (theClass == CKO_PUBLIC_KEY) {
SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert);
CK_ATTRIBUTE theTemplate;
if (pubKey == NULL) {
return PR_FALSE;
}
PK11_SETATTRS(&theTemplate,0,NULL,0);
switch (pubKey->keyType) {
case rsaKey:
PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data,
pubKey->u.rsa.modulus.len);
break;
case dsaKey:
PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data,
pubKey->u.dsa.publicValue.len);
case dhKey:
PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data,
pubKey->u.dh.publicValue.len);
break;
}
if (theTemplate.ulValueLen == 0) {
SECKEY_DestroyPublicKey(pubKey);
return PR_FALSE;
}
pk11_SignedToUnsigned(&theTemplate);
if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_KEY) {
SECKEY_DestroyPublicKey(pubKey);
return PR_TRUE;
}
SECKEY_DestroyPublicKey(pubKey);
}
return PR_FALSE;
}
/*
* Check out if a cert has ID of zero. This is a magic ID that tells
* NSS that this cert may be an automagically trusted cert.
* The Cert has to be self signed as well. That check is done elsewhere.
*
*/
PRBool
pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
{
CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0};
PRBool isZero = PR_FALSE;
int i;
CK_RV crv;
crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1);
if (crv != CKR_OK) {
return isZero;
}
if (keyID.ulValueLen != 0) {
char *value = (char *)keyID.pValue;
isZero = PR_TRUE; /* ID exists, may be zero */
for (i=0; i < (int) keyID.ulValueLen; i++) {
if (value[i] != 0) {
isZero = PR_FALSE; /* nope */
break;
}
}
}
PORT_Free(keyID.pValue);
return isZero;
}
CERTCertificate
*pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID,
CK_ATTRIBUTE *privateLabel, char **nickptr)
{
CK_ATTRIBUTE certTemp[] = {
{ CKA_ID, NULL, 0 },
{ CKA_VALUE, NULL, 0 },
{ CKA_LABEL, NULL, 0 }
};
CK_ATTRIBUTE *id = &certTemp[0];
CK_ATTRIBUTE *certDER = &certTemp[1];
CK_ATTRIBUTE *label = &certTemp[2];
SECItem derCert;
int csize = sizeof(certTemp)/sizeof(certTemp[0]);
PRArenaPool *arena;
char *nickname;
CERTCertificate *cert;
CK_RV crv;
arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);
if (arena == NULL) return NULL;
/*
* grab the der encoding
*/
crv = PK11_GetAttributes(arena,slot,certID,certTemp,csize);
if (crv != CKR_OK) {
PORT_FreeArena(arena,PR_FALSE);
PORT_SetError( PK11_MapError(crv) );
return NULL;
}
/*
* build a certificate out of it
*/
derCert.data = (unsigned char*)certDER->pValue;
derCert.len = certDER->ulValueLen;
/* figure out the nickname.... */
nickname = pk11_buildNickname(slot,label,privateLabel,id);
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, nickname,
PR_FALSE, PR_TRUE);
if (nickptr) {
*nickptr = nickname;
} else {
if (nickname) PORT_Free(nickname);
}
PORT_FreeArena(arena,PR_FALSE);
return cert;
}
/*
* Build an CERTCertificate structure from a PKCS#11 object ID.... certID
* Must be a CertObject. This code does not explicitly checks that.
*/
CERTCertificate *
PK11_MakeCertFromHandle(PK11SlotInfo *slot,CK_OBJECT_HANDLE certID,
CK_ATTRIBUTE *privateLabel)
{
char * nickname = NULL;
CERTCertificate *cert = NULL;
CERTCertTrust *trust;
PRBool isFortezzaRootCA = PR_FALSE;
PRBool swapNickname = PR_FALSE;
cert = pk11_fastCert(slot,certID,privateLabel, &nickname);
if (cert == NULL) goto loser;
if (nickname) {
if (cert->nickname != NULL) {
cert->dbnickname = cert->nickname;
}
cert->nickname = PORT_ArenaStrdup(cert->arena,nickname);
PORT_Free(nickname);
nickname = NULL;
swapNickname = PR_TRUE;
}
/* remember where this cert came from.... If we have just looked
* it up from the database and it already has a slot, don't add a new
* one. */
if (cert->slot == NULL) {
cert->slot = PK11_ReferenceSlot(slot);
cert->pkcs11ID = certID;
cert->ownSlot = PR_TRUE;
}
if (cert->trust == NULL) {
unsigned int type;
trust =
(CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
if (trust == NULL) goto loser;
PORT_Memset(trust,0, sizeof(CERTCertTrust));
cert->trust = trust;
/* build some cert trust flags */
if (CERT_IsCACert(cert, &type)) {
unsigned int trustflags = CERTDB_VALID_CA;
/* Allow PKCS #11 modules to give us trusted CA's. We only accept
* valid CA's which are self-signed here. They must have an object
* ID of '0'. */
if (pk11_isID0(slot,certID) &&
SECITEM_CompareItem(&cert->derSubject,&cert->derIssuer)
== SECEqual) {
trustflags |= CERTDB_TRUSTED_CA;
/* is the slot a fortezza card? allow the user or
* admin to turn on objectSigning, but don't turn
* full trust on explicitly */
if (PK11_DoesMechanism(slot,CKM_KEA_KEY_DERIVE)) {
trust->objectSigningFlags |= CERTDB_VALID_CA;
isFortezzaRootCA = PR_TRUE;
}
}
if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
trust->sslFlags |= trustflags;
}
if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
trust->emailFlags |= trustflags;
}
if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA)
== NS_CERT_TYPE_OBJECT_SIGNING_CA) {
trust->objectSigningFlags |= trustflags;
}
}
} else {
trust = cert->trust;
}
if (PK11_IsUserCert(slot,cert,certID)) {
trust->sslFlags |= CERTDB_USER;
trust->emailFlags |= CERTDB_USER;
/* trust->objectSigningFlags |= CERTDB_USER; */
}
/* if fortezza, write the root cert to the DB */
if ((isFortezzaRootCA) && (!cert->isperm)) {
char *name = NULL;
if (swapNickname) {
nickname = cert->nickname;
cert->nickname = cert->dbnickname;
}
if (cert->nickname) {
name = PORT_Strdup(cert->nickname);
}
if (name == NULL) name = CERT_MakeCANickname(cert);
CERT_AddTempCertToPerm(cert,name,cert->trust);
if (name) PORT_Free(name);
if (swapNickname) {
if (cert->nickname != NULL) {
cert->dbnickname = cert->nickname;
}
cert->nickname = PORT_ArenaStrdup(cert->arena,nickname);
}
}
return cert;
loser:
if (nickname) PORT_Free(nickname);
if (cert) CERT_DestroyCertificate(cert);
return NULL;
}
/*
* Build get a certificate from a private key
*/
CERTCertificate *
PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
{
PK11SlotInfo *slot = privKey->pkcs11Slot;
CK_OBJECT_HANDLE certID =
PK11_MatchItem(slot,privKey->pkcs11ID,CKO_CERTIFICATE);
SECStatus rv;
CERTCertificate *cert;
if (certID == CK_INVALID_KEY) {
/* couldn't find it on the card, look in our data base */
SECItem derSubject;
rv = PK11_ReadAttribute(slot, privKey->pkcs11ID, CKA_SUBJECT, NULL,
&derSubject);
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
return NULL;
}
cert = CERT_FindCertByName(CERT_GetDefaultCertDB(),&derSubject);
PORT_Free(derSubject.data);
return cert;
}
cert = PK11_MakeCertFromHandle(slot,certID,NULL);
return (cert);
}
/*
* destroy a private key if there are no matching certs.
* this function also frees the privKey structure.
*/
SECStatus
PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey)
{
CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey);
/* found a cert matching the private key?. */
if (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;
}
/*
* delete a cert and it's private key (if no other certs are pointing to the
* private key.
*/
SECStatus
PK11_DeleteTokenCertAndKey(CERTCertificate *cert,void *wincx)
{
SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert,wincx);
CK_OBJECT_HANDLE pubKey;
PK11SlotInfo *slot = NULL;
pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
if (privKey) {
PK11_DestroyTokenObject(cert->slot,cert->pkcs11ID);
PK11_DeleteTokenPrivateKey(privKey);
}
if ((pubKey != CK_INVALID_KEY) && (slot != NULL)) {
PK11_DestroyTokenObject(slot,pubKey);
PK11_FreeSlot(slot);
}
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
*/
typedef struct pk11DoCertCallbackStr {
SECStatus(* callback)(PK11SlotInfo *slot, CERTCertificate*, void *);
SECStatus(* noslotcallback)(CERTCertificate*, void *);
void *callbackArg;
} pk11DoCertCallback;
/*
* callback to map object handles to certificate structures.
*/
SECStatus
pk11_DoCerts(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, void *arg)
{
CERTCertificate *cert;
pk11DoCertCallback *certcb = (pk11DoCertCallback *) arg;
cert = PK11_MakeCertFromHandle(slot, certID, NULL);
if (cert == NULL) {
return SECFailure;
}
if (certcb ) {
if (certcb->callback) {
(*certcb->callback)(slot, cert, certcb->callbackArg);
}
if (certcb->noslotcallback) {
(*certcb->noslotcallback)(cert, certcb->callbackArg);
}
}
CERT_DestroyCertificate(cert);
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;
}
/* Traverse slots callback */
typedef struct pk11TraverseSlotStr {
SECStatus (*callback)(PK11SlotInfo *,CK_OBJECT_HANDLE, void *);
void *callbackArg;
CK_ATTRIBUTE *findTemplate;
int templateCount;
} pk11TraverseSlotCert;
/*
* 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;
CK_ULONG returned_count = 0;
pk11TraverseSlotCert *slotcb = (pk11TraverseSlotCert *) 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;
static SECStatus
pk11_SaveCert(PK11SlotInfo *slot, CERTCertificate *cert, void *arg)
{
pk11CertCallback *certcb = (pk11CertCallback *)arg;
SECStatus rv = SECSuccess;
if (slot->cert_count == slot->array_size) return CKR_OK;
slot->cert_array[slot->cert_count] = CERT_DupCertificate(cert);
if (slot->cert_array[slot->cert_count] == NULL) {
return SECFailure;
}
/* now the slot has a hold of the cert, free the slot's element in the
* cert.. */
if (cert->ownSlot && (slot == cert->slot)) {
PK11_FreeSlot(cert->slot);
cert->ownSlot = PR_FALSE;
}
slot->cert_count++;
if (certcb->callback) {
rv = (*certcb->callback)(cert, NULL, certcb->callbackArg);
}
return rv;
}
/* free the slots */
void
PK11_FreeSlotCerts(PK11SlotInfo *slot)
{
int i;
if (slot->cert_array) {
for (i=0; i < slot->cert_count; i++) {
/* if we point the cert on our array, the cert doesn't have a
* reference to use (otherwise you would never be able to free
* a slot :) */
if ((slot->cert_array[i]->slot == slot) &&
(!slot->cert_array[i]->ownSlot)) {
slot->cert_array[i]->slot = NULL;
}
CERT_DestroyCertificate(slot->cert_array[i]);
}
PORT_Free(slot->cert_array);
slot->cert_array = NULL;
slot->cert_count = 0;
}
return;
}
/*
* Update PQG parameters for all the certs on a slot.
*/
static SECStatus
pk11_UpdateSlotPQG(PK11SlotInfo *slot)
{
int i, tag;
CERTCertificate * cert;
SECOidData *oid;
SECStatus rv1 = SECSuccess;
SECStatus rv2 = SECSuccess;
if (slot->cert_array) {
for (i=0; i < slot->cert_count; i++) {
cert = slot->cert_array[i];
oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
if (oid != NULL) {
tag = oid->offset;
/* Check if cert has a DSA or Fortezza public key */
if ( (tag == SEC_OID_MISSI_KEA_DSS_OLD) ||
(tag == SEC_OID_MISSI_DSS_OLD) ||
(tag == SEC_OID_MISSI_KEA_DSS) ||
(tag == SEC_OID_MISSI_DSS) ||
(tag == SEC_OID_ANSIX9_DSA_SIGNATURE) ||
(tag == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) ||
(tag == SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) ) {
/* update PQG parameters */
rv1 = SECKEY_UpdateCertPQG(cert);
if (rv1 == SECFailure) {
rv2 = rv1;
}
}
} /* end of if oid != NULL */
} /* end of for loop */
}
return rv2;
}
/*
* Extract all the certs on a card from a slot.
*/
static SECStatus
pk11_ExtractCertsFromSlot(PK11SlotInfo *slot, void *arg)
{
pk11TraverseSlotCert *slotcb = (pk11TraverseSlotCert *) arg;
int object_count;
SECStatus rv;
rv = SECSuccess;
PK11_FreeSlotCerts(slot);
object_count = PK11_NumberObjectsFor(slot,slotcb->findTemplate,
slotcb->templateCount);
/*Actually this isn't a failure... there just were no certs to be found*/
if (object_count == 0) {
return SECSuccess;
}
slot->cert_array = (CERTCertificate **)
PORT_Alloc(sizeof(CERTCertificate *)*object_count);
if (slot->cert_array == NULL) {
return SECFailure;
}
slot->cert_count = 0;
slot->array_size = object_count;
PK11_TraverseSlot(slot,arg);
/* Update the PQG parameters for the extracted certs. */
rv = pk11_UpdateSlotPQG(slot);
return rv;
}
/*
* read all the certs from a slot
*/
SECStatus
PK11_ReadSlotCerts(PK11SlotInfo *slot)
{
/* build slot list */
pk11CertCallback caller;
pk11DoCertCallback saver;
pk11TraverseSlotCert creater;
CK_ATTRIBUTE theTemplate;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
PK11_SETATTRS(&theTemplate, CKA_CLASS, &certClass, sizeof(certClass));
caller.callback = NULL;
caller.callbackArg = NULL;
saver.callback = pk11_SaveCert;
saver.noslotcallback = NULL;
saver.callbackArg = (void *) & caller;
creater.callback = pk11_DoCerts;
creater.callbackArg = (void *) & saver;
creater.findTemplate = &theTemplate;
creater.templateCount = 1;
return pk11_ExtractCertsFromSlot(slot, &creater);
}
/*
* Extract all the certs on a card from a slot.
*/
static SECStatus
pk11_TraverseAllSlots(PRBool loadCerts,
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,loadCerts,wincx);
if (list == NULL) return SECFailure;
/* look at each slot and authenticate as necessary */
for (le = list->head ; le; le = le->next) {
/* don't nab internal slots */
if ((!loadCerts) && le->slot->isInternal == PR_TRUE) {
continue;
}
if (loadCerts || !PK11_IsFriendly(le->slot)) {
rv = PK11_Authenticate(le->slot, loadCerts, wincx);
if (rv != SECSuccess) continue;
}
(*callback)(le->slot,arg);
}
PK11_FreeSlotList(list);
return SECSuccess;
}
/*
* Extract all the certs on a card from a slot.
*/
SECStatus
PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
void *arg, void *wincx) {
pk11CertCallback caller;
pk11DoCertCallback saver;
pk11TraverseSlotCert creater;
CK_ATTRIBUTE theTemplate;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
PK11_SETATTRS(&theTemplate, CKA_CLASS, &certClass, sizeof(certClass));
caller.callback = callback;
caller.callbackArg = arg;
saver.callback = pk11_SaveCert;
saver.noslotcallback = NULL;
saver.callbackArg = (void *) & caller;
creater.callback = pk11_DoCerts;
creater.callbackArg = (void *) & saver;
creater.findTemplate = &theTemplate;
creater.templateCount = 1;
return pk11_TraverseAllSlots(PR_FALSE, pk11_ExtractCertsFromSlot,
&creater, wincx);
}
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_KEY;
}
if (!PK11_IsFriendly(slot)) {
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) {
PK11_FreeSlot(slot);
*slotptr = NULL;
return CK_INVALID_KEY;
}
}
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;
}
CERTCertificate *
PK11_FindCertFromNickname(char *nickname, void *wincx) {
PK11SlotInfo *slot;
int count=0;
CK_OBJECT_HANDLE *certID = PK11_FindObjectsFromNickname(nickname,&slot,
CKO_CERTIFICATE, &count, wincx);
CERTCertificate *cert;
if (certID == CK_INVALID_KEY) return NULL;
cert = PK11_MakeCertFromHandle(slot,certID[0],NULL);
PK11_FreeSlot(slot);
PORT_Free(certID);
return cert;
}
CERTCertList *
PK11_FindCertsFromNickname(char *nickname, void *wincx) {
PK11SlotInfo *slot;
int i,count = 0;
CK_OBJECT_HANDLE *certID = PK11_FindObjectsFromNickname(nickname,&slot,
CKO_CERTIFICATE, &count, wincx);
CERTCertList *certList = NULL;
if (certID == NULL) return NULL;
certList= CERT_NewCertList();
for (i=0; i < count; i++) {
CERTCertificate *cert = PK11_MakeCertFromHandle(slot,certID[i],NULL);
if (cert) CERT_AddCertToListTail(certList,cert);
}
if (CERT_LIST_HEAD(certList) == NULL) {
CERT_DestroyCertList(certList);
certList = NULL;
}
PK11_FreeSlot(slot);
PORT_Free(certID);
return certList;
}
/*
* extract a key ID for a certificate...
* NOTE: We call this function from PKCS11.c If we ever use
* pkcs11 to extract the public key (we currently do not), this will break.
*/
SECItem *
PK11_GetPubIndexKeyID(CERTCertificate *cert) {
SECKEYPublicKey *pubk;
SECItem *newItem = NULL;
pubk = CERT_ExtractPublicKey(cert);
if (pubk == NULL) return NULL;
switch (pubk->keyType) {
case rsaKey:
newItem = SECITEM_DupItem(&pubk->u.rsa.modulus);
break;
case dsaKey:
newItem = SECITEM_DupItem(&pubk->u.dsa.publicValue);
break;
case dhKey:
newItem = SECITEM_DupItem(&pubk->u.dh.publicValue);
case fortezzaKey:
default:
newItem = NULL; /* Fortezza Fix later... */
}
SECKEY_DestroyPublicKey(pubk);
/* make hash of it */
return newItem;
}
/*
* generate a CKA_ID from a certificate.
*/
SECItem *
pk11_mkcertKeyID(CERTCertificate *cert) {
SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert) ;
SECItem *certCKA_ID;
if (pubKeyData == NULL) return NULL;
certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
SECITEM_FreeItem(pubKeyData,PR_TRUE);
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;
}
/*
* Write the cert into the token.
*/
SECStatus
PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert,
CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust) {
int len = 0;
SECItem *keyID = pk11_mkcertKeyID(cert);
CK_ATTRIBUTE keyAttrs[] = {
{ CKA_LABEL, NULL, 0},
{ CKA_SUBJECT, NULL, 0},
};
CK_OBJECT_CLASS certc = CKO_CERTIFICATE;
CK_CERTIFICATE_TYPE certType = CKC_X_509;
CK_OBJECT_HANDLE certID;
CK_SESSION_HANDLE rwsession;
CK_BBOOL cktrue = CK_TRUE;
SECStatus rv = SECFailure;
CK_ATTRIBUTE certAttrs[] = {
{ CKA_ID, NULL, 0 },
{ CKA_LABEL, NULL, 0},
{ CKA_CLASS, NULL, 0},
{ CKA_TOKEN, NULL, 0},
{ CKA_CERTIFICATE_TYPE, NULL, 0},
{ CKA_SUBJECT, NULL, 0},
{ CKA_ISSUER, NULL, 0},
{ CKA_SERIAL_NUMBER, NULL, 0},
{ CKA_VALUE, NULL, 0},
{ CKA_NETSCAPE_TRUST, NULL, 0},
};
int certCount = sizeof(certAttrs)/sizeof(certAttrs[0]), keyCount = 2;
CK_ATTRIBUTE *attrs;
CK_RV crv;
SECCertUsage *certUsage = NULL;
if (keyID == NULL) {
PORT_SetError(SEC_ERROR_ADDING_CERT);
return rv;
}
len = ((nickname) ? PORT_Strlen(nickname) : 0);
attrs = certAttrs;
PK11_SETATTRS(attrs,CKA_ID, keyID->data, keyID->len); attrs++;
if(nickname) {
PK11_SETATTRS(attrs,CKA_LABEL, nickname, len ); attrs++;
}
PK11_SETATTRS(attrs,CKA_CLASS, &certc, sizeof(certc) ); attrs++;
PK11_SETATTRS(attrs,CKA_TOKEN, &cktrue, sizeof(cktrue) ); attrs++;
PK11_SETATTRS(attrs,CKA_CERTIFICATE_TYPE, &certType,
sizeof(certType)); attrs++;
PK11_SETATTRS(attrs,CKA_SUBJECT, cert->derSubject.data,
cert->derSubject.len ); attrs++;
PK11_SETATTRS(attrs,CKA_ISSUER, cert->derIssuer.data,
cert->derIssuer.len ); attrs++;
PK11_SETATTRS(attrs,CKA_SERIAL_NUMBER, cert->serialNumber.data,
cert->serialNumber.len); attrs++;
PK11_SETATTRS(attrs,CKA_VALUE, cert->derCert.data, cert->derCert.len);
if(includeTrust && PK11_IsInternal(slot)) {
attrs++;
certUsage = (SECCertUsage*)PORT_Alloc(sizeof(SECCertUsage));
if(!certUsage) {
SECITEM_FreeItem(keyID,PR_TRUE);
PORT_SetError(SEC_ERROR_NO_MEMORY);
return rv;
}
*certUsage = certUsageUserCertImport;
PK11_SETATTRS(attrs,CKA_NETSCAPE_TRUST, certUsage, sizeof(SECCertUsage));
} else {
certCount--;
}
attrs = keyAttrs;
if(nickname) {
PK11_SETATTRS(attrs,CKA_LABEL, nickname, len ); attrs++;
}
PK11_SETATTRS(attrs,CKA_SUBJECT, cert->derSubject.data,
cert->derSubject.len );
if(!nickname) {
certCount--;
keyCount--;
}
rwsession = PK11_GetRWSession(slot);
crv = PK11_GETTAB(slot)->C_SetAttributeValue(rwsession,key,keyAttrs,
keyCount);
if (crv != CKR_OK) {
PORT_SetError( PK11_MapError(crv) );
goto done;
}
crv = PK11_GETTAB(slot)->
C_CreateObject(rwsession,certAttrs,certCount,&certID);
if (crv == CKR_OK) {
rv = SECSuccess;
} else {
PORT_SetError( PK11_MapError(crv) );
}
done:
SECITEM_FreeItem(keyID,PR_TRUE);
PK11_RestoreROSession(slot,rwsession);
if(certUsage) {
PORT_Free(certUsage);
}
return rv;
}
/*
* get a certificate handle, look at the cached handle first..
*/
CK_OBJECT_HANDLE
pk11_getcerthandle(PK11SlotInfo *slot, CERTCertificate *cert,
CK_ATTRIBUTE *theTemplate,int tsize)
{
CK_OBJECT_HANDLE certh;
if (cert->slot == slot) {
certh = cert->pkcs11ID;
if (certh == CK_INVALID_KEY) {
certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
cert->pkcs11ID = certh;
}
} else {
certh = pk11_FindObjectByTemplate(slot,theTemplate,tsize);
}
return certh;
}
/*
* return the private key From a given Cert
*/
SECKEYPrivateKey *
PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx) {
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_VALUE, 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_OBJECT_HANDLE certh;
CK_OBJECT_HANDLE keyh;
CK_ATTRIBUTE *attrs = theTemplate;
SECStatus rv;
PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
cert->derCert.len); attrs++;
PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
/*
* issue the find
*/
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) {
return NULL;
}
certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
if (certh == CK_INVALID_KEY) {
return NULL;
}
keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
if (keyh == CK_INVALID_KEY) { return NULL; }
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.
*/
PK11SlotInfo *
PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr,
void *wincx) {
PK11SlotList *list;
PK11SlotListElement *le;
SECItem *keyID;
CK_OBJECT_HANDLE key;
PK11SlotInfo *slot = NULL;
SECStatus rv;
keyID = pk11_mkcertKeyID(cert);
/* get them all! */
list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
if ((keyID == NULL) || (list == NULL)) {
if (keyID) SECITEM_FreeItem(keyID,PR_TRUE);
if (list) PK11_FreeSlotList(list);
return NULL;
}
/* Look for the slot that holds the Key */
for (le = list->head ; le; le = le->next) {
rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
if (rv != SECSuccess) continue;
key = pk11_FindPrivateKeyFromCertID(le->slot,keyID);
if (key != CK_INVALID_KEY) {
slot = PK11_ReferenceSlot(le->slot);
if (keyPtr) *keyPtr = key;
break;
}
}
SECITEM_FreeItem(keyID,PR_TRUE);
PK11_FreeSlotList(list);
return slot;
}
PK11SlotInfo *
PK11_ImportCertForKey(CERTCertificate *cert, char *nickname,void *wincx) {
PK11SlotInfo *slot = NULL;
CK_OBJECT_HANDLE key;
slot = PK11_KeyForCertExists(cert,&key,wincx);
if (slot) {
if (PK11_ImportCert(slot,cert,key,nickname,PR_FALSE) != SECSuccess) {
PK11_FreeSlot(slot);
slot = NULL;
}
} else {
PORT_SetError(SEC_ERROR_ADDING_CERT);
}
return slot;
}
static CK_OBJECT_HANDLE
pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr,
CK_ATTRIBUTE *searchTemplate, int count, void *wincx) {
PK11SlotList *list;
PK11SlotListElement *le;
CK_OBJECT_HANDLE certHandle = CK_INVALID_KEY;
PK11SlotInfo *slot = NULL;
SECStatus rv;
*slotPtr = NULL;
/* get them all! */
list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
if (list == NULL) {
if (list) PK11_FreeSlotList(list);
return CK_INVALID_KEY;
}
/* Look for the slot that holds the Key */
for (le = list->head ; le; le = le->next) {
if (!PK11_IsFriendly(le->slot)) {
rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
if (rv != SECSuccess) continue;
}
certHandle = pk11_FindObjectByTemplate(le->slot,searchTemplate,count);
if (certHandle != CK_INVALID_KEY) {
slot = PK11_ReferenceSlot(le->slot);
break;
}
}
PK11_FreeSlotList(list);
if (slot == NULL) {
return CK_INVALID_KEY;
}
*slotPtr = slot;
return certHandle;
}
/*
* We're looking for a cert which we have the private key for that's on the
* list of recipients. This searches one slot.
*/
static CK_OBJECT_HANDLE
pk11_FindCertObjectByRecipient(PK11SlotInfo *slot,
SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip)
{
CK_OBJECT_HANDLE certHandle;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_OBJECT_CLASS peerClass ;
CK_ATTRIBUTE searchTemplate[] = {
{ CKA_CLASS, NULL, 0 },
{ CKA_ISSUER, NULL, 0 },
{ CKA_SERIAL_NUMBER, NULL, 0}
};
int count = sizeof(searchTemplate)/sizeof(CK_ATTRIBUTE);
SEC_PKCS7RecipientInfo *ri = NULL;
CK_ATTRIBUTE *attrs;
int i;
peerClass = CKO_PRIVATE_KEY;
if (!PK11_IsLoggedIn(slot,NULL) && PK11_NeedLogin(slot)) {
peerClass = CKO_PUBLIC_KEY;
}
for (i=0; (ri = recipientArray[i]) != NULL; i++) {
attrs = searchTemplate;
PK11_SETATTRS(attrs, CKA_CLASS, &certClass,sizeof(certClass)); attrs++;
PK11_SETATTRS(attrs, CKA_ISSUER, ri->issuerAndSN->derIssuer.data,
ri->issuerAndSN->derIssuer.len); attrs++;
PK11_SETATTRS(attrs, CKA_SERIAL_NUMBER,
ri->issuerAndSN->serialNumber.data,ri->issuerAndSN->serialNumber.len);
certHandle = pk11_FindObjectByTemplate(slot,searchTemplate,count);
if (certHandle != CK_INVALID_KEY) {
CERTCertificate *cert = pk11_fastCert(slot,certHandle,NULL,NULL);
if (PK11_IsUserCert(slot,cert,certHandle)) {
/* we've found a cert handle, now let's see if there is a key
* associated with it... */
*rip = ri;
CERT_DestroyCertificate(cert);
return certHandle;
}
CERT_DestroyCertificate(cert);
}
}
*rip = NULL;
return CK_INVALID_KEY;
}
/*
* This function is the same as above, but it searches all the slots.
*/
static CK_OBJECT_HANDLE
pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr,
SEC_PKCS7RecipientInfo **recipientArray,SEC_PKCS7RecipientInfo **rip,
void *wincx) {
PK11SlotList *list;
PK11SlotListElement *le;
CK_OBJECT_HANDLE certHandle = CK_INVALID_KEY;
PK11SlotInfo *slot = NULL;
SECStatus rv;
*slotPtr = NULL;
/* get them all! */
list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_TRUE,wincx);
if (list == NULL) {
if (list) PK11_FreeSlotList(list);
return CK_INVALID_KEY;
}
*rip = NULL;
/* Look for the slot that holds the Key */
for (le = list->head ; le; le = le->next) {
if ( !PK11_IsFriendly(le->slot)) {
rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
if (rv != SECSuccess) continue;
}
certHandle = pk11_FindCertObjectByRecipient(le->slot,
recipientArray,rip);
if (certHandle != CK_INVALID_KEY) {
slot = PK11_ReferenceSlot(le->slot);
break;
}
}
PK11_FreeSlotList(list);
if (slot == NULL) {
return CK_INVALID_KEY;
}
*slotPtr = slot;
return certHandle;
}
/*
* We need to invert the search logic for PKCS 7 because if we search for
* each cert on the list over all the slots, we wind up with lots of spurious
* password prompts. This way we get only one password prompt per slot, at
* the max, and most of the time we can find the cert, and only prompt for
* the key...
*/
CERTCertificate *
PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr,
SEC_PKCS7RecipientInfo **array, SEC_PKCS7RecipientInfo **rip,
SECKEYPrivateKey**privKey, void *wincx)
{
CK_OBJECT_HANDLE certHandle = CK_INVALID_KEY;
CK_OBJECT_HANDLE keyHandle = CK_INVALID_KEY;
PK11SlotInfo *slot = NULL;
CERTCertificate *cert = NULL;
SECStatus rv;
*privKey = NULL;
certHandle = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx);
if (certHandle == CK_INVALID_KEY) {
return NULL;
}
rv = PK11_Authenticate(*slotPtr,PR_TRUE,wincx);
if (rv != SECSuccess) {
PK11_FreeSlot(*slotPtr);
*slotPtr = NULL;
return NULL;
}
keyHandle = PK11_MatchItem(*slotPtr,certHandle,CKO_PRIVATE_KEY);
if (keyHandle == CK_INVALID_KEY) {
PK11_FreeSlot(*slotPtr);
*slotPtr = NULL;
return NULL;
}
*privKey = PK11_MakePrivKey(*slotPtr, nullKey, PR_TRUE, keyHandle, wincx);
if (*privKey == NULL) {
PK11_FreeSlot(*slotPtr);
*slotPtr = NULL;
return NULL;
}
cert = PK11_MakeCertFromHandle(*slotPtr,certHandle,NULL);
if (cert == NULL) {
PK11_FreeSlot(*slotPtr);
SECKEY_DestroyPrivateKey(*privKey);
*slotPtr = NULL;
*privKey = NULL;
return NULL;
}
return cert;
}
CERTCertificate *
PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
void *wincx)
{
CK_OBJECT_HANDLE certHandle;
CERTCertificate *cert = NULL;
CK_ATTRIBUTE searchTemplate[] = {
{ CKA_ISSUER, NULL, 0 },
{ CKA_SERIAL_NUMBER, NULL, 0}
};
int count = sizeof(searchTemplate)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE *attrs = searchTemplate;
PK11_SETATTRS(attrs, CKA_ISSUER, issuerSN->derIssuer.data,
issuerSN->derIssuer.len); attrs++;
PK11_SETATTRS(attrs, CKA_SERIAL_NUMBER, issuerSN->serialNumber.data,
issuerSN->serialNumber.len);
certHandle = pk11_FindCertObjectByTemplate
(slotPtr,searchTemplate,count,wincx);
if (certHandle == CK_INVALID_KEY) {
return NULL;
}
cert = PK11_MakeCertFromHandle(*slotPtr,certHandle,NULL);
if (cert == NULL) {
PK11_FreeSlot(*slotPtr);
return NULL;
}
return cert;
}
CK_OBJECT_HANDLE
PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
{
CK_OBJECT_HANDLE certHandle;
CK_ATTRIBUTE searchTemplate = { CKA_VALUE, NULL, 0 };
PK11_SETATTRS(&searchTemplate, CKA_VALUE, cert->derCert.data,
cert->derCert.len);
if (cert->slot) {
certHandle = pk11_getcerthandle(cert->slot,cert,&searchTemplate,1);
if (certHandle != CK_INVALID_KEY) {
*pSlot = PK11_ReferenceSlot(cert->slot);
return certHandle;
}
}
certHandle = pk11_FindCertObjectByTemplate(pSlot,&searchTemplate,1,wincx);
if (certHandle != CK_INVALID_KEY) {
if (cert->slot == NULL) {
cert->slot = PK11_ReferenceSlot(*pSlot);
cert->pkcs11ID = certHandle;
cert->ownSlot = PR_FALSE;
}
}
return(certHandle);
}
SECKEYPrivateKey *
PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
{
CK_OBJECT_HANDLE certHandle;
CK_OBJECT_HANDLE keyHandle;
PK11SlotInfo *slot = NULL;
SECKEYPrivateKey *privKey;
SECStatus rv;
certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
if (certHandle == CK_INVALID_KEY) {
return NULL;
}
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) {
PK11_FreeSlot(slot);
return NULL;
}
keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY);
if (keyHandle == CK_INVALID_KEY) {
PK11_FreeSlot(slot);
return NULL;
}
privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
PK11_FreeSlot(slot);
return privKey;
}
CK_OBJECT_HANDLE
pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
{
CK_OBJECT_HANDLE certHandle;
CK_OBJECT_HANDLE keyHandle;
certHandle = PK11_FindObjectForCert(cert, wincx, slot);
if (certHandle == CK_INVALID_KEY) {
return CK_INVALID_KEY;
}
keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY);
if (keyHandle == CK_INVALID_KEY) {
PK11_FreeSlot(*slot);
return CK_INVALID_KEY;
}
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_KEY) {
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
*/
int
PK11_NumberCertsForCertSubject(CERTCertificate *cert)
{
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_CLASS, NULL, 0 },
{ CKA_SUBJECT, NULL, 0 },
};
CK_ATTRIBUTE *attr = theTemplate;
int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len);
if ((cert->slot == NULL) || (cert->slot->isInternal)) {
return 0;
}
return PK11_NumberObjectsFor(cert->slot,theTemplate,templateSize);
}
/*
* Walk all the certs with the same subject
*/
SECStatus
PK11_TraverseCertsForSubject(CERTCertificate *cert,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
if(!cert) {
return SECFailure;
}
return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
}
SECStatus
PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
pk11DoCertCallback caller;
pk11TraverseSlotCert callarg;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_CLASS, NULL, 0 },
{ CKA_SUBJECT, NULL, 0 },
};
CK_ATTRIBUTE *attr = theTemplate;
int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
PK11_SETATTRS(attr,CKA_SUBJECT,cert->derSubject.data,cert->derSubject.len);
if ((slot == NULL) || (slot->isInternal)) {
return SECSuccess;
}
caller.noslotcallback = callback;
caller.callback = NULL;
caller.callbackArg = arg;
callarg.callback = pk11_DoCerts;
callarg.callbackArg = (void *) & caller;
callarg.findTemplate = theTemplate;
callarg.templateCount = templateSize;
return PK11_TraverseSlot(slot, &callarg);
}
SECStatus
PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
pk11DoCertCallback caller;
pk11TraverseSlotCert callarg;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_CLASS, NULL, 0 },
{ CKA_LABEL, NULL, 0 },
};
CK_ATTRIBUTE *attr = theTemplate;
int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
if(!nickname) {
return SECSuccess;
}
PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
PK11_SETATTRS(attr,CKA_LABEL,nickname->data,nickname->len);
if ((slot == NULL) || (slot->isInternal)) {
return SECSuccess;
}
caller.noslotcallback = callback;
caller.callback = NULL;
caller.callbackArg = arg;
callarg.callback = pk11_DoCerts;
callarg.callbackArg = (void *) & caller;
callarg.findTemplate = theTemplate;
callarg.templateCount = templateSize;
return PK11_TraverseSlot(slot, &callarg);
}
SECStatus
PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
pk11DoCertCallback caller;
pk11TraverseSlotCert callarg;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_CLASS, NULL, 0 },
};
CK_ATTRIBUTE *attr = theTemplate;
int templateSize = sizeof(theTemplate)/sizeof(theTemplate[0]);
PK11_SETATTRS(attr,CKA_CLASS, &certClass, sizeof(certClass)); attr++;
if (slot == NULL) {
return SECSuccess;
}
caller.noslotcallback = callback;
caller.callback = NULL;
caller.callbackArg = arg;
callarg.callback = pk11_DoCerts;
callarg.callbackArg = (void *) & caller;
callarg.findTemplate = theTemplate;
callarg.templateCount = templateSize;
return PK11_TraverseSlot(slot, &callarg);
}
/*
* return the certificate associated with a derCert
*/
CERTCertificate *
PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx)
{
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_VALUE, 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_OBJECT_HANDLE certh;
CK_ATTRIBUTE *attrs = theTemplate;
SECStatus rv;
PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
cert->derCert.len); attrs++;
PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
/*
* issue the find
*/
if ( !PK11_IsFriendly(slot)) {
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) return NULL;
}
certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
if (certh == CK_INVALID_KEY) {
return NULL;
}
return PK11_MakeCertFromHandle(slot, certh, NULL);
}
/*
* return the certificate associated with a derCert
*/
CERTCertificate *
PK11_FindCertFromDERSubjectAndNickname(PK11SlotInfo *slot,
CERTCertificate *cert,
char *nickname, void *wincx)
{
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_SUBJECT, NULL, 0 },
{ CKA_LABEL, 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_OBJECT_HANDLE certh;
CK_ATTRIBUTE *attrs = theTemplate;
SECStatus rv;
PK11_SETATTRS(attrs, CKA_SUBJECT, cert->derSubject.data,
cert->derSubject.len); attrs++;
PK11_SETATTRS(attrs, CKA_LABEL, nickname, PORT_Strlen(nickname));
PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
/*
* issue the find
*/
if ( !PK11_IsFriendly(slot)) {
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) return NULL;
}
certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
if (certh == CK_INVALID_KEY) {
return NULL;
}
return PK11_MakeCertFromHandle(slot, certh, NULL);
}
/*
* import a cert for a private key we have already generated. Set the label
* on both to be the nickname.
*/
static CK_OBJECT_HANDLE
pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx)
{
SECItem *keyID;
CK_OBJECT_HANDLE key;
SECStatus rv;
if((slot == NULL) || (cert == NULL)) {
return CK_INVALID_KEY;
}
keyID = pk11_mkcertKeyID(cert);
if(keyID == NULL) {
return CK_INVALID_KEY;
}
key = CK_INVALID_KEY;
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) goto loser;
key = pk11_FindPrivateKeyFromCertID(slot, keyID);
loser:
SECITEM_ZfreeItem(keyID, PR_TRUE);
return key;
}
SECKEYPrivateKey *
PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx)
{
CK_OBJECT_HANDLE keyHandle;
if((slot == NULL) || (cert == NULL)) {
return NULL;
}
keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
if (keyHandle == CK_INVALID_KEY) {
return NULL;
}
return PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,wincx);
}
SECStatus
PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert,
char *nickname,
PRBool addCertUsage,void *wincx)
{
CK_OBJECT_HANDLE keyHandle;
if((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
return SECFailure;
}
keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
if (keyHandle == CK_INVALID_KEY) {
return SECFailure;
}
return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
}
/* remove when the real version comes out */
#define SEC_OID_MISSI_KEA 300 /* until we have v3 stuff merged */
PRBool
KEAPQGCompare(CERTCertificate *server,CERTCertificate *cert) {
if ( SECKEY_KEAParamCompare(server,cert) == SECEqual ) {
return PR_TRUE;
} else {
return PR_FALSE;
}
}
PRBool
PK11_FortezzaHasKEA(CERTCertificate *cert) {
/* look at the subject and see if it is a KEA for MISSI key */
SECOidData *oid;
if ((cert->trust == NULL) ||
((cert->trust->sslFlags & CERTDB_USER) != CERTDB_USER)) {
return PR_FALSE;
}
oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) ||
(oid->offset == SEC_OID_MISSI_KEA_DSS) ||
(oid->offset == SEC_OID_MISSI_KEA)) ;
}
/*
* Find a kea cert on this slot that matches the domain of it's peer
*/
static CERTCertificate
*pk11_GetKEAMate(PK11SlotInfo *slot,CERTCertificate *peer)
{
int i;
CERTCertificate *returnedCert = NULL;
for (i=0; i < slot->cert_count; i++) {
CERTCertificate *cert = slot->cert_array[i];
if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer,cert)) {
returnedCert = CERT_DupCertificate(cert);
break;
}
}
return returnedCert;
}
/*
* The following is a FORTEZZA only Certificate request. We call this when we
* are doing a non-client auth SSL connection. We are only interested in the
* fortezza slots, and we are only interested in certs that share the same root
* key as the server.
*/
CERTCertificate *
PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
{
PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
PR_FALSE,PR_TRUE,wincx);
PK11SlotListElement *le;
CERTCertificate *returnedCert = NULL;
SECStatus rv;
/* loop through all the fortezza tokens */
for (le = keaList->head; le; le = le->next) {
rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
if (rv != SECSuccess) continue;
if (le->slot->session == CK_INVALID_SESSION) {
continue;
}
returnedCert = pk11_GetKEAMate(le->slot,server);
if (returnedCert) break;
}
PK11_FreeSlotList(keaList);
return returnedCert;
}
/*
* find a matched pair of kea certs to key exchange parameters from one
* fortezza card to another as necessary.
*/
SECStatus
PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
CERTCertificate **cert1, CERTCertificate **cert2)
{
PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
PR_FALSE,PR_TRUE,NULL);
CERTCertificate *returnedCert = NULL;
int i;
for (i=0; i < slot1->cert_count; i++) {
CERTCertificate *cert = slot1->cert_array[i];
if (PK11_FortezzaHasKEA(cert)) {
returnedCert = pk11_GetKEAMate(slot2,cert);
if (returnedCert != NULL) {
*cert2 = returnedCert;
*cert1 = CERT_DupCertificate(cert);
return SECSuccess;
}
}
}
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
*/
CK_OBJECT_HANDLE
PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
{
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_VALUE, 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;
SECStatus rv;
PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
cert->derCert.len); attrs++;
PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
/*
* issue the find
*/
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) {
return CK_INVALID_KEY;
}
return pk11_getcerthandle(slot,cert,theTemplate,tsize);
}
SECItem *
PK11_GetKeyIDFromCert(CERTCertificate *cert, void *wincx)
{
CK_OBJECT_HANDLE handle;
PK11SlotInfo *slot = NULL;
CK_ATTRIBUTE theTemplate[] = {
{ CKA_ID, NULL, 0 },
};
int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
SECItem *item = NULL;
CK_RV crv;
handle = PK11_FindObjectForCert(cert,wincx,&slot);
if (handle == CK_INVALID_KEY) {
goto loser;
}
crv = PK11_GetAttributes(NULL,slot,handle,theTemplate,tsize);
if (crv != CKR_OK) {
PORT_SetError( PK11_MapError(crv) );
goto loser;
}
item = PORT_ZNew(SECItem);
if (item) {
item->data = theTemplate[0].pValue;
item->len = theTemplate[0].ulValueLen;
}
loser:
PK11_FreeSlot(slot);
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 = theTemplate[0].pValue;
item->len = theTemplate[0].ulValueLen;
}
loser:
return item;
}