Coverage Report

Created: 2018-09-25 14:53

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