gecko-dev/security/nss/lib/pk11wrap/pk11cert.c
relyea%netscape.com ce09346d8c Token and cert processing fixes:
1) use NewTempCert rather than DERDecode cert in all import cert cases.
When DERDecode cert is used, we may wind up with a cert that gets cleared
when we try to import it because it already in the cache. NewTempCert will
return the version that is in the cache.
   2) If we are returning the CAList, only return certs that are CA's
(not usercerts).
   3) Authenticate to all the tokens if necessary before we try to list
certs. (Stan code should eventually get automatic authentication calls in
the code itself).
   4) When looking up user certs, don't return those certs with the same
subject, but do not have any key material associated with them (that is
don't crash if we have old certs in our database without nicknames, but
match user certs on our smart cards).
   5) Save the nickname associated with our subject list in the temp
cache so we can correctly remove the entry even if the cert's nickname
changes (because of smart card insertions and removals, or because of
creation and deletions of our user cert).
2002-04-22 19:09:01 +00:00

3987 lines
109 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 "nssilock.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 "cmsreclist.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 "dev.h"
#include "nsspki.h"
#include "pki.h"
#include "pkim.h"
#include "pkitm.h"
#define PK11_SEARCH_CHUNKSIZE 10
CK_OBJECT_HANDLE
pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx);
struct nss3_cert_cbstr {
SECStatus(* callback)(CERTCertificate*, void *);
nssList *cached;
void *arg;
};
/* Translate from NSSCertificate to CERTCertificate, then pass the latter
* to a callback.
*/
static PRStatus convert_cert(NSSCertificate *c, void *arg)
{
CERTCertificate *nss3cert;
SECStatus secrv;
struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
nss3cert = STAN_GetCERTCertificate(c);
if (!nss3cert) return PR_FAILURE;
secrv = (*nss3cb->callback)(nss3cert, nss3cb->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.
*/
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 (cert_label && (cert_label->ulValueLen)) {
suffixLen = cert_label->ulValueLen;
suffix = (char*)cert_label->pValue;
} else if (key_label && (key_label->ulValueLen)) {
suffixLen = key_label->ulValueLen;
suffix = (char*)key_label->pValue;
} else if (cert_id && cert_id->ulValueLen > 0) {
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;
}
/* if is internal key slot, add code to skip the prefix!! */
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_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;
}
/*
* 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_HANDLE) {
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;
case keaKey:
case fortezzaKey:
case nullKey:
/* fall through and return false */
break;
}
if (theTemplate.ulValueLen == 0) {
SECKEY_DestroyPublicKey(pubKey);
return PR_FALSE;
}
pk11_SignedToUnsigned(&theTemplate);
if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_HANDLE) {
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_DecodeDERCertificate(&derCert, PR_TRUE, nickname);
if (cert) {
cert->dbhandle = (CERTCertDBHandle *)
nssToken_GetTrustDomain(slot->nssToken);
}
if (nickptr) {
*nickptr = nickname;
} else {
if (nickname) PORT_Free(nickname);
}
PORT_FreeArena(arena,PR_FALSE);
return cert;
}
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.
*/
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;
}
trust = (CERTCertTrust*)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
if (trust == NULL) goto loser;
PORT_Memset(trust,0, sizeof(CERTCertTrust));
cert->trust = trust;
if(! pk11_HandleTrustObject(slot, cert, trust) ) {
unsigned int type;
/* 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;
}
}
}
if (PK11_IsUserCert(slot,cert,certID)) {
trust->sslFlags |= CERTDB_USER;
trust->emailFlags |= CERTDB_USER;
/* trust->objectSigningFlags |= CERTDB_USER; */
}
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 handle = privKey->pkcs11ID;
CK_OBJECT_HANDLE certID =
PK11_MatchItem(slot,handle,CKO_CERTIFICATE);
CERTCertificate *cert;
if (certID == CK_INVALID_HANDLE) {
PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
return NULL;
}
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, 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.
*/
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) {
#ifdef NSS_CLASSIC
PK11_DestroyTokenObject(cert->slot,cert->pkcs11ID);
#else
/* For 3.4, utilize the generic cert delete function */
SEC_DeletePermCertificate(cert);
#endif
PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
}
if ((pubKey != CK_INVALID_HANDLE) && (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 *);
SECStatus(* itemcallback)(CERTCertificate*, SECItem *, void *);
void *callbackArg;
} pk11DoCertCallback;
/*
* callback to map object handles to certificate structures.
*/
static 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);
}
if (certcb->itemcallback) {
(*certcb->itemcallback)(cert, NULL, certcb->callbackArg);
}
}
CERT_DestroyCertificate(cert);
return SECSuccess;
}
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]);
SECStatus rv;
rv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize);
if (rv == SECFailure) {
goto loser;
}
rv = SECFailure;
new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode));
if (new_node == NULL) {
goto loser;
}
new_node->type = *((CK_BBOOL *)fetchCrl[1].pValue) ?
SEC_KRL_TYPE : SEC_CRL_TYPE;
derCrl.data = (unsigned char *)fetchCrl[0].pValue;
derCrl.len = fetchCrl[0].ulValueLen;
new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type);
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;
/*
* Extract all the certs on a card from a slot.
*/
static 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) {
if (!PK11_IsFriendly(le->slot)) {
rv = PK11_Authenticate(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 *);
void *arg;
};
static SECStatus fake_der_cb(CERTCertificate *c, void *a)
{
struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
return (*fda->callback)(c, &c->derCert, fda->arg);
}
/*
* Extract all the certs on a card from a slot.
*/
SECStatus
PK11_TraverseSlotCerts(SECStatus(* callback)(CERTCertificate*,SECItem *,void *),
void *arg, void *wincx) {
#ifdef NSS_CLASSIC
pk11DoCertCallback caller;
pk11TraverseSlot creater;
CK_ATTRIBUTE theTemplate;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
PK11_SETATTRS(&theTemplate, CKA_CLASS, &certClass, sizeof(certClass));
caller.callback = NULL;
caller.noslotcallback = NULL;
caller.itemcallback = callback;
caller.callbackArg = arg;
creater.callback = pk11_DoCerts;
creater.callbackArg = (void *) & caller;
creater.findTemplate = &theTemplate;
creater.templateCount = 1;
return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, wincx);
#else
NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
struct fake_der_cb_argstr fda;
struct nss3_cert_cbstr pk11cb;
fda.callback = callback;
fda.arg = arg;
pk11cb.callback = fake_der_cb;
pk11cb.arg = &fda;
NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
return SECSuccess;
#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;
}
if (!PK11_IsFriendly(slot)) {
rv = PK11_Authenticate(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)
{
NSSCertificate **certs;
PRUint32 i, count;
NSSToken **tokens, **tp;
count = nssList_Count(certList);
if (count == 0) {
return;
}
certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
if (!certs) {
return;
}
nssList_GetArray(certList, (void **)certs, count);
for (i=0; i<count; i++) {
tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
if (tokens) {
for (tp = tokens; *tp; tp++) {
if (*tp == token) {
nssPKIObjectCollection_AddObject(collection,
(nssPKIObject *)certs[i]);
}
}
nssTokenArray_Destroy(tokens);
}
CERT_DestroyCertificate(STAN_GetCERTCertificate(certs[i]));
}
nss_ZFreeIf(certs);
}
CERTCertificate *
PK11_FindCertFromNickname(char *nickname, void *wincx) {
#ifdef NSS_CLASSIC
PK11SlotInfo *slot;
int count=0;
CK_OBJECT_HANDLE *certID = PK11_FindObjectsFromNickname(nickname,&slot,
CKO_CERTIFICATE, &count, wincx);
CERTCertificate *cert;
if (certID == CK_INVALID_HANDLE) return NULL;
cert = PK11_MakeCertFromHandle(slot,certID[0],NULL);
PK11_FreeSlot(slot);
PORT_Free(certID);
return cert;
#else
PRStatus status;
CERTCertificate *rvCert = NULL;
NSSCertificate *cert = NULL;
NSSCertificate **certs = NULL;
NSSUsage usage;
NSSToken *token;
PK11SlotInfo *slot = NULL;
char *nickCopy;
char *delimit = NULL;
char *tokenName;
NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
usage.anyUsage = PR_TRUE;
nickCopy = PORT_Strdup(nickname);
if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
tokenName = nickCopy;
nickname = delimit + 1;
*delimit = '\0';
/* find token by name */
token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
if (token) {
slot = PK11_ReferenceSlot(token->pk11slot);
}
*delimit = ':';
} else {
slot = PK11_GetInternalKeySlot();
token = PK11Slot_GetNSSToken(slot);
}
if (token) {
nssList *certList;
nssCryptokiObject **instances;
nssPKIObjectCollection *collection;
nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
if (!PK11_IsPresent(slot)) {
goto loser;
}
if (!PK11_IsFriendly(slot)) {
if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) {
goto loser;
}
}
collection = nssCertificateCollection_Create(defaultTD, NULL);
if (!collection) {
goto loser;
}
certList = nssList_Create(NULL, PR_FALSE);
if (!certList) {
nssPKIObjectCollection_Destroy(collection);
goto loser;
}
(void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
nickname,
certList);
transfer_token_certs_to_collection(certList, token, collection);
instances = nssToken_FindCertificatesByNickname(token,
NULL,
nickname,
tokenOnly,
0,
&status);
nssPKIObjectCollection_AddInstances(collection, instances, 0);
nss_ZFreeIf(instances);
/* if it wasn't found, repeat the process for email address */
if (nssPKIObjectCollection_Count(collection) == 0 &&
PORT_Strchr(nickname, '@') != NULL)
{
(void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD,
nickname,
certList);
transfer_token_certs_to_collection(certList, token, collection);
instances = nssToken_FindCertificatesByEmail(token,
NULL,
nickname,
tokenOnly,
0,
&status);
nssPKIObjectCollection_AddInstances(collection, instances, 0);
nss_ZFreeIf(instances);
}
certs = nssPKIObjectCollection_GetCertificates(collection,
NULL, 0, NULL);
nssPKIObjectCollection_Destroy(collection);
if (certs) {
cert = nssCertificateArray_FindBestCertificate(certs, NULL,
&usage, NULL);
rvCert = STAN_GetCERTCertificate(cert);
nssCertificateArray_Destroy(certs);
}
nssList_Destroy(certList);
}
if (slot) {
PK11_FreeSlot(slot);
}
if (nickCopy) PORT_Free(nickCopy);
return rvCert;
loser:
if (slot) {
PK11_FreeSlot(slot);
}
if (nickCopy) PORT_Free(nickCopy);
return NULL;
#endif
}
CERTCertList *
PK11_FindCertsFromNickname(char *nickname, void *wincx) {
#ifdef NSS_CLASSIC
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;
#else
char *nickCopy;
char *delimit = NULL;
char *tokenName;
int i;
CERTCertList *certList = NULL;
nssPKIObjectCollection *collection = NULL;
NSSCertificate **foundCerts = NULL;
NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
NSSCertificate *c;
NSSToken *token;
PK11SlotInfo *slot;
nickCopy = PORT_Strdup(nickname);
if ((delimit = PORT_Strchr(nickCopy,':')) != NULL) {
tokenName = nickCopy;
nickname = delimit + 1;
*delimit = '\0';
/* find token by name */
token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
if (token) {
slot = PK11_ReferenceSlot(token->pk11slot);
} else {
slot = NULL;
}
*delimit = ':';
} else {
slot = PK11_GetInternalKeySlot();
token = PK11Slot_GetNSSToken(slot);
}
if (token) {
PRStatus status;
nssList *nameList;
nssCryptokiObject **instances;
nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
if (!PK11_IsFriendly(slot)) {
if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) {
PK11_FreeSlot(slot);
return NULL;
}
}
collection = nssCertificateCollection_Create(defaultTD, NULL);
if (!collection) {
PK11_FreeSlot(slot);
return NULL;
}
nameList = nssList_Create(NULL, PR_FALSE);
if (!nameList) {
PK11_FreeSlot(slot);
return NULL;
}
(void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
nickname,
nameList);
transfer_token_certs_to_collection(nameList, token, collection);
instances = nssToken_FindCertificatesByNickname(token,
NULL,
nickname,
tokenOnly,
0,
&status);
nssPKIObjectCollection_AddInstances(collection, instances, 0);
nss_ZFreeIf(instances);
nssList_Destroy(nameList);
foundCerts = nssPKIObjectCollection_GetCertificates(collection,
NULL, 0, NULL);
nssPKIObjectCollection_Destroy(collection);
}
if (slot) {
PK11_FreeSlot(slot);
}
if (nickCopy) PORT_Free(nickCopy);
if (foundCerts) {
certList = CERT_NewCertList();
for (i=0, c = *foundCerts; c; c = foundCerts[++i]) {
CERT_AddCertToListTail(certList, STAN_GetCERTCertificate(c));
}
if (CERT_LIST_HEAD(certList) == NULL) {
CERT_DestroyCertList(certList);
certList = NULL;
}
nss_ZFreeIf(foundCerts);
}
return certList;
#endif
}
/*
* 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) {
#ifdef NSS_CLASSIC
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;
int realCount = 0;
CK_ATTRIBUTE *attrs;
CK_RV crv;
SECCertUsage *certUsage = NULL;
SECItem derSerial = { 0 };
NSSToken *token;
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++;
if (PR_TRUE) {
/* CERTCertificate stores serial numbers decoded. I need the DER
* here. sigh.
*/
CERT_SerialNumberFromDERCert(&cert->derCert, &derSerial);
PK11_SETATTRS(attrs,CKA_SERIAL_NUMBER, derSerial.data, derSerial.len);
attrs++;
}
PK11_SETATTRS(attrs,CKA_VALUE, cert->derCert.data,
cert->derCert.len); attrs++;
if (includeTrust && PK11_IsInternal(slot)) {
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));
attrs++;
}
realCount = attrs - certAttrs;
PORT_Assert(realCount <= 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);
if (key != CK_INVALID_HANDLE) {
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,realCount,&certID);
if (crv == CKR_OK) {
rv = SECSuccess;
} else {
PORT_SetError( PK11_MapError(crv) );
}
if (!cert->nickname && nickname) {
cert->nickname = PORT_ArenaStrdup(cert->arena, nickname);
}
cert->pkcs11ID = certID;
cert->dbhandle = STAN_GetDefaultTrustDomain();
if (cert->slot == NULL) {
cert->slot = PK11_ReferenceSlot(slot);
cert->ownSlot = PR_TRUE;
if (cert->nssCertificate) {
nssCryptokiInstance *instance;
NSSCertificate *c = cert->nssCertificate;
instance = nss_ZNEW(c->object.arena, nssCryptokiInstance);
instance->token = slot->nssToken;
instance->handle = cert->pkcs11ID;
instance->isTokenObject = PR_TRUE;
nssPKIObject_AddInstance(&c->object, instance);
} else {
cert->nssCertificate = STAN_GetNSSCertificate(cert);
}
}
cert->trust = nssTrust_GetCERTCertTrustForCert(cert->nssCertificate, cert);
token = PK11Slot_GetNSSToken(slot);
done:
if (derSerial.data) PORT_Free(derSerial.data);
SECITEM_FreeItem(keyID,PR_TRUE);
PK11_RestoreROSession(slot,rwsession);
if(certUsage) {
PORT_Free(certUsage);
}
return rv;
#else
PRStatus status;
NSSCertificate *c;
nssCryptokiObject *keyobj, *certobj;
NSSToken *token = PK11Slot_GetNSSToken(slot);
SECItem *keyID = pk11_mkcertKeyID(cert);
if (keyID == NULL) {
goto loser;
}
/* need to get the cert as a stan cert */
if (cert->nssCertificate) {
c = cert->nssCertificate;
} else {
c = STAN_GetNSSCertificate(cert);
}
/* set the id for the cert */
nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
if (!c->id.data) {
goto loser;
}
if (key != CK_INVALID_HANDLE) {
/* create an object for the key, ... */
keyobj = nss_ZNEW(NULL, nssCryptokiObject);
if (!keyobj) {
goto loser;
}
keyobj->token = nssToken_AddRef(token);
keyobj->handle = key;
keyobj->isTokenObject = PR_TRUE;
/* ... in order to set matching attributes for the key */
status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname,
&c->id, &c->subject);
nssCryptokiObject_Destroy(keyobj);
if (status != PR_SUCCESS) {
goto loser;
}
}
/* do the token import */
certobj = nssToken_ImportCertificate(token, NULL,
NSSCertificateType_PKIX,
&c->id,
nickname,
&c->encoding,
&c->issuer,
&c->subject,
&c->serial,
PR_TRUE);
if (!certobj) {
goto loser;
}
/* add the new instance to the cert, force an update of the
* CERTCertificate, and finish
*/
nssPKIObject_AddInstance(&c->object, certobj);
nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
(void)STAN_ForceCERTCertificateUpdate(c);
SECITEM_FreeItem(keyID,PR_TRUE);
return SECSuccess;
loser:
SECITEM_FreeItem(keyID,PR_TRUE);
PORT_SetError(SEC_ERROR_ADDING_CERT);
return SECFailure;
#endif
}
/*
* 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_HANDLE) {
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_HANDLE) {
return NULL;
}
keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY);
if (keyh == CK_INVALID_HANDLE) { 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_HANDLE) {
slot = PK11_ReferenceSlot(le->slot);
if (keyPtr) *keyPtr = key;
break;
}
}
SECITEM_FreeItem(keyID,PR_TRUE);
PK11_FreeSlotList(list);
return slot;
}
/*
* 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_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr,
void *wincx) {
CERTCertificate *cert;
PK11SlotInfo *slot = NULL;
cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
if (cert == NULL) return NULL;
slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
CERT_DestroyCertificate (cert);
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;
}
PK11SlotInfo *
PK11_ImportDERCertForKey(SECItem *derCert, char *nickname,void *wincx) {
CERTCertificate *cert;
PK11SlotInfo *slot = NULL;
cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
if (cert == NULL) return NULL;
slot = PK11_ImportCertForKey(cert, nickname, wincx);
CERT_DestroyCertificate (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_HANDLE;
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_HANDLE;
}
/* 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_HANDLE) {
slot = PK11_ReferenceSlot(le->slot);
break;
}
}
PK11_FreeSlotList(list);
if (slot == NULL) {
return CK_INVALID_HANDLE;
}
*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.
* this is the new version for NSS SMIME code
* this stuff should REALLY be in the SMIME code, but some things in here are not public
* (they should be!)
*/
static CK_OBJECT_HANDLE
pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist, int *rlIndex)
{
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);
NSSCMSRecipient *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 = recipientlist[i]) != NULL; i++) {
/* XXXXX fixme - not yet implemented! */
if (ri->kind == RLSubjKeyID)
continue;
attrs = searchTemplate;
PK11_SETATTRS(attrs, CKA_CLASS, &certClass,sizeof(certClass)); attrs++;
PK11_SETATTRS(attrs, CKA_ISSUER, ri->id.issuerAndSN->derIssuer.data,
ri->id.issuerAndSN->derIssuer.len); attrs++;
PK11_SETATTRS(attrs, CKA_SERIAL_NUMBER,
ri->id.issuerAndSN->serialNumber.data,ri->id.issuerAndSN->serialNumber.len);
certHandle = pk11_FindObjectByTemplate(slot,searchTemplate,count);
if (certHandle != CK_INVALID_HANDLE) {
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... */
ri->slot = PK11_ReferenceSlot(slot);
*rlIndex = i;
CERT_DestroyCertificate(cert);
return certHandle;
}
CERT_DestroyCertificate(cert);
}
}
*rlIndex = -1;
return CK_INVALID_HANDLE;
}
/*
* This function is the same as above, but it searches all the slots.
* this is the new version for NSS SMIME code
* this stuff should REALLY be in the SMIME code, but some things in here are not public
* (they should be!)
*/
static CK_OBJECT_HANDLE
pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
{
PK11SlotList *list;
PK11SlotListElement *le;
CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
SECStatus rv;
/* 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_HANDLE;
}
/* 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_FindCertObjectByRecipientNew(le->slot, recipientlist, rlIndex);
if (certHandle != CK_INVALID_HANDLE)
break;
}
PK11_FreeSlotList(list);
return (le == NULL) ? CK_INVALID_HANDLE : 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_HANDLE) {
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_HANDLE;
}
/*
* 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_HANDLE;
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_HANDLE;
}
*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_HANDLE) {
slot = PK11_ReferenceSlot(le->slot);
break;
}
}
PK11_FreeSlotList(list);
if (slot == NULL) {
return CK_INVALID_HANDLE;
}
*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_HANDLE;
CK_OBJECT_HANDLE keyHandle = CK_INVALID_HANDLE;
CERTCertificate *cert = NULL;
SECStatus rv;
*privKey = NULL;
certHandle = pk11_AllFindCertObjectByRecipient(slotPtr,array,rip,wincx);
if (certHandle == CK_INVALID_HANDLE) {
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_HANDLE) {
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;
}
/*
* This is the new version of the above function for NSS SMIME code
* this stuff should REALLY be in the SMIME code, but some things in here are not public
* (they should be!)
*/
int
PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
{
CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
CK_OBJECT_HANDLE keyHandle = CK_INVALID_HANDLE;
NSSCMSRecipient *rl;
int rlIndex;
certHandle = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
if (certHandle == CK_INVALID_HANDLE) {
return -1;
}
rl = recipientlist[rlIndex];
/* at this point, rl->slot is set */
/* authenticate to the token */
if (PK11_Authenticate(rl->slot, PR_TRUE, wincx) != SECSuccess) {
PK11_FreeSlot(rl->slot);
rl->slot = NULL;
return -1;
}
/* try to get a private key handle for the cert we found */
keyHandle = PK11_MatchItem(rl->slot, certHandle, CKO_PRIVATE_KEY);
if (keyHandle == CK_INVALID_HANDLE) {
PK11_FreeSlot(rl->slot);
rl->slot = NULL;
return -1;
}
/* make a private key out of the handle */
rl->privkey = PK11_MakePrivKey(rl->slot, nullKey, PR_TRUE, keyHandle, wincx);
if (rl->privkey == NULL) {
PK11_FreeSlot(rl->slot);
rl->slot = NULL;
return -1;
}
/* make a cert from the cert handle */
rl->cert = PK11_MakeCertFromHandle(rl->slot, certHandle, NULL);
if (rl->cert == NULL) {
PK11_FreeSlot(rl->slot);
SECKEY_DestroyPrivateKey(rl->privkey);
rl->slot = NULL;
rl->privkey = NULL;
return -1;
}
return rlIndex;
}
CERTCertificate *
PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
void *wincx)
{
#ifdef NSS_CLASSIC
CK_OBJECT_HANDLE certHandle;
CERTCertificate *cert = NULL;
CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
CK_ATTRIBUTE searchTemplate[] = {
{ CKA_CLASS, NULL, 0 },
{ CKA_ISSUER, NULL, 0 },
{ CKA_SERIAL_NUMBER, NULL, 0}
};
int count = sizeof(searchTemplate)/sizeof(CK_ATTRIBUTE);
CK_ATTRIBUTE *attrs = searchTemplate;
PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++;
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_HANDLE) {
return NULL;
}
cert = PK11_MakeCertFromHandle(*slotPtr,certHandle,NULL);
if (cert == NULL) {
PK11_FreeSlot(*slotPtr);
return NULL;
}
return cert;
#else
CERTCertificate *rvCert = NULL;
NSSCertificate *cert;
NSSDER issuer, serial;
NSSCryptoContext *cc;
SECItem *derSerial;
if (slotPtr) *slotPtr = NULL;
/* PKCS#11 needs to use DER-encoded serial numbers. Create a
* CERTIssuerAndSN that actually has the encoded value and pass that
* to PKCS#11 (and the crypto context).
*/
derSerial = SEC_ASN1EncodeItem(NULL, NULL,
&issuerSN->serialNumber,
SEC_IntegerTemplate);
if (!derSerial) {
return NULL;
}
NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
NSSITEM_FROM_SECITEM(&serial, derSerial);
cc = STAN_GetDefaultCryptoContext();
cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc,
&issuer,
&serial);
if (cert) {
SECITEM_FreeItem(derSerial, PR_TRUE);
return STAN_GetCERTCertificate(cert);
}
cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
STAN_GetDefaultTrustDomain(),
&issuer,
&serial);
if (cert) {
rvCert = STAN_GetCERTCertificate(cert);
if (slotPtr) *slotPtr = PK11_ReferenceSlot(rvCert->slot);
}
SECITEM_FreeItem(derSerial, PR_TRUE);
return rvCert;
#endif
}
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_HANDLE) {
*pSlot = PK11_ReferenceSlot(cert->slot);
return certHandle;
}
}
certHandle = pk11_FindCertObjectByTemplate(pSlot,&searchTemplate,1,wincx);
if (certHandle != CK_INVALID_HANDLE) {
if (cert->slot == NULL) {
cert->slot = PK11_ReferenceSlot(*pSlot);
cert->pkcs11ID = certHandle;
cert->ownSlot = PR_TRUE;
}
}
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_HANDLE) {
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_HANDLE) {
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_HANDLE) {
return CK_INVALID_HANDLE;
}
keyHandle = PK11_MatchItem(*slot,certHandle,CKO_PUBLIC_KEY);
if (keyHandle == CK_INVALID_HANDLE) {
PK11_FreeSlot(*slot);
return CK_INVALID_HANDLE;
}
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
*/
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) {
PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
PR_FALSE,PR_TRUE,NULL);
PK11SlotListElement *le;
int count = 0;
/* loop through all the fortezza tokens */
for (le = list->head; le; le = le->next) {
count += PK11_NumberObjectsFor(le->slot,theTemplate,templateSize);
}
PK11_FreeSlotList(list);
return count;
}
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;
}
if (cert->slot == NULL) {
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) {
PK11_TraverseCertsForSubjectInSlot(cert,le->slot,callback,arg);
}
PK11_FreeSlotList(list);
return SECSuccess;
}
return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
}
SECStatus
PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
#ifdef NSS_CLASSIC
pk11DoCertCallback caller;
pk11TraverseSlot 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) {
return SECSuccess;
}
caller.noslotcallback = callback;
caller.callback = NULL;
caller.itemcallback = NULL;
caller.callbackArg = arg;
callarg.callback = pk11_DoCerts;
callarg.callbackArg = (void *) & caller;
callarg.findTemplate = theTemplate;
callarg.templateCount = templateSize;
return PK11_TraverseSlot(slot, &callarg);
#else
PRStatus nssrv = PR_SUCCESS;
NSSToken *token;
NSSDER subject;
NSSTrustDomain *td;
nssList *subjectList;
nssPKIObjectCollection *collection;
nssCryptokiObject **instances;
NSSCertificate **certs;
nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
td = STAN_GetDefaultTrustDomain();
NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
token = PK11Slot_GetNSSToken(slot);
if (!nssToken_IsPresent(token)) {
return SECSuccess;
}
collection = nssCertificateCollection_Create(td, NULL);
if (!collection) {
return SECFailure;
}
subjectList = nssList_Create(NULL, PR_FALSE);
if (!subjectList) {
nssPKIObjectCollection_Destroy(collection);
return SECFailure;
}
(void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject,
subjectList);
transfer_token_certs_to_collection(subjectList, token, collection);
instances = nssToken_FindCertificatesBySubject(token, NULL,
&subject,
tokenOnly, 0, &nssrv);
nssPKIObjectCollection_AddInstances(collection, instances, 0);
nss_ZFreeIf(instances);
nssList_Destroy(subjectList);
certs = nssPKIObjectCollection_GetCertificates(collection,
NULL, 0, NULL);
nssPKIObjectCollection_Destroy(collection);
if (certs) {
CERTCertificate *oldie;
NSSCertificate **cp;
for (cp = certs; *cp; cp++) {
oldie = STAN_GetCERTCertificate(*cp);
if ((*callback)(oldie, arg) != SECSuccess) {
nssrv = PR_FAILURE;
break;
}
}
nssCertificateArray_Destroy(certs);
}
return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
#endif
}
SECStatus
PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
#ifdef NSS_CLASSIC
pk11DoCertCallback caller;
pk11TraverseSlot 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) {
return SECSuccess;
}
caller.noslotcallback = callback;
caller.callback = NULL;
caller.itemcallback = NULL;
caller.callbackArg = arg;
callarg.callback = pk11_DoCerts;
callarg.callbackArg = (void *) & caller;
callarg.findTemplate = theTemplate;
callarg.templateCount = templateSize;
return PK11_TraverseSlot(slot, &callarg);
#else
struct nss3_cert_cbstr pk11cb;
PRStatus nssrv = PR_SUCCESS;
NSSToken *token;
NSSTrustDomain *td;
NSSUTF8 *nick;
PRBool created = PR_FALSE;
nssCryptokiObject **instances;
nssPKIObjectCollection *collection = NULL;
NSSCertificate **certs;
nssList *nameList = NULL;
nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
pk11cb.callback = callback;
pk11cb.arg = arg;
token = PK11Slot_GetNSSToken(slot);
if (!nssToken_IsPresent(token)) {
return SECSuccess;
}
if (nickname->data[nickname->len-1] != '\0') {
nick = nssUTF8_Create(NULL, nssStringType_UTF8String,
nickname->data, nickname->len);
created = PR_TRUE;
} else {
nick = (NSSUTF8 *)nickname->data;
}
td = STAN_GetDefaultTrustDomain();
collection = nssCertificateCollection_Create(td, NULL);
if (!collection) {
goto loser;
}
nameList = nssList_Create(NULL, PR_FALSE);
if (!nameList) {
goto loser;
}
(void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
transfer_token_certs_to_collection(nameList, token, collection);
instances = nssToken_FindCertificatesByNickname(token, NULL,
nick,
tokenOnly, 0, &nssrv);
nssPKIObjectCollection_AddInstances(collection, instances, 0);
nss_ZFreeIf(instances);
nssList_Destroy(nameList);
certs = nssPKIObjectCollection_GetCertificates(collection,
NULL, 0, NULL);
nssPKIObjectCollection_Destroy(collection);
if (certs) {
CERTCertificate *oldie;
NSSCertificate **cp;
for (cp = certs; *cp; cp++) {
oldie = STAN_GetCERTCertificate(*cp);
if ((*callback)(oldie, arg) != SECSuccess) {
nssrv = PR_FAILURE;
break;
}
}
nssCertificateArray_Destroy(certs);
}
if (created) nss_ZFreeIf(nick);
return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
loser:
if (created) {
nss_ZFreeIf(nick);
}
if (collection) {
nssPKIObjectCollection_Destroy(collection);
}
if (nameList) {
nssList_Destroy(nameList);
}
return SECFailure;
#endif
}
SECStatus
PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
SECStatus(* callback)(CERTCertificate*, void *), void *arg)
{
#ifdef NSS_CLASSIC
pk11DoCertCallback caller;
pk11TraverseSlot 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.itemcallback = NULL;
caller.callbackArg = arg;
callarg.callback = pk11_DoCerts;
callarg.callbackArg = (void *) & caller;
callarg.findTemplate = theTemplate;
callarg.templateCount = templateSize;
return PK11_TraverseSlot(slot, &callarg);
#else
PRStatus nssrv;
NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
NSSToken *tok;
nssList *certList = NULL;
nssCryptokiObject **instances;
nssPKIObjectCollection *collection;
NSSCertificate **certs;
nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
tok = PK11Slot_GetNSSToken(slot);
if (!nssToken_IsPresent(tok)) {
return SECSuccess;
}
collection = nssCertificateCollection_Create(td, NULL);
if (!collection) {
return SECFailure;
}
certList = nssList_Create(NULL, PR_FALSE);
if (!certList) {
nssPKIObjectCollection_Destroy(collection);
return SECFailure;
}
(void *)nssTrustDomain_GetCertsFromCache(td, certList);
transfer_token_certs_to_collection(certList, tok, collection);
instances = nssToken_FindCertificates(tok, NULL,
tokenOnly, 0, &nssrv);
nssPKIObjectCollection_AddInstances(collection, instances, 0);
nss_ZFreeIf(instances);
nssList_Destroy(certList);
certs = nssPKIObjectCollection_GetCertificates(collection,
NULL, 0, NULL);
nssPKIObjectCollection_Destroy(collection);
if (certs) {
CERTCertificate *oldie;
NSSCertificate **cp;
for (cp = certs; *cp; cp++) {
oldie = STAN_GetCERTCertificate(*cp);
if ((*callback)(oldie, arg) != SECSuccess) {
nssrv = PR_FAILURE;
break;
}
}
nssCertificateArray_Destroy(certs);
}
return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
#endif
}
/*
* return the certificate associated with a derCert
*/
CERTCertificate *
PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx)
{
#ifdef NSS_CLASSIC
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_HANDLE) {
return NULL;
}
return PK11_MakeCertFromHandle(slot, certh, NULL);
#else
CERTCertificate *rvCert = NULL;
NSSCertificate *c;
NSSDER derCert;
NSSToken *tok;
NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
tok = PK11Slot_GetNSSToken(slot);
NSSITEM_FROM_SECITEM(&derCert, &cert->derCert);
if (!PK11_IsFriendly(slot)) {
if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) {
PK11_FreeSlot(slot);
return NULL;
}
}
c = NSSTrustDomain_FindCertificateByEncodedCertificate(td, &derCert);
if (c) {
PRBool isToken = PR_FALSE;
NSSToken **tp;
NSSToken **tokens = nssPKIObject_GetTokens(&c->object, NULL);
if (tokens) {
for (tp = tokens; *tp; tp++) {
if (*tp == tok) {
isToken = PR_TRUE;
break;
}
}
if (!isToken) {
NSSCertificate_Destroy(c);
c = NULL;
}
nssTokenArray_Destroy(tokens);
}
}
if (c) {
rvCert = STAN_GetCERTCertificate(c);
}
return rvCert;
#endif
}
/* mcgreer 3.4 -- nobody uses this, ignoring */
/*
* 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_HANDLE) {
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_HANDLE;
}
keyID = pk11_mkcertKeyID(cert);
if(keyID == NULL) {
return CK_INVALID_HANDLE;
}
key = CK_INVALID_HANDLE;
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_HANDLE) {
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_HANDLE) {
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)
{
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_HANDLE;
}
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_HANDLE) {
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;
}
struct listCertsStr {
PK11CertListType type;
CERTCertList *certList;
};
static PRBool
isOnList(CERTCertList *certList,CERTCertificate *cert)
{
CERTCertListNode *cln;
for (cln = CERT_LIST_HEAD(certList); !CERT_LIST_END(cln,certList);
cln = CERT_LIST_NEXT(cln)) {
if (cln->cert == cert) {
return PR_TRUE;
}
}
return PR_FALSE;
}
static SECStatus
#ifdef NSS_CLASSIC
pk11ListCertCallback(CERTCertificate *cert, SECItem *derCert, void *arg)
#else
pk11ListCertCallback(CERTCertificate *cert, void *arg)
#endif
{
struct listCertsStr *listCertP = (struct listCertsStr *)arg;
CERTCertificate *newCert = NULL;
PK11CertListType type = listCertP->type;
CERTCertList *certList = listCertP->certList;
CERTCertTrust *trust;
PRBool isUnique = PR_FALSE;
PRBool isCA = PR_FALSE;
char *nickname = NULL;
unsigned int certType;
if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique)) {
isUnique = PR_TRUE;
}
if ((type == PK11CertListCA) || (type == PK11CertListRootUnique)) {
isCA = PR_TRUE;
}
/* at this point the nickname is correct for the cert. save it for later */
if (!isUnique && cert->nickname) {
nickname = PORT_ArenaStrdup(listCertP->certList->arena,cert->nickname);
}
#ifdef NSS_CLASSIC
if (derCert == NULL) {
newCert=CERT_DupCertificate(cert);
} else {
newCert=CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),&cert->derCert);
}
#else
newCert=CERT_DupCertificate(cert);
#endif
if (newCert == NULL) return SECSuccess;
trust = newCert->trust;
/* if we want user certs and we don't have one skip this cert */
if ((type == PK11CertListUser) &&
((trust == NULL) ||
( ((trust->sslFlags & CERTDB_USER) == 0) &&
((trust->emailFlags & CERTDB_USER) == 0) )) ) {
CERT_DestroyCertificate(newCert);
return SECSuccess;
}
/* if we want root certs, skip the user certs */
if ((type == PK11CertListRootUnique) &&
((trust) && (((trust->sslFlags & CERTDB_USER ) ||
(trust->emailFlags & CERTDB_USER))) ) ) {
CERT_DestroyCertificate(newCert);
return SECSuccess;
}
/* if we want Unique certs and we already have it on our list, skip it */
if ( isUnique && isOnList(certList,newCert) ) {
CERT_DestroyCertificate(newCert);
return SECSuccess;
}
/* if we want CA certs and it ain't one, skip it */
if( isCA && (!CERT_IsCACert(newCert, &certType)) ) {
CERT_DestroyCertificate(newCert);
return SECSuccess;
}
/* put slot certs at the end */
if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
CERT_AddCertToListTailWithData(certList,newCert,nickname);
} else {
CERT_AddCertToListHeadWithData(certList,newCert,nickname);
}
return SECSuccess;
}
CERTCertList *
PK11_ListCerts(PK11CertListType type, void *pwarg)
{
#ifdef NSS_CLASSIC
CERTCertList *certList = NULL;
struct listCertsStr listCerts;
certList= CERT_NewCertList();
listCerts.type = type;
listCerts.certList = certList;
PK11_TraverseSlotCerts(pk11ListCertCallback,&listCerts,pwarg);
if (CERT_LIST_HEAD(certList) == NULL) {
CERT_DestroyCertList(certList);
certList = NULL;
}
return certList;
#else
NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
CERTCertList *certList = NULL;
struct nss3_cert_cbstr pk11cb;
struct listCertsStr listCerts;
certList = CERT_NewCertList();
listCerts.type = type;
listCerts.certList = certList;
pk11cb.callback = pk11ListCertCallback;
pk11cb.arg = &listCerts;
/* authenticate to the slots */
(void) pk11_TraverseAllSlots( NULL, NULL, pwarg);
#ifdef notdef
if (type == PK11CertListUser) {
NSSTrustDomain_TraverseUserCertificates(defaultTD, convert_cert &pk11cb);
} else {
NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
}
#else
NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
#endif
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 = theTemplate[0].pValue;
item->len =theTemplate[0].ulValueLen;
return item;
}
SECItem *
PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
CERTCertificate *cert, void *wincx)
{
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 certHandle;
CK_ATTRIBUTE *attrs = theTemplate;
PK11SlotInfo *slotRef = NULL;
SECItem *item;
SECStatus rv;
if (slot) {
PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
cert->derCert.len); attrs++;
rv = PK11_Authenticate(slot, PR_TRUE, wincx);
if (rv != SECSuccess) {
return NULL;
}
certHandle = pk11_getcerthandle(slot,cert,theTemplate,tsize);
} else {
certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
if (certHandle == CK_INVALID_HANDLE) {
return pk11_mkcertKeyID(cert);
}
slot = slotRef;
}
if (certHandle == CK_INVALID_HANDLE) {
return NULL;
}
item = pk11_GetLowLevelKeyFromHandle(slot,certHandle);
if (slotRef) PK11_FreeSlot(slotRef);
return item;
}
SECItem *
PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey)
{
return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID);
}
static SECStatus
listCertsCallback(CERTCertificate* cert, void*arg)
{
CERTCertList *list = (CERTCertList*)arg;
char *nickname = NULL;
if (cert->nickname) {
nickname = PORT_ArenaStrdup(list->arena,cert->nickname);
}
return CERT_AddCertToListTailWithData(list,
CERT_DupCertificate(cert),nickname);
}
CERTCertList *
PK11_ListCertsInSlot(PK11SlotInfo *slot)
{
SECStatus status;
CERTCertList *certs;
certs = CERT_NewCertList();
if(certs == NULL) return NULL;
status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
(void*)certs);
if( status != SECSuccess ) {
CERT_DestroyCertList(certs);
certs = NULL;
}
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) {
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) {
return NULL;
}
*slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot);
*crlHandle = crl->object.instances[0]->handle;
if (crl->url) {
*url = PORT_Strdup(crl->url);
}
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);
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) {
/* 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 = 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 = smimeData[1].pValue;
emailProfile->len = smimeData[1].ulValueLen;
if (profileTime) {
*profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
if (*profileTime) {
(*profileTime)->data = 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;
}