Coverage Report

Created: 2026-05-19 06:33

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