tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11cert.c (94274B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * This file manages PKCS #11 instances of certificates.
      6 */
      7 
      8 #include <stddef.h>
      9 
     10 #include "secport.h"
     11 #include "seccomon.h"
     12 #include "secmod.h"
     13 #include "secmodi.h"
     14 #include "secmodti.h"
     15 #include "pkcs11.h"
     16 #include "pk11func.h"
     17 #include "cert.h"
     18 #include "certi.h"
     19 #include "secitem.h"
     20 #include "keyhi.h"
     21 #include "secoid.h"
     22 #include "pkcs7t.h"
     23 #include "cmsreclist.h"
     24 
     25 #include "certdb.h"
     26 #include "secerr.h"
     27 #include "sslerr.h"
     28 
     29 #include "pki3hack.h"
     30 #include "dev3hack.h"
     31 
     32 #include "devm.h"
     33 #include "nsspki.h"
     34 #include "pki.h"
     35 #include "pkim.h"
     36 #include "pkitm.h"
     37 #include "pkistore.h" /* to remove temp cert */
     38 #include "devt.h"
     39 #include "ckhelper.h"
     40 #include "pkcs11uri.h"
     41 
     42 extern const NSSError NSS_ERROR_NOT_FOUND;
     43 extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
     44 
     45 struct nss3_cert_cbstr {
     46    SECStatus (*callback)(CERTCertificate *, void *);
     47    nssList *cached;
     48    void *arg;
     49 };
     50 
     51 /* Translate from NSSCertificate to CERTCertificate, then pass the latter
     52 * to a callback.
     53 */
     54 static PRStatus
     55 convert_cert(NSSCertificate *c, void *arg)
     56 {
     57    CERTCertificate *nss3cert;
     58    SECStatus secrv;
     59    struct nss3_cert_cbstr *nss3cb = (struct nss3_cert_cbstr *)arg;
     60    /* 'c' is not adopted. caller will free it */
     61    nss3cert = STAN_GetCERTCertificate(c);
     62    if (!nss3cert)
     63        return PR_FAILURE;
     64    secrv = (*nss3cb->callback)(nss3cert, nss3cb->arg);
     65    return (secrv) ? PR_FAILURE : PR_SUCCESS;
     66 }
     67 
     68 /*
     69 * build a cert nickname based on the token name and the label of the
     70 * certificate If the label in NULL, build a label based on the ID.
     71 */
     72 static int
     73 toHex(int x)
     74 {
     75    return (x < 10) ? (x + '0') : (x + 'a' - 10);
     76 }
     77 #define MAX_CERT_ID 4
     78 #define DEFAULT_STRING "Cert ID "
     79 static char *
     80 pk11_buildNickname(PK11SlotInfo *slot, CK_ATTRIBUTE *cert_label,
     81                   CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id)
     82 {
     83    int prefixLen = PORT_Strlen(slot->token_name);
     84    int suffixLen = 0;
     85    char *suffix = NULL;
     86    char buildNew[sizeof(DEFAULT_STRING) + MAX_CERT_ID * 2];
     87    char *next, *nickname;
     88 
     89    if (cert_label && (cert_label->ulValueLen)) {
     90        suffixLen = cert_label->ulValueLen;
     91        suffix = (char *)cert_label->pValue;
     92    } else if (key_label && (key_label->ulValueLen)) {
     93        suffixLen = key_label->ulValueLen;
     94        suffix = (char *)key_label->pValue;
     95    } else if (cert_id && cert_id->ulValueLen > 0) {
     96        int i, first = cert_id->ulValueLen - MAX_CERT_ID;
     97        int offset = sizeof(DEFAULT_STRING);
     98        char *idValue = (char *)cert_id->pValue;
     99 
    100        PORT_Memcpy(buildNew, DEFAULT_STRING, sizeof(DEFAULT_STRING) - 1);
    101        next = buildNew + offset;
    102        if (first < 0)
    103            first = 0;
    104        for (i = first; i < (int)cert_id->ulValueLen; i++) {
    105            *next++ = toHex((idValue[i] >> 4) & 0xf);
    106            *next++ = toHex(idValue[i] & 0xf);
    107        }
    108        *next++ = 0;
    109        suffix = buildNew;
    110        suffixLen = PORT_Strlen(buildNew);
    111    } else {
    112        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    113        return NULL;
    114    }
    115 
    116    /* if is internal key slot, add code to skip the prefix!! */
    117    next = nickname = (char *)PORT_Alloc(prefixLen + 1 + suffixLen + 1);
    118    if (nickname == NULL)
    119        return NULL;
    120 
    121    PORT_Memcpy(next, slot->token_name, prefixLen);
    122    next += prefixLen;
    123    *next++ = ':';
    124    PORT_Memcpy(next, suffix, suffixLen);
    125    next += suffixLen;
    126    *next++ = 0;
    127    return nickname;
    128 }
    129 
    130 PRBool
    131 PK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,
    132                CK_OBJECT_HANDLE certID)
    133 {
    134    CK_OBJECT_CLASS theClass;
    135 
    136    if (slot == NULL)
    137        return PR_FALSE;
    138    if (cert == NULL)
    139        return PR_FALSE;
    140 
    141    theClass = CKO_PRIVATE_KEY;
    142    if (pk11_LoginStillRequired(slot, NULL)) {
    143        theClass = CKO_PUBLIC_KEY;
    144    }
    145    if (PK11_MatchItem(slot, certID, theClass) != CK_INVALID_HANDLE) {
    146        return PR_TRUE;
    147    }
    148 
    149    if (theClass == CKO_PUBLIC_KEY) {
    150        SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(cert);
    151        CK_ATTRIBUTE theTemplate;
    152 
    153        if (pubKey == NULL) {
    154            return PR_FALSE;
    155        }
    156 
    157        PK11_SETATTRS(&theTemplate, 0, NULL, 0);
    158        switch (pubKey->keyType) {
    159            case rsaKey:
    160            case rsaPssKey:
    161            case rsaOaepKey:
    162                PK11_SETATTRS(&theTemplate, CKA_MODULUS, pubKey->u.rsa.modulus.data,
    163                              pubKey->u.rsa.modulus.len);
    164                break;
    165            case dsaKey:
    166                PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.dsa.publicValue.data,
    167                              pubKey->u.dsa.publicValue.len);
    168                break;
    169            case dhKey:
    170                PK11_SETATTRS(&theTemplate, CKA_VALUE, pubKey->u.dh.publicValue.data,
    171                              pubKey->u.dh.publicValue.len);
    172                break;
    173            case ecKey:
    174            case edKey:
    175            case ecMontKey:
    176                PK11_SETATTRS(&theTemplate, CKA_EC_POINT,
    177                              pubKey->u.ec.publicValue.data,
    178                              pubKey->u.ec.publicValue.len);
    179                break;
    180            case mldsaKey:
    181                PK11_SETATTRS(&theTemplate, CKA_VALUE,
    182                              pubKey->u.mldsa.publicValue.data,
    183                              pubKey->u.mldsa.publicValue.len);
    184                break;
    185            case keaKey:
    186            case fortezzaKey:
    187            case kyberKey:
    188            case nullKey:
    189                /* fall through and return false */
    190                break;
    191        }
    192 
    193        if (theTemplate.ulValueLen == 0) {
    194            SECKEY_DestroyPublicKey(pubKey);
    195            return PR_FALSE;
    196        }
    197        if (pubKey->keyType != ecKey && pubKey->keyType != edKey &&
    198            pubKey->keyType != ecMontKey && pubKey->keyType != mldsaKey) {
    199            pk11_SignedToUnsigned(&theTemplate);
    200        }
    201        if (pk11_FindObjectByTemplate(slot, &theTemplate, 1) != CK_INVALID_HANDLE) {
    202            SECKEY_DestroyPublicKey(pubKey);
    203            return PR_TRUE;
    204        }
    205        SECKEY_DestroyPublicKey(pubKey);
    206    }
    207    return PR_FALSE;
    208 }
    209 
    210 /*
    211 * Check out if a cert has ID of zero. This is a magic ID that tells
    212 * NSS that this cert may be an automagically trusted cert.
    213 * The Cert has to be self signed as well. That check is done elsewhere.
    214 *
    215 */
    216 PRBool
    217 pk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID)
    218 {
    219    CK_ATTRIBUTE keyID = { CKA_ID, NULL, 0 };
    220    PRBool isZero = PR_FALSE;
    221    int i;
    222    CK_RV crv;
    223 
    224    crv = PK11_GetAttributes(NULL, slot, certID, &keyID, 1);
    225    if (crv != CKR_OK) {
    226        return isZero;
    227    }
    228 
    229    if (keyID.ulValueLen != 0) {
    230        char *value = (char *)keyID.pValue;
    231        isZero = PR_TRUE; /* ID exists, may be zero */
    232        for (i = 0; i < (int)keyID.ulValueLen; i++) {
    233            if (value[i] != 0) {
    234                isZero = PR_FALSE; /* nope */
    235                break;
    236            }
    237        }
    238    }
    239    PORT_Free(keyID.pValue);
    240    return isZero;
    241 }
    242 
    243 /*
    244 * Create an NSSCertificate from a slot/certID pair, return it as a
    245 * CERTCertificate.  Optionally, output the nickname string.
    246 */
    247 static CERTCertificate *
    248 pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID,
    249              CK_ATTRIBUTE *privateLabel, char **nickptr)
    250 {
    251    NSSCertificate *c;
    252    nssCryptokiObject *co = NULL;
    253    nssPKIObject *pkio;
    254    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
    255 
    256    /* Get the cryptoki object from the handle */
    257    NSSToken *token = PK11Slot_GetNSSToken(slot);
    258    if (!token || !token->defaultSession) {
    259        (void)nssToken_Destroy(token); /* null token is ok */
    260        PORT_SetError(SEC_ERROR_NO_TOKEN);
    261        return NULL;
    262    }
    263    co = nssCryptokiObject_Create(token, token->defaultSession, certID);
    264    (void)nssToken_Destroy(token);
    265    if (!co) {
    266        return NULL;
    267    }
    268 
    269    /* Create a PKI object from the cryptoki instance */
    270    pkio = nssPKIObject_Create(NULL, co, td, NULL, nssPKIMonitor);
    271    if (!pkio) {
    272        nssCryptokiObject_Destroy(co);
    273        return NULL;
    274    }
    275 
    276    /* Create a certificate */
    277    c = nssCertificate_Create(pkio);
    278    if (!c) {
    279        nssPKIObject_Destroy(pkio);
    280        return NULL;
    281    }
    282 
    283    /* Build and output a nickname, if desired.
    284     * This must be done before calling nssTrustDomain_AddCertsToCache
    285     * because that function may destroy c, pkio and co!
    286     */
    287    if ((nickptr) && (co->label)) {
    288        CK_ATTRIBUTE label, id;
    289 
    290        label.type = CKA_LABEL;
    291        label.pValue = co->label;
    292        label.ulValueLen = PORT_Strlen(co->label);
    293 
    294        id.type = CKA_ID;
    295        id.pValue = c->id.data;
    296        id.ulValueLen = c->id.size;
    297 
    298        *nickptr = pk11_buildNickname(slot, &label, privateLabel, &id);
    299    }
    300 
    301    /* This function may destroy the cert in "c" and all its subordinate
    302     * structures, and replace the value in "c" with the address of a
    303     * different NSSCertificate that it found in the cache.
    304     * Presumably, the nickname which we just output above remains valid. :)
    305     */
    306    (void)nssTrustDomain_AddCertsToCache(td, &c, 1);
    307    return STAN_GetCERTCertificateOrRelease(c);
    308 }
    309 
    310 /*
    311 * Build an CERTCertificate structure from a PKCS#11 object ID.... certID
    312 * Must be a CertObject. This code does not explicitly checks that.
    313 */
    314 CERTCertificate *
    315 PK11_MakeCertFromHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID,
    316                        CK_ATTRIBUTE *privateLabel)
    317 {
    318    char *nickname = NULL;
    319    CERTCertificate *cert = NULL;
    320    CERTCertTrust *trust;
    321 
    322    if (slot == NULL || certID == CK_INVALID_HANDLE) {
    323        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    324        return NULL;
    325    }
    326 
    327    cert = pk11_fastCert(slot, certID, privateLabel, &nickname);
    328    if (cert == NULL) {
    329        goto loser;
    330    }
    331 
    332    if (nickname) {
    333        if (cert->nickname != NULL) {
    334            cert->dbnickname = cert->nickname;
    335        }
    336        cert->nickname = PORT_ArenaStrdup(cert->arena, nickname);
    337        PORT_Free(nickname);
    338        nickname = NULL;
    339    }
    340 
    341    /* remember where this cert came from.... If we have just looked
    342     * it up from the database and it already has a slot, don't add a new
    343     * one. */
    344    if (cert->slot == NULL) {
    345        cert->slot = PK11_ReferenceSlot(slot);
    346        cert->pkcs11ID = certID;
    347        cert->ownSlot = PR_TRUE;
    348        cert->series = slot->series;
    349    }
    350 
    351    trust = (CERTCertTrust *)PORT_ArenaAlloc(cert->arena, sizeof(CERTCertTrust));
    352    if (trust == NULL)
    353        goto loser;
    354    PORT_Memset(trust, 0, sizeof(CERTCertTrust));
    355 
    356    if (!pk11_HandleTrustObject(slot, cert, trust)) {
    357        unsigned int type;
    358 
    359        /* build some cert trust flags */
    360        if (CERT_IsCACert(cert, &type)) {
    361            unsigned int trustflags = CERTDB_VALID_CA;
    362 
    363            /* Allow PKCS #11 modules to give us trusted CA's. We only accept
    364             * valid CA's which are self-signed here. They must have an object
    365             * ID of '0'.  */
    366            if (pk11_isID0(slot, certID) &&
    367                cert->isRoot) {
    368                trustflags |= CERTDB_TRUSTED_CA;
    369                /* is the slot a fortezza card? allow the user or
    370                 * admin to turn on objectSigning, but don't turn
    371                 * full trust on explicitly */
    372                if (PK11_DoesMechanism(slot, CKM_KEA_KEY_DERIVE)) {
    373                    trust->objectSigningFlags |= CERTDB_VALID_CA;
    374                }
    375            }
    376            if ((type & NS_CERT_TYPE_SSL_CA) == NS_CERT_TYPE_SSL_CA) {
    377                trust->sslFlags |= trustflags;
    378            }
    379            if ((type & NS_CERT_TYPE_EMAIL_CA) == NS_CERT_TYPE_EMAIL_CA) {
    380                trust->emailFlags |= trustflags;
    381            }
    382            if ((type & NS_CERT_TYPE_OBJECT_SIGNING_CA) == NS_CERT_TYPE_OBJECT_SIGNING_CA) {
    383                trust->objectSigningFlags |= trustflags;
    384            }
    385        }
    386    }
    387 
    388    if (PK11_IsUserCert(slot, cert, certID)) {
    389        trust->sslFlags |= CERTDB_USER;
    390        trust->emailFlags |= CERTDB_USER;
    391        /*    trust->objectSigningFlags |= CERTDB_USER; */
    392    }
    393    CERT_LockCertTrust(cert);
    394    cert->trust = trust;
    395    CERT_UnlockCertTrust(cert);
    396 
    397    return cert;
    398 
    399 loser:
    400    if (nickname)
    401        PORT_Free(nickname);
    402    if (cert)
    403        CERT_DestroyCertificate(cert);
    404    return NULL;
    405 }
    406 
    407 /*
    408 * Build get a certificate from a private key
    409 */
    410 CERTCertificate *
    411 PK11_GetCertFromPrivateKey(SECKEYPrivateKey *privKey)
    412 {
    413    PK11SlotInfo *slot = privKey->pkcs11Slot;
    414    CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
    415    CK_OBJECT_HANDLE certID =
    416        PK11_MatchItem(slot, handle, CKO_CERTIFICATE);
    417    CERTCertificate *cert;
    418 
    419    if (certID == CK_INVALID_HANDLE) {
    420        PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
    421        return NULL;
    422    }
    423    cert = PK11_MakeCertFromHandle(slot, certID, NULL);
    424    return (cert);
    425 }
    426 
    427 CK_OBJECT_HANDLE *
    428 PK11_FindCertHandlesForKeyHandle(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle,
    429                                 int *certHandleCountOut)
    430 {
    431    if (!slot || !certHandleCountOut || keyHandle == CK_INVALID_HANDLE) {
    432        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    433        return NULL;
    434    }
    435 
    436    PORTCheapArenaPool arena;
    437    PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
    438    CK_ATTRIBUTE idTemplate[] = {
    439        { CKA_ID, NULL, 0 },
    440    };
    441    const int idAttrCount = sizeof(idTemplate) / sizeof(idTemplate[0]);
    442    CK_RV crv = PK11_GetAttributes(&arena.arena, slot, keyHandle, idTemplate, idAttrCount);
    443    if (crv != CKR_OK) {
    444        PORT_DestroyCheapArena(&arena);
    445        PORT_SetError(PK11_MapError(crv));
    446        return NULL;
    447    }
    448 
    449    if ((idTemplate[0].ulValueLen == 0) || (idTemplate[0].ulValueLen == -1)) {
    450        PORT_DestroyCheapArena(&arena);
    451        PORT_SetError(SEC_ERROR_BAD_KEY);
    452        return NULL;
    453    }
    454 
    455    CK_OBJECT_CLASS searchClass = CKO_CERTIFICATE;
    456    CK_ATTRIBUTE searchTemplate[] = {
    457        idTemplate[0],
    458        { CKA_CLASS, &searchClass, sizeof(searchClass) }
    459    };
    460    const size_t searchAttrCount = sizeof(searchTemplate) / sizeof(searchTemplate[0]);
    461    CK_OBJECT_HANDLE *ids = pk11_FindObjectsByTemplate(slot, searchTemplate, searchAttrCount, certHandleCountOut);
    462 
    463    PORT_DestroyCheapArena(&arena);
    464    return ids;
    465 }
    466 
    467 CERTCertList *
    468 PK11_GetCertsMatchingPrivateKey(SECKEYPrivateKey *privKey)
    469 {
    470    if (!privKey) {
    471        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    472        return NULL;
    473    }
    474    CERTCertList *certs = CERT_NewCertList();
    475    if (!certs) {
    476        PORT_SetError(SEC_ERROR_NO_MEMORY);
    477        return NULL;
    478    }
    479    PK11SlotInfo *slot = privKey->pkcs11Slot;
    480    CK_OBJECT_HANDLE handle = privKey->pkcs11ID;
    481    CK_OBJECT_HANDLE certID = PK11_MatchItem(slot, handle, CKO_CERTIFICATE);
    482    /* If we can't get a matching certID, there are no matching certificates,
    483     * which is not an error. */
    484    if (certID == CK_INVALID_HANDLE) {
    485        return certs;
    486    }
    487    int certHandleCount = 0;
    488    CK_OBJECT_HANDLE *certHandles = PK11_FindCertHandlesForKeyHandle(slot, handle, &certHandleCount);
    489    if (!certHandles) {
    490        /* If certHandleCount is 0, there are no matching certificates, which is
    491         * not an error. */
    492        if (certHandleCount == 0) {
    493            return certs;
    494        }
    495        CERT_DestroyCertList(certs);
    496        return NULL;
    497    }
    498    int i;
    499    for (i = 0; i < certHandleCount; i++) {
    500        CERTCertificate *cert = PK11_MakeCertFromHandle(slot, certHandles[i], NULL);
    501        /* If PK11_MakeCertFromHandle fails for one handle, optimistically
    502           assume other handles may succeed (i.e. this is best-effort). */
    503        if (!cert) {
    504            continue;
    505        }
    506        if (CERT_AddCertToListTail(certs, cert) != SECSuccess) {
    507            CERT_DestroyCertificate(cert);
    508        }
    509    }
    510    PORT_Free(certHandles);
    511    return certs;
    512 }
    513 
    514 /*
    515 * delete a cert and it's private key (if no other certs are pointing to the
    516 * private key.
    517 */
    518 SECStatus
    519 PK11_DeleteTokenCertAndKey(CERTCertificate *cert, void *wincx)
    520 {
    521    SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(cert, wincx);
    522    CK_OBJECT_HANDLE pubKey;
    523    PK11SlotInfo *slot = NULL;
    524 
    525    pubKey = pk11_FindPubKeyByAnyCert(cert, &slot, wincx);
    526    if (privKey) {
    527        /* For 3.4, utilize the generic cert delete function */
    528        SEC_DeletePermCertificate(cert);
    529        PK11_DeleteTokenPrivateKey(privKey, PR_FALSE);
    530    }
    531    if ((pubKey != CK_INVALID_HANDLE) && (slot != NULL)) {
    532        PK11_DestroyTokenObject(slot, pubKey);
    533        PK11_FreeSlot(slot);
    534    }
    535    return SECSuccess;
    536 }
    537 
    538 /*
    539 * cert callback structure
    540 */
    541 typedef struct pk11DoCertCallbackStr {
    542    SECStatus (*callback)(PK11SlotInfo *slot, CERTCertificate *, void *);
    543    SECStatus (*noslotcallback)(CERTCertificate *, void *);
    544    SECStatus (*itemcallback)(CERTCertificate *, SECItem *, void *);
    545    void *callbackArg;
    546 } pk11DoCertCallback;
    547 
    548 typedef struct pk11CertCallbackStr {
    549    SECStatus (*callback)(CERTCertificate *, SECItem *, void *);
    550    void *callbackArg;
    551 } pk11CertCallback;
    552 
    553 struct fake_der_cb_argstr {
    554    SECStatus (*callback)(CERTCertificate *, SECItem *, void *);
    555    void *arg;
    556 };
    557 
    558 static SECStatus
    559 fake_der_cb(CERTCertificate *c, void *a)
    560 {
    561    struct fake_der_cb_argstr *fda = (struct fake_der_cb_argstr *)a;
    562    return (*fda->callback)(c, &c->derCert, fda->arg);
    563 }
    564 
    565 /*
    566 * Extract all the certs on a card from a slot.
    567 */
    568 SECStatus
    569 PK11_TraverseSlotCerts(SECStatus (*callback)(CERTCertificate *, SECItem *, void *),
    570                       void *arg, void *wincx)
    571 {
    572    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
    573    struct fake_der_cb_argstr fda;
    574    struct nss3_cert_cbstr pk11cb;
    575 
    576    /* authenticate to the tokens first */
    577    (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, wincx);
    578 
    579    fda.callback = callback;
    580    fda.arg = arg;
    581    pk11cb.callback = fake_der_cb;
    582    pk11cb.arg = &fda;
    583    NSSTrustDomain_TraverseCertificates(defaultTD, convert_cert, &pk11cb);
    584    return SECSuccess;
    585 }
    586 
    587 static void
    588 transfer_token_certs_to_collection(nssList *certList, NSSToken *token,
    589                                   nssPKIObjectCollection *collection)
    590 {
    591    NSSCertificate **certs;
    592    PRUint32 i, count;
    593    NSSToken **tokens, **tp;
    594    count = nssList_Count(certList);
    595    if (count == 0) {
    596        return;
    597    }
    598    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
    599    if (!certs) {
    600        return;
    601    }
    602    nssList_GetArray(certList, (void **)certs, count);
    603    for (i = 0; i < count; i++) {
    604        tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
    605        if (tokens) {
    606            for (tp = tokens; *tp; tp++) {
    607                if (*tp == token) {
    608                    nssPKIObjectCollection_AddObject(collection,
    609                                                     (nssPKIObject *)certs[i]);
    610                }
    611            }
    612            nssTokenArray_Destroy(tokens);
    613        }
    614        CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
    615    }
    616    nss_ZFreeIf(certs);
    617 }
    618 
    619 static void
    620 transfer_uri_certs_to_collection(nssList *certList, PK11URI *uri,
    621                                 nssPKIObjectCollection *collection)
    622 {
    623 
    624    NSSCertificate **certs;
    625    PRUint32 i, count;
    626    NSSToken **tokens, **tp;
    627    PK11SlotInfo *slot;
    628    const SECItem *id;
    629 
    630    count = nssList_Count(certList);
    631    if (count == 0) {
    632        return;
    633    }
    634    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
    635    if (!certs) {
    636        return;
    637    }
    638    id = PK11URI_GetPathAttributeItem(uri, PK11URI_PATTR_ID);
    639    nssList_GetArray(certList, (void **)certs, count);
    640    for (i = 0; i < count; i++) {
    641        /*
    642         * Filter the subject matched certs based on the
    643         * CKA_ID from the URI
    644         */
    645        if (id && (id->len != certs[i]->id.size ||
    646                   memcmp(id, certs[i]->id.data, certs[i]->id.size)))
    647            continue;
    648        tokens = nssPKIObject_GetTokens(&certs[i]->object, NULL);
    649        if (tokens) {
    650            for (tp = tokens; *tp; tp++) {
    651                const char *value;
    652                slot = (*tp)->pk11slot;
    653 
    654                value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TOKEN);
    655                if (value &&
    656                    !pk11_MatchString(value,
    657                                      (char *)slot->tokenInfo.label,
    658                                      sizeof(slot->tokenInfo.label))) {
    659                    continue;
    660                }
    661 
    662                value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MANUFACTURER);
    663                if (value &&
    664                    !pk11_MatchString(value,
    665                                      (char *)slot->tokenInfo.manufacturerID,
    666                                      sizeof(slot->tokenInfo.manufacturerID))) {
    667                    continue;
    668                }
    669 
    670                value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MODEL);
    671                if (value &&
    672                    !pk11_MatchString(value,
    673                                      (char *)slot->tokenInfo.model,
    674                                      sizeof(slot->tokenInfo.model))) {
    675                    continue;
    676                }
    677 
    678                value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_SERIAL);
    679                if (value &&
    680                    !pk11_MatchString(value,
    681                                      (char *)slot->tokenInfo.serialNumber,
    682                                      sizeof(slot->tokenInfo.serialNumber))) {
    683                    continue;
    684                }
    685 
    686                nssPKIObjectCollection_AddObject(collection,
    687                                                 (nssPKIObject *)certs[i]);
    688                break;
    689            }
    690            nssTokenArray_Destroy(tokens);
    691        }
    692        CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(certs[i]));
    693    }
    694    nss_ZFreeIf(certs);
    695 }
    696 
    697 static NSSCertificate **
    698 find_certs_from_uri(const char *uriString, void *wincx)
    699 {
    700    PK11URI *uri = NULL;
    701    CK_ATTRIBUTE attributes[10];
    702    CK_ULONG nattributes = 0;
    703    const SECItem *id;
    704    const char *label, *type;
    705    PK11SlotInfo *slotinfo;
    706    nssCryptokiObject **instances;
    707    PRStatus status;
    708    nssPKIObjectCollection *collection = NULL;
    709    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
    710    NSSCertificate **certs = NULL;
    711    nssList *certList = NULL;
    712    SECStatus rv;
    713    CK_OBJECT_CLASS s_class = CKO_CERTIFICATE;
    714    static const CK_BBOOL s_true = CK_TRUE;
    715    NSSToken **tokens, **tok;
    716 
    717    uri = PK11URI_ParseURI(uriString);
    718    if (uri == NULL) {
    719        goto loser;
    720    }
    721 
    722    collection = nssCertificateCollection_Create(defaultTD, NULL);
    723    if (!collection) {
    724        goto loser;
    725    }
    726    certList = nssList_Create(NULL, PR_FALSE);
    727    if (!certList) {
    728        goto loser;
    729    }
    730 
    731    /* if the "type" attribute is specified its value must be "cert" */
    732    type = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TYPE);
    733    if (type && strcmp(type, "cert")) {
    734        goto loser;
    735    }
    736 
    737    label = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_OBJECT);
    738    if (label) {
    739        (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
    740                                                          label,
    741                                                          certList);
    742    } else {
    743        (void)nssTrustDomain_GetCertsFromCache(defaultTD, certList);
    744    }
    745 
    746    transfer_uri_certs_to_collection(certList, uri, collection);
    747 
    748    /* add the CKA_CLASS and CKA_TOKEN attributes manually */
    749    attributes[nattributes].type = CKA_CLASS;
    750    attributes[nattributes].pValue = (void *)&s_class;
    751    attributes[nattributes].ulValueLen = sizeof(s_class);
    752    nattributes++;
    753 
    754    attributes[nattributes].type = CKA_TOKEN;
    755    attributes[nattributes].pValue = (void *)&s_true;
    756    attributes[nattributes].ulValueLen = sizeof(s_true);
    757    nattributes++;
    758 
    759    if (label) {
    760        attributes[nattributes].type = CKA_LABEL;
    761        attributes[nattributes].pValue = (void *)label;
    762        attributes[nattributes].ulValueLen = strlen(label);
    763        nattributes++;
    764    }
    765 
    766    id = PK11URI_GetPathAttributeItem(uri, PK11URI_PATTR_ID);
    767    if (id) {
    768        attributes[nattributes].type = CKA_ID;
    769        attributes[nattributes].pValue = (void *)id->data;
    770        attributes[nattributes].ulValueLen = id->len;
    771        nattributes++;
    772    }
    773 
    774    tokens = NSSTrustDomain_FindTokensByURI(defaultTD, uri);
    775    for (tok = tokens; tok && *tok; tok++) {
    776        if (nssToken_IsPresent(*tok)) {
    777            slotinfo = (*tok)->pk11slot;
    778 
    779            rv = pk11_AuthenticateUnfriendly(slotinfo, PR_TRUE, wincx);
    780            if (rv != SECSuccess) {
    781                continue;
    782            }
    783            instances = nssToken_FindObjectsByTemplate(*tok, NULL,
    784                                                       attributes,
    785                                                       nattributes,
    786                                                       0, &status);
    787            nssPKIObjectCollection_AddInstances(collection, instances, 0);
    788            nss_ZFreeIf(instances);
    789        }
    790        (void)nssToken_Destroy(*tok);
    791    }
    792    nss_ZFreeIf(tokens);
    793    nssList_Destroy(certList);
    794    certs = nssPKIObjectCollection_GetCertificates(collection, NULL, 0, NULL);
    795 
    796 loser:
    797    if (collection) {
    798        nssPKIObjectCollection_Destroy(collection);
    799    }
    800    if (uri) {
    801        PK11URI_DestroyURI(uri);
    802    }
    803    return certs;
    804 }
    805 
    806 CERTCertificate *
    807 PK11_FindCertFromURI(const char *uri, void *wincx)
    808 {
    809    static const NSSUsage usage = { PR_TRUE /* ... */ };
    810    NSSCertificate *cert = NULL;
    811    NSSCertificate **certs = NULL;
    812    CERTCertificate *rvCert = NULL;
    813 
    814    certs = find_certs_from_uri(uri, wincx);
    815    if (certs) {
    816        cert = nssCertificateArray_FindBestCertificate(certs, NULL,
    817                                                       &usage, NULL);
    818        if (cert) {
    819            rvCert = STAN_GetCERTCertificateOrRelease(cert);
    820        }
    821        nssCertificateArray_Destroy(certs);
    822    }
    823    return rvCert;
    824 }
    825 
    826 CERTCertList *
    827 PK11_FindCertsFromURI(const char *uri, void *wincx)
    828 {
    829    int i;
    830    CERTCertList *certList = NULL;
    831    NSSCertificate **foundCerts;
    832    NSSCertificate *c;
    833 
    834    foundCerts = find_certs_from_uri(uri, wincx);
    835    if (foundCerts) {
    836        PRTime now = PR_Now();
    837        certList = CERT_NewCertList();
    838        for (i = 0, c = *foundCerts; c; c = foundCerts[++i]) {
    839            if (certList) {
    840                CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
    841                /* c may be invalid after this, don't reference it */
    842                if (certCert) {
    843                    /* CERT_AddCertToListSorted adopts certCert  */
    844                    CERT_AddCertToListSorted(certList, certCert,
    845                                             CERT_SortCBValidity, &now);
    846                }
    847            } else {
    848                nssCertificate_Destroy(c);
    849            }
    850        }
    851        if (certList && CERT_LIST_HEAD(certList) == NULL) {
    852            CERT_DestroyCertList(certList);
    853            certList = NULL;
    854        }
    855        /* all the certs have been adopted or freed, free the  raw array */
    856        nss_ZFreeIf(foundCerts);
    857    }
    858    return certList;
    859 }
    860 
    861 static NSSCertificate **
    862 find_certs_from_nickname(const char *nickname, void *wincx)
    863 {
    864    PRStatus status;
    865    NSSCertificate **certs = NULL;
    866    NSSToken *token = NULL;
    867    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
    868    PK11SlotInfo *slot = NULL;
    869    SECStatus rv;
    870    char *nickCopy;
    871    char *delimit = NULL;
    872    char *tokenName;
    873 
    874    if (!PORT_Strncasecmp(nickname, "pkcs11:", strlen("pkcs11:"))) {
    875        certs = find_certs_from_uri(nickname, wincx);
    876        if (certs)
    877            return certs;
    878    }
    879    nickCopy = PORT_Strdup(nickname);
    880    if (!nickCopy) {
    881        /* error code is set */
    882        return NULL;
    883    }
    884    if ((delimit = PORT_Strchr(nickCopy, ':')) != NULL) {
    885        tokenName = nickCopy;
    886        nickname = delimit + 1;
    887        *delimit = '\0';
    888        /* find token by name */
    889        token = NSSTrustDomain_FindTokenByName(defaultTD, (NSSUTF8 *)tokenName);
    890        if (token) {
    891            slot = PK11_ReferenceSlot(token->pk11slot);
    892        } else {
    893            PORT_SetError(SEC_ERROR_NO_TOKEN);
    894        }
    895        *delimit = ':';
    896    } else {
    897        slot = PK11_GetInternalKeySlot();
    898        token = PK11Slot_GetNSSToken(slot);
    899        if (!token) {
    900            PORT_SetError(SEC_ERROR_NO_TOKEN);
    901        }
    902    }
    903    if (token) {
    904        nssList *certList;
    905        nssCryptokiObject **instances;
    906        nssPKIObjectCollection *collection;
    907        nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
    908        if (!PK11_IsPresent(slot)) {
    909            goto loser;
    910        }
    911        rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
    912        if (rv != SECSuccess) {
    913            goto loser;
    914        }
    915        collection = nssCertificateCollection_Create(defaultTD, NULL);
    916        if (!collection) {
    917            goto loser;
    918        }
    919        certList = nssList_Create(NULL, PR_FALSE);
    920        if (!certList) {
    921            nssPKIObjectCollection_Destroy(collection);
    922            goto loser;
    923        }
    924        (void)nssTrustDomain_GetCertsForNicknameFromCache(defaultTD,
    925                                                          nickname,
    926                                                          certList);
    927        transfer_token_certs_to_collection(certList, token, collection);
    928        instances = nssToken_FindCertificatesByNickname(token,
    929                                                        NULL,
    930                                                        nickname,
    931                                                        tokenOnly,
    932                                                        0,
    933                                                        &status);
    934        nssPKIObjectCollection_AddInstances(collection, instances, 0);
    935        nss_ZFreeIf(instances);
    936        /* if it wasn't found, repeat the process for email address */
    937        if (nssPKIObjectCollection_Count(collection) == 0 &&
    938            PORT_Strchr(nickname, '@') != NULL) {
    939            char *lowercaseName = CERT_FixupEmailAddr(nickname);
    940            if (lowercaseName) {
    941                (void)nssTrustDomain_GetCertsForEmailAddressFromCache(defaultTD,
    942                                                                      lowercaseName,
    943                                                                      certList);
    944                transfer_token_certs_to_collection(certList, token, collection);
    945                instances = nssToken_FindCertificatesByEmail(token,
    946                                                             NULL,
    947                                                             lowercaseName,
    948                                                             tokenOnly,
    949                                                             0,
    950                                                             &status);
    951                nssPKIObjectCollection_AddInstances(collection, instances, 0);
    952                nss_ZFreeIf(instances);
    953                PORT_Free(lowercaseName);
    954            }
    955        }
    956        certs = nssPKIObjectCollection_GetCertificates(collection,
    957                                                       NULL, 0, NULL);
    958        nssPKIObjectCollection_Destroy(collection);
    959        nssList_Destroy(certList);
    960    }
    961 loser:
    962    if (token) {
    963        (void)nssToken_Destroy(token);
    964    }
    965    if (slot) {
    966        PK11_FreeSlot(slot);
    967    }
    968    if (nickCopy)
    969        PORT_Free(nickCopy);
    970    return certs;
    971 }
    972 
    973 CERTCertificate *
    974 PK11_FindCertFromNickname(const char *nickname, void *wincx)
    975 {
    976    CERTCertificate *rvCert = NULL;
    977    NSSCertificate *cert = NULL;
    978    NSSCertificate **certs = NULL;
    979    static const NSSUsage usage = { PR_TRUE /* ... */ };
    980 
    981    certs = find_certs_from_nickname(nickname, wincx);
    982    if (certs) {
    983        cert = nssCertificateArray_FindBestCertificate(certs, NULL,
    984                                                       &usage, NULL);
    985        if (cert) {
    986            rvCert = STAN_GetCERTCertificateOrRelease(cert);
    987        }
    988        nssCertificateArray_Destroy(certs);
    989    }
    990    return rvCert;
    991 }
    992 
    993 /* Traverse slots callback */
    994 typedef struct FindCertsEmailArgStr {
    995    char *email;
    996    CERTCertList *certList;
    997 } FindCertsEmailArg;
    998 
    999 SECStatus
   1000 FindCertsEmailCallback(CERTCertificate *cert, SECItem *item, void *arg)
   1001 {
   1002    FindCertsEmailArg *cbparam = (FindCertsEmailArg *)arg;
   1003    const char *cert_email = CERT_GetFirstEmailAddress(cert);
   1004    PRBool found = PR_FALSE;
   1005 
   1006    /* Email address present in certificate? */
   1007    if (cert_email == NULL) {
   1008        return SECSuccess;
   1009    }
   1010 
   1011    /* Parameter correctly set? */
   1012    if (cbparam->email == NULL) {
   1013        return SECFailure;
   1014    }
   1015 
   1016    /* Loop over all email addresses */
   1017    do {
   1018        if (!strcmp(cert_email, cbparam->email)) {
   1019            /* found one matching email address */
   1020            PRTime now = PR_Now();
   1021            found = PR_TRUE;
   1022            CERT_AddCertToListSorted(cbparam->certList,
   1023                                     CERT_DupCertificate(cert),
   1024                                     CERT_SortCBValidity, &now);
   1025        }
   1026        cert_email = CERT_GetNextEmailAddress(cert, cert_email);
   1027    } while (cert_email && !found);
   1028 
   1029    return SECSuccess;
   1030 }
   1031 
   1032 /* Find all certificates with matching email address */
   1033 CERTCertList *
   1034 PK11_FindCertsFromEmailAddress(const char *email, void *wincx)
   1035 {
   1036    FindCertsEmailArg cbparam;
   1037    SECStatus rv;
   1038 
   1039    cbparam.certList = CERT_NewCertList();
   1040    if (cbparam.certList == NULL) {
   1041        return NULL;
   1042    }
   1043 
   1044    cbparam.email = CERT_FixupEmailAddr(email);
   1045    if (cbparam.email == NULL) {
   1046        CERT_DestroyCertList(cbparam.certList);
   1047        return NULL;
   1048    }
   1049 
   1050    rv = PK11_TraverseSlotCerts(FindCertsEmailCallback, &cbparam, NULL);
   1051    if (rv != SECSuccess) {
   1052        CERT_DestroyCertList(cbparam.certList);
   1053        PORT_Free(cbparam.email);
   1054        return NULL;
   1055    }
   1056 
   1057    /* empty list? */
   1058    if (CERT_LIST_EMPTY(cbparam.certList)) {
   1059        CERT_DestroyCertList(cbparam.certList);
   1060        cbparam.certList = NULL;
   1061    }
   1062 
   1063    PORT_Free(cbparam.email);
   1064    return cbparam.certList;
   1065 }
   1066 
   1067 CERTCertList *
   1068 PK11_FindCertsFromNickname(const char *nickname, void *wincx)
   1069 {
   1070    int i;
   1071    CERTCertList *certList = NULL;
   1072    NSSCertificate **foundCerts = NULL;
   1073    NSSCertificate *c;
   1074 
   1075    foundCerts = find_certs_from_nickname(nickname, wincx);
   1076    if (foundCerts) {
   1077        PRTime now = PR_Now();
   1078        certList = CERT_NewCertList();
   1079        for (i = 0, c = *foundCerts; c; c = foundCerts[++i]) {
   1080            if (certList) {
   1081                CERTCertificate *certCert = STAN_GetCERTCertificateOrRelease(c);
   1082                /* c may be invalid after this, don't reference it */
   1083                if (certCert) {
   1084                    /* CERT_AddCertToListSorted adopts certCert  */
   1085                    CERT_AddCertToListSorted(certList, certCert,
   1086                                             CERT_SortCBValidity, &now);
   1087                }
   1088            } else {
   1089                nssCertificate_Destroy(c);
   1090            }
   1091        }
   1092        /* all the certs have been adopted or freed, free the  raw array */
   1093        nss_ZFreeIf(foundCerts);
   1094    }
   1095    return certList;
   1096 }
   1097 
   1098 /*
   1099 * extract a key ID for a certificate...
   1100 * NOTE: We call this function from PKCS11.c If we ever use
   1101 * pkcs11 to extract the public key (we currently do not), this will break.
   1102 */
   1103 SECItem *
   1104 PK11_GetPubIndexKeyID(CERTCertificate *cert)
   1105 {
   1106    SECKEYPublicKey *pubk;
   1107    SECItem *newItem = NULL;
   1108 
   1109    pubk = CERT_ExtractPublicKey(cert);
   1110    if (pubk == NULL)
   1111        return NULL;
   1112 
   1113    const SECItem *oldItem = PK11_GetPublicValueFromPublicKey(pubk);
   1114    if (oldItem) {
   1115        newItem = SECITEM_DupItem(oldItem);
   1116    }
   1117 
   1118    SECKEY_DestroyPublicKey(pubk);
   1119    /* make hash of it */
   1120    return newItem;
   1121 }
   1122 
   1123 /*
   1124 * generate a CKA_ID from a certificate.
   1125 */
   1126 SECItem *
   1127 pk11_mkcertKeyID(CERTCertificate *cert)
   1128 {
   1129    SECItem *pubKeyData = PK11_GetPubIndexKeyID(cert);
   1130    SECItem *certCKA_ID;
   1131 
   1132    if (pubKeyData == NULL)
   1133        return NULL;
   1134 
   1135    certCKA_ID = PK11_MakeIDFromPubKey(pubKeyData);
   1136    SECITEM_FreeItem(pubKeyData, PR_TRUE);
   1137    return certCKA_ID;
   1138 }
   1139 
   1140 /*
   1141 * Write the cert into the token.
   1142 */
   1143 SECStatus
   1144 PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert,
   1145                CK_OBJECT_HANDLE key, const char *nickname,
   1146                PRBool includeTrust)
   1147 {
   1148    PRStatus status;
   1149    NSSCertificate *c;
   1150    nssCryptokiObject *keyobj, *certobj;
   1151    NSSToken *token = NULL;
   1152    char *emailAddr = NULL;
   1153    nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
   1154    nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
   1155    SECItem *keyID = pk11_mkcertKeyID(cert);
   1156    if (keyID == NULL) {
   1157        goto loser; /* error code should be set already */
   1158    }
   1159    token = PK11Slot_GetNSSToken(slot);
   1160    if (!token) {
   1161        PORT_SetError(SEC_ERROR_NO_TOKEN);
   1162        goto loser;
   1163    }
   1164 
   1165    if (PK11_IsInternal(slot) && cert->emailAddr && cert->emailAddr[0]) {
   1166        emailAddr = cert->emailAddr;
   1167    }
   1168 
   1169    /* need to get the cert as a stan cert */
   1170    CERT_LockCertTempPerm(cert);
   1171    NSSCertificate *nssCert = cert->nssCertificate;
   1172    CERT_UnlockCertTempPerm(cert);
   1173    if (nssCert) {
   1174        c = nssCert;
   1175    } else {
   1176        c = STAN_GetNSSCertificate(cert);
   1177        if (c == NULL) {
   1178            goto loser;
   1179        }
   1180    }
   1181 
   1182    /* set the id for the cert */
   1183    nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
   1184    if (!c->id.data) {
   1185        goto loser;
   1186    }
   1187 
   1188    if (key != CK_INVALID_HANDLE) {
   1189        /* create an object for the key, ... */
   1190        keyobj = nss_ZNEW(NULL, nssCryptokiObject);
   1191        if (!keyobj) {
   1192            goto loser;
   1193        }
   1194        keyobj->token = nssToken_AddRef(token);
   1195        keyobj->handle = key;
   1196        keyobj->isTokenObject = PR_TRUE;
   1197 
   1198        /* ... in order to set matching attributes for the key */
   1199        status = nssCryptokiPrivateKey_SetCertificate(keyobj, NULL, nickname,
   1200                                                      &c->id, &c->subject);
   1201        nssCryptokiObject_Destroy(keyobj);
   1202        if (status != PR_SUCCESS) {
   1203            goto loser;
   1204        }
   1205    }
   1206 
   1207    /* do the token import */
   1208    certobj = nssToken_ImportCertificate(token, NULL,
   1209                                         NSSCertificateType_PKIX,
   1210                                         &c->id,
   1211                                         nickname,
   1212                                         &c->encoding,
   1213                                         &c->issuer,
   1214                                         &c->subject,
   1215                                         &c->serial,
   1216                                         emailAddr,
   1217                                         PR_TRUE);
   1218    if (!certobj) {
   1219        if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
   1220            PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
   1221            SECITEM_FreeItem(keyID, PR_TRUE);
   1222            return SECFailure;
   1223        }
   1224        goto loser;
   1225    }
   1226 
   1227    if (c->object.cryptoContext) {
   1228        /* Delete the temp instance */
   1229        NSSCryptoContext *cc = c->object.cryptoContext;
   1230        nssCertificateStore_Lock(cc->certStore, &lockTrace);
   1231        nssCertificateStore_RemoveCertLOCKED(cc->certStore, c);
   1232        nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace);
   1233        c->object.cryptoContext = NULL;
   1234        CERT_LockCertTempPerm(cert);
   1235        cert->istemp = PR_FALSE;
   1236        cert->isperm = PR_TRUE;
   1237        CERT_UnlockCertTempPerm(cert);
   1238    }
   1239 
   1240    /* add the new instance to the cert, force an update of the
   1241     * CERTCertificate, and finish
   1242     */
   1243    nssPKIObject_AddInstance(&c->object, certobj);
   1244    /* nssTrustDomain_AddCertsToCache may release a reference to 'c' and
   1245     * replace 'c' with a different value. So we add a reference to 'c' to
   1246     * prevent 'c' from being destroyed. */
   1247    nssCertificate_AddRef(c);
   1248    nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
   1249    (void)STAN_ForceCERTCertificateUpdate(c);
   1250    nssCertificate_Destroy(c);
   1251    SECITEM_FreeItem(keyID, PR_TRUE);
   1252    (void)nssToken_Destroy(token);
   1253    return SECSuccess;
   1254 loser:
   1255    if (token) {
   1256        (void)nssToken_Destroy(token);
   1257    }
   1258    CERT_MapStanError();
   1259    SECITEM_FreeItem(keyID, PR_TRUE);
   1260    if (PORT_GetError() != SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
   1261        PORT_SetError(SEC_ERROR_ADDING_CERT);
   1262    }
   1263    return SECFailure;
   1264 }
   1265 
   1266 SECStatus
   1267 PK11_ImportDERCert(PK11SlotInfo *slot, SECItem *derCert,
   1268                   CK_OBJECT_HANDLE key, char *nickname, PRBool includeTrust)
   1269 {
   1270    CERTCertificate *cert;
   1271    SECStatus rv;
   1272 
   1273    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
   1274                                   derCert, NULL, PR_FALSE, PR_TRUE);
   1275    if (cert == NULL)
   1276        return SECFailure;
   1277 
   1278    rv = PK11_ImportCert(slot, cert, key, nickname, includeTrust);
   1279    CERT_DestroyCertificate(cert);
   1280    return rv;
   1281 }
   1282 
   1283 /*
   1284 * return the private key From a given Cert
   1285 */
   1286 SECKEYPrivateKey *
   1287 PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert,
   1288                            void *wincx)
   1289 {
   1290    int err;
   1291    CK_OBJECT_HANDLE certh;
   1292    CK_OBJECT_HANDLE keyh;
   1293    PRBool needLogin;
   1294    SECStatus rv;
   1295 
   1296    certh = PK11_FindCertInSlot(slot, cert, wincx);
   1297    if (certh == CK_INVALID_HANDLE) {
   1298        return NULL;
   1299    }
   1300    /*
   1301     * prevent a login race condition. If slot is logged in between
   1302     * our call to pk11_LoginStillRequired and the
   1303     * PK11_MatchItem. The matchItem call will either succeed, or
   1304     * we will call it one more time after calling PK11_Authenticate
   1305     * (which is a noop on an authenticated token).
   1306     */
   1307    needLogin = pk11_LoginStillRequired(slot, wincx);
   1308    keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY);
   1309    if ((keyh == CK_INVALID_HANDLE) && needLogin &&
   1310        (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
   1311         SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
   1312        /* try it again authenticated */
   1313        rv = PK11_Authenticate(slot, PR_TRUE, wincx);
   1314        if (rv != SECSuccess) {
   1315            return NULL;
   1316        }
   1317        keyh = PK11_MatchItem(slot, certh, CKO_PRIVATE_KEY);
   1318    }
   1319    if (keyh == CK_INVALID_HANDLE) {
   1320        return NULL;
   1321    }
   1322    return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyh, wincx);
   1323 }
   1324 
   1325 /*
   1326 * import a cert for a private key we have already generated. Set the label
   1327 * on both to be the nickname. This is for the Key Gen, orphaned key case.
   1328 */
   1329 PK11SlotInfo *
   1330 PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr,
   1331                      void *wincx)
   1332 {
   1333    PK11SlotList *list;
   1334    PK11SlotListElement *le;
   1335    SECItem *keyID;
   1336    CK_OBJECT_HANDLE key;
   1337    PK11SlotInfo *slot = NULL;
   1338    SECStatus rv;
   1339    int err;
   1340 
   1341    keyID = pk11_mkcertKeyID(cert);
   1342    /* get them all! */
   1343    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
   1344    if ((keyID == NULL) || (list == NULL)) {
   1345        if (keyID)
   1346            SECITEM_FreeItem(keyID, PR_TRUE);
   1347        if (list)
   1348            PK11_FreeSlotList(list);
   1349        return NULL;
   1350    }
   1351 
   1352    /* Look for the slot that holds the Key */
   1353    for (le = list->head; le; le = le->next) {
   1354        /*
   1355         * prevent a login race condition. If le->slot is logged in between
   1356         * our call to pk11_LoginStillRequired and the
   1357         * pk11_FindPrivateKeyFromCertID, the find will either succeed, or
   1358         * we will call it one more time after calling PK11_Authenticate
   1359         * (which is a noop on an authenticated token).
   1360         */
   1361        PRBool needLogin = pk11_LoginStillRequired(le->slot, wincx);
   1362        key = pk11_FindPrivateKeyFromCertID(le->slot, keyID);
   1363        if ((key == CK_INVALID_HANDLE) && needLogin &&
   1364            (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
   1365             SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
   1366            /* authenticate and try again */
   1367            rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
   1368            if (rv != SECSuccess)
   1369                continue;
   1370            key = pk11_FindPrivateKeyFromCertID(le->slot, keyID);
   1371        }
   1372        if (key != CK_INVALID_HANDLE) {
   1373            slot = PK11_ReferenceSlot(le->slot);
   1374            if (keyPtr)
   1375                *keyPtr = key;
   1376            break;
   1377        }
   1378    }
   1379 
   1380    SECITEM_FreeItem(keyID, PR_TRUE);
   1381    PK11_FreeSlotList(list);
   1382    return slot;
   1383 }
   1384 /*
   1385 * import a cert for a private key we have already generated. Set the label
   1386 * on both to be the nickname. This is for the Key Gen, orphaned key case.
   1387 */
   1388 PK11SlotInfo *
   1389 PK11_KeyForDERCertExists(SECItem *derCert, CK_OBJECT_HANDLE *keyPtr,
   1390                         void *wincx)
   1391 {
   1392    CERTCertificate *cert;
   1393    PK11SlotInfo *slot = NULL;
   1394 
   1395    /* letting this use go -- the only thing that the cert is used for is
   1396     * to get the ID attribute.
   1397     */
   1398    cert = CERT_DecodeDERCertificate(derCert, PR_FALSE, NULL);
   1399    if (cert == NULL)
   1400        return NULL;
   1401 
   1402    slot = PK11_KeyForCertExists(cert, keyPtr, wincx);
   1403    CERT_DestroyCertificate(cert);
   1404    return slot;
   1405 }
   1406 
   1407 PK11SlotInfo *
   1408 PK11_ImportCertForKey(CERTCertificate *cert, const char *nickname,
   1409                      void *wincx)
   1410 {
   1411    PK11SlotInfo *slot = NULL;
   1412    CK_OBJECT_HANDLE key;
   1413 
   1414    slot = PK11_KeyForCertExists(cert, &key, wincx);
   1415 
   1416    if (slot) {
   1417        if (PK11_ImportCert(slot, cert, key, nickname, PR_FALSE) != SECSuccess) {
   1418            PK11_FreeSlot(slot);
   1419            slot = NULL;
   1420        }
   1421    } else {
   1422        PORT_SetError(SEC_ERROR_ADDING_CERT);
   1423    }
   1424 
   1425    return slot;
   1426 }
   1427 
   1428 PK11SlotInfo *
   1429 PK11_ImportDERCertForKey(SECItem *derCert, char *nickname, void *wincx)
   1430 {
   1431    CERTCertificate *cert;
   1432    PK11SlotInfo *slot = NULL;
   1433 
   1434    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
   1435                                   derCert, NULL, PR_FALSE, PR_TRUE);
   1436    if (cert == NULL)
   1437        return NULL;
   1438 
   1439    slot = PK11_ImportCertForKey(cert, nickname, wincx);
   1440    CERT_DestroyCertificate(cert);
   1441    return slot;
   1442 }
   1443 
   1444 static CK_OBJECT_HANDLE
   1445 pk11_FindCertObjectByTemplate(PK11SlotInfo **slotPtr,
   1446                              CK_ATTRIBUTE *searchTemplate, size_t count, void *wincx)
   1447 {
   1448    PK11SlotList *list;
   1449    PK11SlotListElement *le;
   1450    CK_OBJECT_HANDLE certHandle = CK_INVALID_HANDLE;
   1451    PK11SlotInfo *slot = NULL;
   1452    SECStatus rv;
   1453 
   1454    *slotPtr = NULL;
   1455 
   1456    /* get them all! */
   1457    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
   1458    if (list == NULL) {
   1459        return CK_INVALID_HANDLE;
   1460    }
   1461 
   1462    /* Look for the slot that holds the Key */
   1463    for (le = list->head; le; le = le->next) {
   1464        rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
   1465        if (rv != SECSuccess)
   1466            continue;
   1467 
   1468        certHandle = pk11_FindObjectByTemplate(le->slot, searchTemplate, count);
   1469        if (certHandle != CK_INVALID_HANDLE) {
   1470            slot = PK11_ReferenceSlot(le->slot);
   1471            break;
   1472        }
   1473    }
   1474 
   1475    PK11_FreeSlotList(list);
   1476 
   1477    if (slot == NULL) {
   1478        return CK_INVALID_HANDLE;
   1479    }
   1480    *slotPtr = slot;
   1481    return certHandle;
   1482 }
   1483 
   1484 CERTCertificate *
   1485 PK11_FindCertByIssuerAndSNOnToken(PK11SlotInfo *slot,
   1486                                  CERTIssuerAndSN *issuerSN, void *wincx)
   1487 {
   1488    CERTCertificate *rvCert = NULL;
   1489    NSSCertificate *cert = NULL;
   1490    NSSDER issuer, serial;
   1491    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
   1492    NSSToken *token = NULL;
   1493    nssSession *session;
   1494    nssCryptokiObject *instance = NULL;
   1495    nssPKIObject *object = NULL;
   1496    SECItem *derSerial;
   1497    PRStatus status;
   1498 
   1499    if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
   1500        !issuerSN->serialNumber.data || !issuerSN->serialNumber.len ||
   1501        issuerSN->derIssuer.len > CERT_MAX_DN_BYTES ||
   1502        issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES) {
   1503        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1504        return NULL;
   1505    }
   1506 
   1507    token = PK11Slot_GetNSSToken(slot);
   1508    if (!token) {
   1509        PORT_SetError(SEC_ERROR_NO_TOKEN);
   1510        return NULL;
   1511    }
   1512 
   1513    session = nssToken_GetDefaultSession(token); /* non-owning */
   1514    if (!session) {
   1515        (void)nssToken_Destroy(token);
   1516        return NULL;
   1517    }
   1518 
   1519    /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
   1520     * CERTIssuerAndSN that actually has the encoded value and pass that
   1521     * to PKCS#11 (and the crypto context).
   1522     */
   1523    derSerial = SEC_ASN1EncodeItem(NULL, NULL,
   1524                                   &issuerSN->serialNumber,
   1525                                   SEC_ASN1_GET(SEC_IntegerTemplate));
   1526    if (!derSerial) {
   1527        (void)nssToken_Destroy(token);
   1528        return NULL;
   1529    }
   1530 
   1531    NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
   1532    NSSITEM_FROM_SECITEM(&serial, derSerial);
   1533 
   1534    instance = nssToken_FindCertificateByIssuerAndSerialNumber(token, session,
   1535                                                               &issuer, &serial, nssTokenSearchType_TokenForced, &status);
   1536 
   1537    (void)nssToken_Destroy(token);
   1538    SECITEM_FreeItem(derSerial, PR_TRUE);
   1539 
   1540    if (!instance) {
   1541        goto loser;
   1542    }
   1543    object = nssPKIObject_Create(NULL, instance, td, NULL, nssPKIMonitor);
   1544    if (!object) {
   1545        goto loser;
   1546    }
   1547    instance = NULL; /* adopted by the previous call */
   1548    cert = nssCertificate_Create(object);
   1549    if (!cert) {
   1550        goto loser;
   1551    }
   1552    object = NULL; /* adopted by the previous call */
   1553    nssTrustDomain_AddCertsToCache(td, &cert, 1);
   1554    /* on failure, cert is freed below */
   1555    rvCert = STAN_GetCERTCertificate(cert);
   1556    if (!rvCert) {
   1557        goto loser;
   1558    }
   1559    return rvCert;
   1560 
   1561 loser:
   1562    if (instance) {
   1563        nssCryptokiObject_Destroy(instance);
   1564    }
   1565    if (object) {
   1566        nssPKIObject_Destroy(object);
   1567    }
   1568    if (cert) {
   1569        nssCertificate_Destroy(cert);
   1570    }
   1571    return NULL;
   1572 }
   1573 
   1574 static PRCallOnceType keyIDHashCallOnce;
   1575 
   1576 static PRStatus PR_CALLBACK
   1577 pk11_keyIDHash_populate(void *wincx)
   1578 {
   1579    CERTCertList *certList;
   1580    CERTCertListNode *node = NULL;
   1581    SECItem subjKeyID = { siBuffer, NULL, 0 };
   1582    SECItem *slotid = NULL;
   1583    SECMODModuleList *modules, *mlp;
   1584    SECMODListLock *moduleLock;
   1585    int i;
   1586 
   1587    certList = PK11_ListCerts(PK11CertListUser, wincx);
   1588    if (!certList) {
   1589        return PR_FAILURE;
   1590    }
   1591 
   1592    for (node = CERT_LIST_HEAD(certList);
   1593         !CERT_LIST_END(node, certList);
   1594         node = CERT_LIST_NEXT(node)) {
   1595        if (CERT_FindSubjectKeyIDExtension(node->cert,
   1596                                           &subjKeyID) == SECSuccess &&
   1597            subjKeyID.data != NULL) {
   1598            cert_AddSubjectKeyIDMapping(&subjKeyID, node->cert);
   1599            SECITEM_FreeItem(&subjKeyID, PR_FALSE);
   1600        }
   1601    }
   1602    CERT_DestroyCertList(certList);
   1603 
   1604    /*
   1605     * Record the state of each slot in a hash. The concatenation of slotID
   1606     * and moduleID is used as its key, with the slot series as its value.
   1607     */
   1608    slotid = SECITEM_AllocItem(NULL, NULL,
   1609                               sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
   1610    if (!slotid) {
   1611        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1612        return PR_FAILURE;
   1613    }
   1614    moduleLock = SECMOD_GetDefaultModuleListLock();
   1615    if (!moduleLock) {
   1616        SECITEM_FreeItem(slotid, PR_TRUE);
   1617        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
   1618        return PR_FAILURE;
   1619    }
   1620    SECMOD_GetReadLock(moduleLock);
   1621    modules = SECMOD_GetDefaultModuleList();
   1622    for (mlp = modules; mlp; mlp = mlp->next) {
   1623        for (i = 0; i < mlp->module->slotCount; i++) {
   1624            memcpy(slotid->data, &mlp->module->slots[i]->slotID,
   1625                   sizeof(CK_SLOT_ID));
   1626            memcpy(&slotid->data[sizeof(CK_SLOT_ID)], &mlp->module->moduleID,
   1627                   sizeof(SECMODModuleID));
   1628            cert_UpdateSubjectKeyIDSlotCheck(slotid,
   1629                                             mlp->module->slots[i]->series);
   1630        }
   1631    }
   1632    SECMOD_ReleaseReadLock(moduleLock);
   1633    SECITEM_FreeItem(slotid, PR_TRUE);
   1634 
   1635    return PR_SUCCESS;
   1636 }
   1637 
   1638 /*
   1639 * We're looking for a cert which we have the private key for that's on the
   1640 * list of recipients. This searches one slot.
   1641 * this is the new version for NSS SMIME code
   1642 * this stuff should REALLY be in the SMIME code, but some things in here are not public
   1643 * (they should be!)
   1644 */
   1645 static CERTCertificate *
   1646 pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipientlist,
   1647                                  int *rlIndex, void *pwarg)
   1648 {
   1649    NSSCMSRecipient *ri = NULL;
   1650    int i;
   1651    PRBool tokenRescanDone = PR_FALSE;
   1652    CERTCertTrust trust;
   1653 
   1654    for (i = 0; (ri = recipientlist[i]) != NULL; i++) {
   1655        CERTCertificate *cert = NULL;
   1656        if (ri->kind == RLSubjKeyID) {
   1657            SECItem *derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
   1658            if (!derCert && !tokenRescanDone) {
   1659                /*
   1660                 * We didn't find the cert by its key ID. If we have slots
   1661                 * with removable tokens, a failure from
   1662                 * cert_FindDERCertBySubjectKeyID doesn't necessarily imply
   1663                 * that the cert is unavailable - the token might simply
   1664                 * have been inserted after the initial run of
   1665                 * pk11_keyIDHash_populate (wrapped by PR_CallOnceWithArg),
   1666                 * or a different token might have been present in that
   1667                 * slot, initially. Let's check for new tokens...
   1668                 */
   1669                PK11SlotList *sl = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
   1670                                                     PR_FALSE, PR_FALSE, pwarg);
   1671                if (sl) {
   1672                    PK11SlotListElement *le;
   1673                    SECItem *slotid = SECITEM_AllocItem(NULL, NULL,
   1674                                                        sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
   1675                    if (!slotid) {
   1676                        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1677                        PK11_FreeSlotList(sl);
   1678                        return NULL;
   1679                    }
   1680                    for (le = sl->head; le; le = le->next) {
   1681                        memcpy(slotid->data, &le->slot->slotID,
   1682                               sizeof(CK_SLOT_ID));
   1683                        memcpy(&slotid->data[sizeof(CK_SLOT_ID)],
   1684                               &le->slot->module->moduleID,
   1685                               sizeof(SECMODModuleID));
   1686                        /*
   1687                         * Any changes with the slot since our last check?
   1688                         * If so, re-read the certs in that specific slot.
   1689                         */
   1690                        if (cert_SubjectKeyIDSlotCheckSeries(slotid) != PK11_GetSlotSeries(le->slot)) {
   1691                            CERTCertListNode *node = NULL;
   1692                            SECItem subjKeyID = { siBuffer, NULL, 0 };
   1693                            CERTCertList *cl = PK11_ListCertsInSlot(le->slot);
   1694                            if (!cl) {
   1695                                continue;
   1696                            }
   1697                            for (node = CERT_LIST_HEAD(cl);
   1698                                 !CERT_LIST_END(node, cl);
   1699                                 node = CERT_LIST_NEXT(node)) {
   1700                                if (CERT_IsUserCert(node->cert) &&
   1701                                    CERT_FindSubjectKeyIDExtension(node->cert,
   1702                                                                   &subjKeyID) == SECSuccess) {
   1703                                    if (subjKeyID.data) {
   1704                                        cert_AddSubjectKeyIDMapping(&subjKeyID,
   1705                                                                    node->cert);
   1706                                        cert_UpdateSubjectKeyIDSlotCheck(slotid,
   1707                                                                         PK11_GetSlotSeries(le->slot));
   1708                                    }
   1709                                    SECITEM_FreeItem(&subjKeyID, PR_FALSE);
   1710                                }
   1711                            }
   1712                            CERT_DestroyCertList(cl);
   1713                        }
   1714                    }
   1715                    PK11_FreeSlotList(sl);
   1716                    SECITEM_FreeItem(slotid, PR_TRUE);
   1717                }
   1718                /* only check once per message/recipientlist */
   1719                tokenRescanDone = PR_TRUE;
   1720                /* do another lookup (hopefully we found that cert...) */
   1721                derCert = cert_FindDERCertBySubjectKeyID(ri->id.subjectKeyID);
   1722            }
   1723            if (derCert) {
   1724                cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
   1725                SECITEM_FreeItem(derCert, PR_TRUE);
   1726            }
   1727        } else {
   1728            cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN,
   1729                                                     pwarg);
   1730        }
   1731        if (cert) {
   1732            /* this isn't our cert */
   1733            if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
   1734                ((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) {
   1735                CERT_DestroyCertificate(cert);
   1736                continue;
   1737            }
   1738            ri->slot = PK11_ReferenceSlot(slot);
   1739            *rlIndex = i;
   1740            return cert;
   1741        }
   1742    }
   1743    *rlIndex = -1;
   1744    return NULL;
   1745 }
   1746 
   1747 /*
   1748 * This function is the same as above, but it searches all the slots.
   1749 * this is the new version for NSS SMIME code
   1750 * this stuff should REALLY be in the SMIME code, but some things in here are not public
   1751 * (they should be!)
   1752 */
   1753 static CERTCertificate *
   1754 pk11_AllFindCertObjectByRecipientNew(NSSCMSRecipient **recipientlist, void *wincx, int *rlIndex)
   1755 {
   1756    PK11SlotList *list;
   1757    PK11SlotListElement *le;
   1758    CERTCertificate *cert = NULL;
   1759    SECStatus rv;
   1760 
   1761    /* get them all! */
   1762    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
   1763    if (list == NULL) {
   1764        return CK_INVALID_HANDLE;
   1765    }
   1766 
   1767    /* Look for the slot that holds the Key */
   1768    for (le = list->head; le; le = le->next) {
   1769        rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
   1770        if (rv != SECSuccess)
   1771            continue;
   1772 
   1773        cert = pk11_FindCertObjectByRecipientNew(le->slot,
   1774                                                 recipientlist, rlIndex, wincx);
   1775        if (cert)
   1776            break;
   1777    }
   1778 
   1779    PK11_FreeSlotList(list);
   1780 
   1781    return cert;
   1782 }
   1783 
   1784 /*
   1785 * We're looking for a cert which we have the private key for that's on the
   1786 * list of recipients. This searches one slot.
   1787 */
   1788 static CERTCertificate *
   1789 pk11_FindCertObjectByRecipient(PK11SlotInfo *slot,
   1790                               SEC_PKCS7RecipientInfo **recipientArray,
   1791                               SEC_PKCS7RecipientInfo **rip, void *pwarg)
   1792 {
   1793    SEC_PKCS7RecipientInfo *ri = NULL;
   1794    CERTCertTrust trust;
   1795    int i;
   1796 
   1797    for (i = 0; (ri = recipientArray[i]) != NULL; i++) {
   1798        CERTCertificate *cert;
   1799 
   1800        cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->issuerAndSN,
   1801                                                 pwarg);
   1802        if (cert) {
   1803            /* this isn't our cert */
   1804            if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
   1805                ((trust.emailFlags & CERTDB_USER) != CERTDB_USER)) {
   1806                CERT_DestroyCertificate(cert);
   1807                continue;
   1808            }
   1809            *rip = ri;
   1810            return cert;
   1811        }
   1812    }
   1813    *rip = NULL;
   1814    return NULL;
   1815 }
   1816 
   1817 /*
   1818 * This function is the same as above, but it searches all the slots.
   1819 */
   1820 static CERTCertificate *
   1821 pk11_AllFindCertObjectByRecipient(PK11SlotInfo **slotPtr,
   1822                                  SEC_PKCS7RecipientInfo **recipientArray,
   1823                                  SEC_PKCS7RecipientInfo **rip,
   1824                                  void *wincx)
   1825 {
   1826    PK11SlotList *list;
   1827    PK11SlotListElement *le;
   1828    CERTCertificate *cert = NULL;
   1829    PK11SlotInfo *slot = NULL;
   1830    SECStatus rv;
   1831 
   1832    *slotPtr = NULL;
   1833 
   1834    /* get them all! */
   1835    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, wincx);
   1836    if (list == NULL) {
   1837        return CK_INVALID_HANDLE;
   1838    }
   1839 
   1840    *rip = NULL;
   1841 
   1842    /* Look for the slot that holds the Key */
   1843    for (le = list->head; le; le = le->next) {
   1844        rv = pk11_AuthenticateUnfriendly(le->slot, PR_TRUE, wincx);
   1845        if (rv != SECSuccess)
   1846            continue;
   1847 
   1848        cert = pk11_FindCertObjectByRecipient(le->slot, recipientArray,
   1849                                              rip, wincx);
   1850        if (cert) {
   1851            slot = PK11_ReferenceSlot(le->slot);
   1852            break;
   1853        }
   1854    }
   1855 
   1856    PK11_FreeSlotList(list);
   1857 
   1858    if (slot == NULL) {
   1859        return NULL;
   1860    }
   1861    *slotPtr = slot;
   1862    PORT_Assert(cert != NULL);
   1863    return cert;
   1864 }
   1865 
   1866 /*
   1867 * We need to invert the search logic for PKCS 7 because if we search for
   1868 * each cert on the list over all the slots, we wind up with lots of spurious
   1869 * password prompts. This way we get only one password prompt per slot, at
   1870 * the max, and most of the time we can find the cert, and only prompt for
   1871 * the key...
   1872 */
   1873 CERTCertificate *
   1874 PK11_FindCertAndKeyByRecipientList(PK11SlotInfo **slotPtr,
   1875                                   SEC_PKCS7RecipientInfo **array,
   1876                                   SEC_PKCS7RecipientInfo **rip,
   1877                                   SECKEYPrivateKey **privKey, void *wincx)
   1878 {
   1879    CERTCertificate *cert = NULL;
   1880 
   1881    *privKey = NULL;
   1882    *slotPtr = NULL;
   1883    cert = pk11_AllFindCertObjectByRecipient(slotPtr, array, rip, wincx);
   1884    if (!cert) {
   1885        return NULL;
   1886    }
   1887 
   1888    *privKey = PK11_FindKeyByAnyCert(cert, wincx);
   1889    if (*privKey == NULL) {
   1890        goto loser;
   1891    }
   1892 
   1893    return cert;
   1894 loser:
   1895    if (cert)
   1896        CERT_DestroyCertificate(cert);
   1897    if (*slotPtr)
   1898        PK11_FreeSlot(*slotPtr);
   1899    *slotPtr = NULL;
   1900    return NULL;
   1901 }
   1902 
   1903 /*
   1904 * This is the new version of the above function for NSS SMIME code
   1905 * this stuff should REALLY be in the SMIME code, but some things in here are not public
   1906 * (they should be!)
   1907 */
   1908 int
   1909 PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *wincx)
   1910 {
   1911    CERTCertificate *cert;
   1912    NSSCMSRecipient *rl;
   1913    PRStatus rv;
   1914    int rlIndex;
   1915 
   1916    rv = PR_CallOnceWithArg(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
   1917    if (rv != PR_SUCCESS)
   1918        return -1;
   1919 
   1920    cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
   1921    if (!cert) {
   1922        return -1;
   1923    }
   1924 
   1925    rl = recipientlist[rlIndex];
   1926 
   1927    /* at this point, rl->slot is set */
   1928 
   1929    rl->privkey = PK11_FindKeyByAnyCert(cert, wincx);
   1930    if (rl->privkey == NULL) {
   1931        goto loser;
   1932    }
   1933 
   1934    /* make a cert from the cert handle */
   1935    rl->cert = cert;
   1936    return rlIndex;
   1937 
   1938 loser:
   1939    if (cert)
   1940        CERT_DestroyCertificate(cert);
   1941    if (rl->slot)
   1942        PK11_FreeSlot(rl->slot);
   1943    rl->slot = NULL;
   1944    return -1;
   1945 }
   1946 
   1947 CERTCertificate *
   1948 PK11_FindCertByIssuerAndSN(PK11SlotInfo **slotPtr, CERTIssuerAndSN *issuerSN,
   1949                           void *wincx)
   1950 {
   1951    CERTCertificate *rvCert = NULL;
   1952    NSSCertificate *cert;
   1953    NSSDER issuer, serial;
   1954    NSSCryptoContext *cc;
   1955    SECItem *derSerial;
   1956 
   1957    if (!issuerSN || !issuerSN->derIssuer.data || !issuerSN->derIssuer.len ||
   1958        !issuerSN->serialNumber.data || !issuerSN->serialNumber.len ||
   1959        issuerSN->derIssuer.len > CERT_MAX_DN_BYTES ||
   1960        issuerSN->serialNumber.len > CERT_MAX_SERIAL_NUMBER_BYTES) {
   1961        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1962        return NULL;
   1963    }
   1964 
   1965    if (slotPtr)
   1966        *slotPtr = NULL;
   1967 
   1968    /* PKCS#11 needs to use DER-encoded serial numbers.  Create a
   1969     * CERTIssuerAndSN that actually has the encoded value and pass that
   1970     * to PKCS#11 (and the crypto context).
   1971     */
   1972    derSerial = SEC_ASN1EncodeItem(NULL, NULL,
   1973                                   &issuerSN->serialNumber,
   1974                                   SEC_ASN1_GET(SEC_IntegerTemplate));
   1975    if (!derSerial) {
   1976        return NULL;
   1977    }
   1978 
   1979    NSSITEM_FROM_SECITEM(&issuer, &issuerSN->derIssuer);
   1980    NSSITEM_FROM_SECITEM(&serial, derSerial);
   1981 
   1982    cc = STAN_GetDefaultCryptoContext();
   1983    cert = NSSCryptoContext_FindCertificateByIssuerAndSerialNumber(cc,
   1984                                                                   &issuer,
   1985                                                                   &serial);
   1986    if (cert) {
   1987        SECITEM_FreeItem(derSerial, PR_TRUE);
   1988        return STAN_GetCERTCertificateOrRelease(cert);
   1989    }
   1990 
   1991    do {
   1992        /* free the old cert on retry. Associated slot was not present */
   1993        if (rvCert) {
   1994            CERT_DestroyCertificate(rvCert);
   1995            rvCert = NULL;
   1996        }
   1997 
   1998        cert = NSSTrustDomain_FindCertificateByIssuerAndSerialNumber(
   1999            STAN_GetDefaultTrustDomain(),
   2000            &issuer,
   2001            &serial);
   2002        if (!cert) {
   2003            break;
   2004        }
   2005 
   2006        rvCert = STAN_GetCERTCertificateOrRelease(cert);
   2007        if (rvCert == NULL) {
   2008            break;
   2009        }
   2010 
   2011        /* Check to see if the cert's token is still there */
   2012    } while (!PK11_IsPresent(rvCert->slot));
   2013 
   2014    if (rvCert && slotPtr)
   2015        *slotPtr = PK11_ReferenceSlot(rvCert->slot);
   2016 
   2017    SECITEM_FreeItem(derSerial, PR_TRUE);
   2018    return rvCert;
   2019 }
   2020 
   2021 CK_OBJECT_HANDLE
   2022 PK11_FindObjectForCert(CERTCertificate *cert, void *wincx, PK11SlotInfo **pSlot)
   2023 {
   2024    CK_OBJECT_HANDLE certHandle;
   2025    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
   2026    CK_ATTRIBUTE *attr;
   2027    CK_ATTRIBUTE searchTemplate[] = {
   2028        { CKA_CLASS, NULL, 0 },
   2029        { CKA_VALUE, NULL, 0 },
   2030    };
   2031    const size_t templateSize = sizeof(searchTemplate) / sizeof(searchTemplate[0]);
   2032 
   2033    attr = searchTemplate;
   2034    PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass));
   2035    attr++;
   2036    PK11_SETATTRS(attr, CKA_VALUE, cert->derCert.data, cert->derCert.len);
   2037 
   2038    if (cert->slot) {
   2039        certHandle = PK11_FindCertInSlot(cert->slot, cert, wincx);
   2040        if (certHandle != CK_INVALID_HANDLE) {
   2041            *pSlot = PK11_ReferenceSlot(cert->slot);
   2042            return certHandle;
   2043        }
   2044    }
   2045 
   2046    certHandle = pk11_FindCertObjectByTemplate(pSlot, searchTemplate,
   2047                                               templateSize, wincx);
   2048    if (certHandle != CK_INVALID_HANDLE) {
   2049        if (cert->slot == NULL) {
   2050            cert->slot = PK11_ReferenceSlot(*pSlot);
   2051            cert->pkcs11ID = certHandle;
   2052            cert->ownSlot = PR_TRUE;
   2053            cert->series = cert->slot->series;
   2054        }
   2055    }
   2056 
   2057    return (certHandle);
   2058 }
   2059 
   2060 SECKEYPrivateKey *
   2061 PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx)
   2062 {
   2063    CK_OBJECT_HANDLE certHandle;
   2064    CK_OBJECT_HANDLE keyHandle;
   2065    PK11SlotInfo *slot = NULL;
   2066    SECKEYPrivateKey *privKey = NULL;
   2067    PRBool needLogin;
   2068    SECStatus rv;
   2069    int err;
   2070 
   2071    certHandle = PK11_FindObjectForCert(cert, wincx, &slot);
   2072    if (certHandle == CK_INVALID_HANDLE) {
   2073        return NULL;
   2074    }
   2075    /*
   2076     * prevent a login race condition. If slot is logged in between
   2077     * our call to pk11_LoginStillRequired and the
   2078     * PK11_MatchItem. The matchItem call will either succeed, or
   2079     * we will call it one more time after calling PK11_Authenticate
   2080     * (which is a noop on an authenticated token).
   2081     */
   2082    needLogin = pk11_LoginStillRequired(slot, wincx);
   2083    keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY);
   2084    if ((keyHandle == CK_INVALID_HANDLE) && needLogin &&
   2085        (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
   2086         SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
   2087        /* authenticate and try again */
   2088        rv = PK11_Authenticate(slot, PR_TRUE, wincx);
   2089        if (rv == SECSuccess) {
   2090            keyHandle = PK11_MatchItem(slot, certHandle, CKO_PRIVATE_KEY);
   2091        }
   2092    }
   2093    if (keyHandle != CK_INVALID_HANDLE) {
   2094        privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
   2095    }
   2096    if (slot) {
   2097        PK11_FreeSlot(slot);
   2098    }
   2099    return privKey;
   2100 }
   2101 
   2102 CK_OBJECT_HANDLE
   2103 pk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx)
   2104 {
   2105    CK_OBJECT_HANDLE certHandle;
   2106    CK_OBJECT_HANDLE keyHandle;
   2107 
   2108    certHandle = PK11_FindObjectForCert(cert, wincx, slot);
   2109    if (certHandle == CK_INVALID_HANDLE) {
   2110        return CK_INVALID_HANDLE;
   2111    }
   2112    keyHandle = PK11_MatchItem(*slot, certHandle, CKO_PUBLIC_KEY);
   2113    if (keyHandle == CK_INVALID_HANDLE) {
   2114        PK11_FreeSlot(*slot);
   2115        return CK_INVALID_HANDLE;
   2116    }
   2117    return keyHandle;
   2118 }
   2119 
   2120 /*
   2121 * find the number of certs in the slot with the same subject name
   2122 */
   2123 int
   2124 PK11_NumberCertsForCertSubject(CERTCertificate *cert)
   2125 {
   2126    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
   2127    CK_ATTRIBUTE theTemplate[] = {
   2128        { CKA_CLASS, NULL, 0 },
   2129        { CKA_SUBJECT, NULL, 0 },
   2130    };
   2131    CK_ATTRIBUTE *attr = theTemplate;
   2132    int templateSize = sizeof(theTemplate) / sizeof(theTemplate[0]);
   2133 
   2134    PK11_SETATTRS(attr, CKA_CLASS, &certClass, sizeof(certClass));
   2135    attr++;
   2136    PK11_SETATTRS(attr, CKA_SUBJECT, cert->derSubject.data, cert->derSubject.len);
   2137 
   2138    if (cert->slot == NULL) {
   2139        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
   2140                                               PR_FALSE, PR_TRUE, NULL);
   2141        PK11SlotListElement *le;
   2142        int count = 0;
   2143 
   2144        if (!list) {
   2145            /* error code is set */
   2146            return 0;
   2147        }
   2148 
   2149        /* loop through all the fortezza tokens */
   2150        for (le = list->head; le; le = le->next) {
   2151            count += PK11_NumberObjectsFor(le->slot, theTemplate, templateSize);
   2152        }
   2153        PK11_FreeSlotList(list);
   2154        return count;
   2155    }
   2156 
   2157    return PK11_NumberObjectsFor(cert->slot, theTemplate, templateSize);
   2158 }
   2159 
   2160 /*
   2161 *  Walk all the certs with the same subject
   2162 */
   2163 SECStatus
   2164 PK11_TraverseCertsForSubject(CERTCertificate *cert,
   2165                             SECStatus (*callback)(CERTCertificate *, void *), void *arg)
   2166 {
   2167    if (!cert) {
   2168        return SECFailure;
   2169    }
   2170    if (cert->slot == NULL) {
   2171        PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,
   2172                                               PR_FALSE, PR_TRUE, NULL);
   2173        PK11SlotListElement *le;
   2174 
   2175        if (!list) {
   2176            /* error code is set */
   2177            return SECFailure;
   2178        }
   2179        /* loop through all the tokens */
   2180        for (le = list->head; le; le = le->next) {
   2181            PK11_TraverseCertsForSubjectInSlot(cert, le->slot, callback, arg);
   2182        }
   2183        PK11_FreeSlotList(list);
   2184        return SECSuccess;
   2185    }
   2186 
   2187    return PK11_TraverseCertsForSubjectInSlot(cert, cert->slot, callback, arg);
   2188 }
   2189 
   2190 SECStatus
   2191 PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert, PK11SlotInfo *slot,
   2192                                   SECStatus (*callback)(CERTCertificate *, void *), void *arg)
   2193 {
   2194    PRStatus nssrv = PR_SUCCESS;
   2195    NSSToken *token;
   2196    NSSDER subject;
   2197    NSSTrustDomain *td;
   2198    nssList *subjectList;
   2199    nssPKIObjectCollection *collection;
   2200    nssCryptokiObject **instances;
   2201    NSSCertificate **certs;
   2202    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
   2203    td = STAN_GetDefaultTrustDomain();
   2204    NSSITEM_FROM_SECITEM(&subject, &cert->derSubject);
   2205    token = PK11Slot_GetNSSToken(slot);
   2206    if (!token) {
   2207        return SECSuccess;
   2208    }
   2209    if (!nssToken_IsPresent(token)) {
   2210        (void)nssToken_Destroy(token);
   2211        return SECSuccess;
   2212    }
   2213    collection = nssCertificateCollection_Create(td, NULL);
   2214    if (!collection) {
   2215        (void)nssToken_Destroy(token);
   2216        return SECFailure;
   2217    }
   2218    subjectList = nssList_Create(NULL, PR_FALSE);
   2219    if (!subjectList) {
   2220        nssPKIObjectCollection_Destroy(collection);
   2221        (void)nssToken_Destroy(token);
   2222        return SECFailure;
   2223    }
   2224    (void)nssTrustDomain_GetCertsForSubjectFromCache(td, &subject,
   2225                                                     subjectList);
   2226    transfer_token_certs_to_collection(subjectList, token, collection);
   2227    instances = nssToken_FindCertificatesBySubject(token, NULL,
   2228                                                   &subject,
   2229                                                   tokenOnly, 0, &nssrv);
   2230    nssPKIObjectCollection_AddInstances(collection, instances, 0);
   2231    nss_ZFreeIf(instances);
   2232    nssList_Destroy(subjectList);
   2233    certs = nssPKIObjectCollection_GetCertificates(collection,
   2234                                                   NULL, 0, NULL);
   2235    nssPKIObjectCollection_Destroy(collection);
   2236    (void)nssToken_Destroy(token);
   2237    if (certs) {
   2238        CERTCertificate *oldie;
   2239        NSSCertificate **cp;
   2240        for (cp = certs; *cp; cp++) {
   2241            oldie = STAN_GetCERTCertificate(*cp);
   2242            if (!oldie) {
   2243                continue;
   2244            }
   2245            if ((*callback)(oldie, arg) != SECSuccess) {
   2246                nssrv = PR_FAILURE;
   2247                break;
   2248            }
   2249        }
   2250        nssCertificateArray_Destroy(certs);
   2251    }
   2252    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
   2253 }
   2254 
   2255 SECStatus
   2256 PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
   2257                                    SECStatus (*callback)(CERTCertificate *, void *), void *arg)
   2258 {
   2259    PRStatus nssrv = PR_SUCCESS;
   2260    NSSToken *token;
   2261    NSSTrustDomain *td;
   2262    NSSUTF8 *nick;
   2263    PRBool created = PR_FALSE;
   2264    nssCryptokiObject **instances;
   2265    nssPKIObjectCollection *collection = NULL;
   2266    NSSCertificate **certs;
   2267    nssList *nameList = NULL;
   2268    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
   2269    token = PK11Slot_GetNSSToken(slot);
   2270    if (!token || !nssToken_IsPresent(token)) {
   2271        (void)nssToken_Destroy(token);
   2272        return SECSuccess;
   2273    }
   2274    if (nickname->data[nickname->len - 1] != '\0') {
   2275        nick = nssUTF8_Create(NULL, nssStringType_UTF8String,
   2276                              nickname->data, nickname->len);
   2277        created = PR_TRUE;
   2278    } else {
   2279        nick = (NSSUTF8 *)nickname->data;
   2280    }
   2281    td = STAN_GetDefaultTrustDomain();
   2282    collection = nssCertificateCollection_Create(td, NULL);
   2283    if (!collection) {
   2284        goto loser;
   2285    }
   2286    nameList = nssList_Create(NULL, PR_FALSE);
   2287    if (!nameList) {
   2288        goto loser;
   2289    }
   2290    (void)nssTrustDomain_GetCertsForNicknameFromCache(td, nick, nameList);
   2291    transfer_token_certs_to_collection(nameList, token, collection);
   2292    instances = nssToken_FindCertificatesByNickname(token, NULL,
   2293                                                    nick,
   2294                                                    tokenOnly, 0, &nssrv);
   2295    nssPKIObjectCollection_AddInstances(collection, instances, 0);
   2296    nss_ZFreeIf(instances);
   2297    nssList_Destroy(nameList);
   2298    certs = nssPKIObjectCollection_GetCertificates(collection,
   2299                                                   NULL, 0, NULL);
   2300    nssPKIObjectCollection_Destroy(collection);
   2301    (void)nssToken_Destroy(token);
   2302    if (certs) {
   2303        CERTCertificate *oldie;
   2304        NSSCertificate **cp;
   2305        for (cp = certs; *cp; cp++) {
   2306            oldie = STAN_GetCERTCertificate(*cp);
   2307            if (!oldie) {
   2308                continue;
   2309            }
   2310            if ((*callback)(oldie, arg) != SECSuccess) {
   2311                nssrv = PR_FAILURE;
   2312                break;
   2313            }
   2314        }
   2315        nssCertificateArray_Destroy(certs);
   2316    }
   2317    if (created)
   2318        nss_ZFreeIf(nick);
   2319    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
   2320 loser:
   2321    (void)nssToken_Destroy(token);
   2322    if (created) {
   2323        nss_ZFreeIf(nick);
   2324    }
   2325    if (collection) {
   2326        nssPKIObjectCollection_Destroy(collection);
   2327    }
   2328    if (nameList) {
   2329        nssList_Destroy(nameList);
   2330    }
   2331    return SECFailure;
   2332 }
   2333 
   2334 SECStatus
   2335 PK11_TraverseCertsInSlot(PK11SlotInfo *slot,
   2336                         SECStatus (*callback)(CERTCertificate *, void *), void *arg)
   2337 {
   2338    PRStatus nssrv;
   2339    NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
   2340    NSSToken *tok;
   2341    nssList *certList = NULL;
   2342    nssCryptokiObject **instances;
   2343    nssPKIObjectCollection *collection;
   2344    NSSCertificate **certs;
   2345    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
   2346    tok = PK11Slot_GetNSSToken(slot);
   2347    if (!tok) {
   2348        return SECSuccess;
   2349    }
   2350    if (!nssToken_IsPresent(tok)) {
   2351        (void)nssToken_Destroy(tok);
   2352        return SECSuccess;
   2353    }
   2354    collection = nssCertificateCollection_Create(td, NULL);
   2355    if (!collection) {
   2356        (void)nssToken_Destroy(tok);
   2357        return SECFailure;
   2358    }
   2359    certList = nssList_Create(NULL, PR_FALSE);
   2360    if (!certList) {
   2361        nssPKIObjectCollection_Destroy(collection);
   2362        (void)nssToken_Destroy(tok);
   2363        return SECFailure;
   2364    }
   2365    (void)nssTrustDomain_GetCertsFromCache(td, certList);
   2366    transfer_token_certs_to_collection(certList, tok, collection);
   2367    instances = nssToken_FindObjects(tok, NULL, CKO_CERTIFICATE,
   2368                                     tokenOnly, 0, &nssrv);
   2369    nssPKIObjectCollection_AddInstances(collection, instances, 0);
   2370    nss_ZFreeIf(instances);
   2371    nssList_Destroy(certList);
   2372    certs = nssPKIObjectCollection_GetCertificates(collection,
   2373                                                   NULL, 0, NULL);
   2374    nssPKIObjectCollection_Destroy(collection);
   2375    (void)nssToken_Destroy(tok);
   2376    if (certs) {
   2377        CERTCertificate *oldie;
   2378        NSSCertificate **cp;
   2379        for (cp = certs; *cp; cp++) {
   2380            oldie = STAN_GetCERTCertificate(*cp);
   2381            if (!oldie) {
   2382                continue;
   2383            }
   2384            if ((*callback)(oldie, arg) != SECSuccess) {
   2385                nssrv = PR_FAILURE;
   2386                break;
   2387            }
   2388        }
   2389        nssCertificateArray_Destroy(certs);
   2390    }
   2391    return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
   2392 }
   2393 
   2394 /*
   2395 * return the certificate associated with a derCert
   2396 */
   2397 CERTCertificate *
   2398 PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
   2399                         void *wincx)
   2400 {
   2401    return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
   2402 }
   2403 
   2404 CERTCertificate *
   2405 PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, const SECItem *inDerCert,
   2406                             void *wincx)
   2407 
   2408 {
   2409    NSSDER derCert;
   2410    NSSToken *tok;
   2411    nssCryptokiObject *co = NULL;
   2412    SECStatus rv;
   2413    CERTCertificate *cert = NULL;
   2414 
   2415    NSSITEM_FROM_SECITEM(&derCert, inDerCert);
   2416    rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
   2417    if (rv != SECSuccess) {
   2418        PK11_FreeSlot(slot);
   2419        return NULL;
   2420    }
   2421 
   2422    tok = PK11Slot_GetNSSToken(slot);
   2423    if (!tok) {
   2424        PK11_FreeSlot(slot);
   2425        return NULL;
   2426    }
   2427    co = nssToken_FindCertificateByEncodedCertificate(tok, NULL, &derCert,
   2428                                                      nssTokenSearchType_TokenOnly, NULL);
   2429    (void)nssToken_Destroy(tok);
   2430 
   2431    if (co) {
   2432        cert = PK11_MakeCertFromHandle(slot, co->handle, NULL);
   2433        nssCryptokiObject_Destroy(co);
   2434    }
   2435 
   2436    return cert;
   2437 }
   2438 
   2439 /*
   2440 * import a cert for a private key we have already generated. Set the label
   2441 * on both to be the nickname.
   2442 */
   2443 static CK_OBJECT_HANDLE
   2444 pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
   2445                            void *wincx)
   2446 {
   2447    SECItem *keyID;
   2448    CK_OBJECT_HANDLE key;
   2449    SECStatus rv;
   2450    PRBool needLogin;
   2451    int err;
   2452 
   2453    if ((slot == NULL) || (cert == NULL)) {
   2454        return CK_INVALID_HANDLE;
   2455    }
   2456 
   2457    keyID = pk11_mkcertKeyID(cert);
   2458    if (keyID == NULL) {
   2459        return CK_INVALID_HANDLE;
   2460    }
   2461 
   2462    /*
   2463     * prevent a login race condition. If slot is logged in between
   2464     * our call to pk11_LoginStillRequired and the
   2465     * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or
   2466     * we will call it one more time after calling PK11_Authenticate
   2467     * (which is a noop on an authenticated token).
   2468     */
   2469    needLogin = pk11_LoginStillRequired(slot, wincx);
   2470    key = pk11_FindPrivateKeyFromCertID(slot, keyID);
   2471    if ((key == CK_INVALID_HANDLE) && needLogin &&
   2472        (SSL_ERROR_NO_CERTIFICATE == (err = PORT_GetError()) ||
   2473         SEC_ERROR_TOKEN_NOT_LOGGED_IN == err)) {
   2474        /* authenticate and try again */
   2475        rv = PK11_Authenticate(slot, PR_TRUE, wincx);
   2476        if (rv != SECSuccess)
   2477            goto loser;
   2478        key = pk11_FindPrivateKeyFromCertID(slot, keyID);
   2479    }
   2480 
   2481 loser:
   2482    SECITEM_ZfreeItem(keyID, PR_TRUE);
   2483    return key;
   2484 }
   2485 
   2486 SECKEYPrivateKey *
   2487 PK11_FindKeyByDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
   2488                      void *wincx)
   2489 {
   2490    CK_OBJECT_HANDLE keyHandle;
   2491 
   2492    if ((slot == NULL) || (cert == NULL)) {
   2493        return NULL;
   2494    }
   2495 
   2496    keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
   2497    if (keyHandle == CK_INVALID_HANDLE) {
   2498        return NULL;
   2499    }
   2500 
   2501    return PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx);
   2502 }
   2503 
   2504 SECStatus
   2505 PK11_ImportCertForKeyToSlot(PK11SlotInfo *slot, CERTCertificate *cert,
   2506                            char *nickname,
   2507                            PRBool addCertUsage, void *wincx)
   2508 {
   2509    CK_OBJECT_HANDLE keyHandle;
   2510 
   2511    if ((slot == NULL) || (cert == NULL) || (nickname == NULL)) {
   2512        return SECFailure;
   2513    }
   2514 
   2515    keyHandle = pk11_findKeyObjectByDERCert(slot, cert, wincx);
   2516    if (keyHandle == CK_INVALID_HANDLE) {
   2517        return SECFailure;
   2518    }
   2519 
   2520    return PK11_ImportCert(slot, cert, keyHandle, nickname, addCertUsage);
   2521 }
   2522 
   2523 /* remove when the real version comes out */
   2524 #define SEC_OID_MISSI_KEA 300 /* until we have v3 stuff merged */
   2525 PRBool
   2526 KEAPQGCompare(CERTCertificate *server, CERTCertificate *cert)
   2527 {
   2528 
   2529    /* not implemented */
   2530    return PR_FALSE;
   2531 }
   2532 
   2533 PRBool
   2534 PK11_FortezzaHasKEA(CERTCertificate *cert)
   2535 {
   2536    /* look at the subject and see if it is a KEA for MISSI key */
   2537    SECOidData *oid;
   2538    CERTCertTrust trust;
   2539 
   2540    if (CERT_GetCertTrust(cert, &trust) != SECSuccess ||
   2541        ((trust.sslFlags & CERTDB_USER) != CERTDB_USER)) {
   2542        return PR_FALSE;
   2543    }
   2544 
   2545    oid = SECOID_FindOID(&cert->subjectPublicKeyInfo.algorithm.algorithm);
   2546    if (!oid) {
   2547        return PR_FALSE;
   2548    }
   2549 
   2550    return (PRBool)((oid->offset == SEC_OID_MISSI_KEA_DSS_OLD) ||
   2551                    (oid->offset == SEC_OID_MISSI_KEA_DSS) ||
   2552                    (oid->offset == SEC_OID_MISSI_KEA));
   2553 }
   2554 
   2555 /*
   2556 * Find a kea cert on this slot that matches the domain of it's peer
   2557 */
   2558 static CERTCertificate
   2559    *
   2560    pk11_GetKEAMate(PK11SlotInfo *slot, CERTCertificate *peer)
   2561 {
   2562    int i;
   2563    CERTCertificate *returnedCert = NULL;
   2564 
   2565    for (i = 0; i < slot->cert_count; i++) {
   2566        CERTCertificate *cert = slot->cert_array[i];
   2567 
   2568        if (PK11_FortezzaHasKEA(cert) && KEAPQGCompare(peer, cert)) {
   2569            returnedCert = CERT_DupCertificate(cert);
   2570            break;
   2571        }
   2572    }
   2573    return returnedCert;
   2574 }
   2575 
   2576 /*
   2577 * The following is a FORTEZZA only Certificate request. We call this when we
   2578 * are doing a non-client auth SSL connection. We are only interested in the
   2579 * fortezza slots, and we are only interested in certs that share the same root
   2580 * key as the server.
   2581 */
   2582 CERTCertificate *
   2583 PK11_FindBestKEAMatch(CERTCertificate *server, void *wincx)
   2584 {
   2585    PK11SlotList *keaList = PK11_GetAllTokens(CKM_KEA_KEY_DERIVE,
   2586                                              PR_FALSE, PR_TRUE, wincx);
   2587    PK11SlotListElement *le;
   2588    CERTCertificate *returnedCert = NULL;
   2589    SECStatus rv;
   2590 
   2591    if (!keaList) {
   2592        /* error code is set */
   2593        return NULL;
   2594    }
   2595 
   2596    /* loop through all the fortezza tokens */
   2597    for (le = keaList->head; le; le = le->next) {
   2598        rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
   2599        if (rv != SECSuccess)
   2600            continue;
   2601        if (le->slot->session == CK_INVALID_HANDLE) {
   2602            continue;
   2603        }
   2604        returnedCert = pk11_GetKEAMate(le->slot, server);
   2605        if (returnedCert)
   2606            break;
   2607    }
   2608    PK11_FreeSlotList(keaList);
   2609 
   2610    return returnedCert;
   2611 }
   2612 
   2613 /*
   2614 * find a matched pair of kea certs to key exchange parameters from one
   2615 * fortezza card to another as necessary.
   2616 */
   2617 SECStatus
   2618 PK11_GetKEAMatchedCerts(PK11SlotInfo *slot1, PK11SlotInfo *slot2,
   2619                        CERTCertificate **cert1, CERTCertificate **cert2)
   2620 {
   2621    CERTCertificate *returnedCert = NULL;
   2622    int i;
   2623 
   2624    for (i = 0; i < slot1->cert_count; i++) {
   2625        CERTCertificate *cert = slot1->cert_array[i];
   2626 
   2627        if (PK11_FortezzaHasKEA(cert)) {
   2628            returnedCert = pk11_GetKEAMate(slot2, cert);
   2629            if (returnedCert != NULL) {
   2630                *cert2 = returnedCert;
   2631                *cert1 = CERT_DupCertificate(cert);
   2632                return SECSuccess;
   2633            }
   2634        }
   2635    }
   2636    return SECFailure;
   2637 }
   2638 
   2639 CK_OBJECT_HANDLE
   2640 PK11_FindEncodedCertInSlot(PK11SlotInfo *slot, SECItem *derCert, void *wincx)
   2641 {
   2642    if (!slot || !derCert) {
   2643        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2644        return SECFailure;
   2645    }
   2646 
   2647    CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
   2648    CK_ATTRIBUTE theTemplate[] = {
   2649        { CKA_VALUE, NULL, 0 },
   2650        { CKA_CLASS, NULL, 0 }
   2651    };
   2652    const size_t tsize = sizeof(theTemplate) / sizeof(theTemplate[0]);
   2653    CK_ATTRIBUTE *attrs = theTemplate;
   2654 
   2655    PK11_SETATTRS(attrs, CKA_VALUE, derCert->data, derCert->len);
   2656    attrs++;
   2657    PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
   2658 
   2659    SECStatus rv = pk11_AuthenticateUnfriendly(slot, PR_TRUE, wincx);
   2660    if (rv != SECSuccess) {
   2661        return CK_INVALID_HANDLE;
   2662    }
   2663 
   2664    return pk11_FindObjectByTemplate(slot, theTemplate, tsize);
   2665 }
   2666 
   2667 CK_OBJECT_HANDLE
   2668 PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert, void *wincx)
   2669 {
   2670    CK_OBJECT_HANDLE certh;
   2671 
   2672    if (cert->slot == slot) {
   2673        certh = cert->pkcs11ID;
   2674        if ((certh == CK_INVALID_HANDLE) ||
   2675            (cert->series != slot->series)) {
   2676            certh = PK11_FindEncodedCertInSlot(slot, &cert->derCert, wincx);
   2677            cert->pkcs11ID = certh;
   2678            cert->series = slot->series;
   2679        }
   2680    } else {
   2681        certh = PK11_FindEncodedCertInSlot(slot, &cert->derCert, wincx);
   2682    }
   2683    return certh;
   2684 }
   2685 
   2686 /* Looking for PK11_GetKeyIDFromCert?
   2687 * Use PK11_GetLowLevelKeyIDForCert instead.
   2688 */
   2689 
   2690 struct listCertsStr {
   2691    PK11CertListType type;
   2692    CERTCertList *certList;
   2693 };
   2694 
   2695 static PRStatus
   2696 pk11ListCertCallback(NSSCertificate *c, void *arg)
   2697 {
   2698    struct listCertsStr *listCertP = (struct listCertsStr *)arg;
   2699    CERTCertificate *newCert = NULL;
   2700    PK11CertListType type = listCertP->type;
   2701    CERTCertList *certList = listCertP->certList;
   2702    PRBool isUnique = PR_FALSE;
   2703    PRBool isCA = PR_FALSE;
   2704    char *nickname = NULL;
   2705    unsigned int certType;
   2706    SECStatus rv;
   2707 
   2708    if ((type == PK11CertListUnique) || (type == PK11CertListRootUnique) ||
   2709        (type == PK11CertListCAUnique) || (type == PK11CertListUserUnique)) {
   2710        /* only list one instance of each certificate, even if several exist */
   2711        isUnique = PR_TRUE;
   2712    }
   2713    if ((type == PK11CertListCA) || (type == PK11CertListRootUnique) ||
   2714        (type == PK11CertListCAUnique)) {
   2715        isCA = PR_TRUE;
   2716    }
   2717 
   2718    /* if we want user certs and we don't have one skip this cert */
   2719    if (((type == PK11CertListUser) || (type == PK11CertListUserUnique)) &&
   2720        !NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
   2721        return PR_SUCCESS;
   2722    }
   2723 
   2724    /* PK11CertListRootUnique means we want CA certs without a private key.
   2725     * This is for legacy app support . PK11CertListCAUnique should be used
   2726     * instead to get all CA certs, regardless of private key
   2727     */
   2728    if ((type == PK11CertListRootUnique) &&
   2729        NSSCertificate_IsPrivateKeyAvailable(c, NULL, NULL)) {
   2730        return PR_SUCCESS;
   2731    }
   2732 
   2733    /* caller still owns the reference to 'c' */
   2734    newCert = STAN_GetCERTCertificate(c);
   2735    if (!newCert) {
   2736        return PR_SUCCESS;
   2737    }
   2738    /* if we want CA certs and it ain't one, skip it */
   2739    if (isCA && (!CERT_IsCACert(newCert, &certType))) {
   2740        return PR_SUCCESS;
   2741    }
   2742    if (isUnique) {
   2743        CERT_DupCertificate(newCert);
   2744 
   2745        nickname = STAN_GetCERTCertificateName(certList->arena, c);
   2746 
   2747        /* put slot certs at the end */
   2748        if (newCert->slot && !PK11_IsInternal(newCert->slot)) {
   2749            rv = CERT_AddCertToListTailWithData(certList, newCert, nickname);
   2750        } else {
   2751            rv = CERT_AddCertToListHeadWithData(certList, newCert, nickname);
   2752        }
   2753        /* if we didn't add the cert to the list, don't leak it */
   2754        if (rv != SECSuccess) {
   2755            CERT_DestroyCertificate(newCert);
   2756        }
   2757    } else {
   2758        /* add multiple instances to the cert list */
   2759        nssCryptokiObject **ip;
   2760        nssCryptokiObject **instances = nssPKIObject_GetInstances(&c->object);
   2761        if (!instances) {
   2762            return PR_SUCCESS;
   2763        }
   2764        for (ip = instances; *ip; ip++) {
   2765            nssCryptokiObject *instance = *ip;
   2766            PK11SlotInfo *slot = instance->token->pk11slot;
   2767 
   2768            /* put the same CERTCertificate in the list for all instances */
   2769            CERT_DupCertificate(newCert);
   2770 
   2771            nickname = STAN_GetCERTCertificateNameForInstance(
   2772                certList->arena, c, instance);
   2773 
   2774            /* put slot certs at the end */
   2775            if (slot && !PK11_IsInternal(slot)) {
   2776                rv = CERT_AddCertToListTailWithData(certList, newCert, nickname);
   2777            } else {
   2778                rv = CERT_AddCertToListHeadWithData(certList, newCert, nickname);
   2779            }
   2780            /* if we didn't add the cert to the list, don't leak it */
   2781            if (rv != SECSuccess) {
   2782                CERT_DestroyCertificate(newCert);
   2783            }
   2784        }
   2785        nssCryptokiObjectArray_Destroy(instances);
   2786    }
   2787    return PR_SUCCESS;
   2788 }
   2789 
   2790 CERTCertList *
   2791 PK11_ListCerts(PK11CertListType type, void *pwarg)
   2792 {
   2793    NSSTrustDomain *defaultTD = STAN_GetDefaultTrustDomain();
   2794    CERTCertList *certList = NULL;
   2795    struct listCertsStr listCerts;
   2796    certList = CERT_NewCertList();
   2797    listCerts.type = type;
   2798    listCerts.certList = certList;
   2799 
   2800    /* authenticate to the slots */
   2801    (void)pk11_TraverseAllSlots(NULL, NULL, PR_TRUE, pwarg);
   2802    NSSTrustDomain_TraverseCertificates(defaultTD, pk11ListCertCallback,
   2803                                        &listCerts);
   2804    return certList;
   2805 }
   2806 
   2807 SECItem *
   2808 PK11_GetLowLevelKeyIDForCert(PK11SlotInfo *slot,
   2809                             CERTCertificate *cert, void *wincx)
   2810 {
   2811    CK_OBJECT_HANDLE certHandle;
   2812    PK11SlotInfo *slotRef = NULL;
   2813    SECItem *item;
   2814 
   2815    if (slot) {
   2816        certHandle = PK11_FindCertInSlot(slot, cert, wincx);
   2817    } else {
   2818        certHandle = PK11_FindObjectForCert(cert, wincx, &slotRef);
   2819        if (certHandle == CK_INVALID_HANDLE) {
   2820            return pk11_mkcertKeyID(cert);
   2821        }
   2822        slot = slotRef;
   2823    }
   2824 
   2825    if (certHandle == CK_INVALID_HANDLE) {
   2826        return NULL;
   2827    }
   2828 
   2829    item = pk11_GetLowLevelKeyFromHandle(slot, certHandle);
   2830    if (slotRef)
   2831        PK11_FreeSlot(slotRef);
   2832    return item;
   2833 }
   2834 
   2835 /* argument type for listCertsCallback */
   2836 typedef struct {
   2837    CERTCertList *list;
   2838    PK11SlotInfo *slot;
   2839 } ListCertsArg;
   2840 
   2841 static SECStatus
   2842 listCertsCallback(CERTCertificate *cert, void *arg)
   2843 {
   2844    ListCertsArg *cdata = (ListCertsArg *)arg;
   2845    char *nickname = NULL;
   2846    nssCryptokiObject *instance, **ci;
   2847    nssCryptokiObject **instances;
   2848    NSSCertificate *c = STAN_GetNSSCertificate(cert);
   2849    SECStatus rv;
   2850 
   2851    if (c == NULL) {
   2852        return SECFailure;
   2853    }
   2854    instances = nssPKIObject_GetInstances(&c->object);
   2855    if (!instances) {
   2856        return SECFailure;
   2857    }
   2858    instance = NULL;
   2859    for (ci = instances; *ci; ci++) {
   2860        if ((*ci)->token->pk11slot == cdata->slot) {
   2861            instance = *ci;
   2862            break;
   2863        }
   2864    }
   2865    PORT_Assert(instance != NULL);
   2866    if (!instance) {
   2867        nssCryptokiObjectArray_Destroy(instances);
   2868        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   2869        return SECFailure;
   2870    }
   2871    nickname = STAN_GetCERTCertificateNameForInstance(cdata->list->arena,
   2872                                                      c, instance);
   2873    nssCryptokiObjectArray_Destroy(instances);
   2874 
   2875    CERT_DupCertificate(cert);
   2876    rv = CERT_AddCertToListTailWithData(cdata->list, cert, nickname);
   2877    if (rv != SECSuccess) {
   2878        CERT_DestroyCertificate(cert);
   2879    }
   2880    return rv;
   2881 }
   2882 
   2883 CERTCertList *
   2884 PK11_ListCertsInSlot(PK11SlotInfo *slot)
   2885 {
   2886    SECStatus status;
   2887    CERTCertList *certs;
   2888    ListCertsArg cdata;
   2889 
   2890    certs = CERT_NewCertList();
   2891    if (certs == NULL)
   2892        return NULL;
   2893    cdata.list = certs;
   2894    cdata.slot = slot;
   2895 
   2896    status = PK11_TraverseCertsInSlot(slot, listCertsCallback,
   2897                                      &cdata);
   2898 
   2899    if (status != SECSuccess) {
   2900        CERT_DestroyCertList(certs);
   2901        certs = NULL;
   2902    }
   2903 
   2904    return certs;
   2905 }
   2906 
   2907 PK11SlotList *
   2908 PK11_GetAllSlotsForCert(CERTCertificate *cert, void *arg)
   2909 {
   2910    nssCryptokiObject **ip;
   2911    PK11SlotList *slotList;
   2912    NSSCertificate *c;
   2913    nssCryptokiObject **instances;
   2914    PRBool found = PR_FALSE;
   2915 
   2916    if (!cert) {
   2917        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2918        return NULL;
   2919    }
   2920 
   2921    c = STAN_GetNSSCertificate(cert);
   2922    if (!c) {
   2923        CERT_MapStanError();
   2924        return NULL;
   2925    }
   2926 
   2927    /* add multiple instances to the cert list */
   2928    instances = nssPKIObject_GetInstances(&c->object);
   2929    if (!instances) {
   2930        PORT_SetError(SEC_ERROR_NO_TOKEN);
   2931        return NULL;
   2932    }
   2933 
   2934    slotList = PK11_NewSlotList();
   2935    if (!slotList) {
   2936        nssCryptokiObjectArray_Destroy(instances);
   2937        return NULL;
   2938    }
   2939 
   2940    for (ip = instances; *ip; ip++) {
   2941        nssCryptokiObject *instance = *ip;
   2942        PK11SlotInfo *slot = instance->token->pk11slot;
   2943        if (slot) {
   2944            PK11_AddSlotToList(slotList, slot, PR_TRUE);
   2945            found = PR_TRUE;
   2946        }
   2947    }
   2948    if (!found) {
   2949        PK11_FreeSlotList(slotList);
   2950        PORT_SetError(SEC_ERROR_NO_TOKEN);
   2951        slotList = NULL;
   2952    }
   2953 
   2954    nssCryptokiObjectArray_Destroy(instances);
   2955    return slotList;
   2956 }
   2957 
   2958 /*
   2959 * Using __PK11_SetCertificateNickname is *DANGEROUS*.
   2960 *
   2961 * The API will update the NSS database, but it *will NOT* update the in-memory data.
   2962 * As a result, after calling this API, there will be INCONSISTENCY between
   2963 * in-memory data and the database.
   2964 *
   2965 * Use of the API should be limited to short-lived tools, which will exit immediately
   2966 * after using this API.
   2967 *
   2968 * If you ignore this warning, your process is TAINTED and will most likely misbehave.
   2969 */
   2970 SECStatus
   2971 __PK11_SetCertificateNickname(CERTCertificate *cert, const char *nickname)
   2972 {
   2973    /* Can't set nickname of temp cert. */
   2974    if (!cert->slot || cert->pkcs11ID == CK_INVALID_HANDLE) {
   2975        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   2976        return SECFailure;
   2977    }
   2978    return PK11_SetObjectNickname(cert->slot, cert->pkcs11ID, nickname);
   2979 }