Coverage Report

Created: 2026-08-18 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/dev/devtoken.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
#include "pkcs11.h"
6
7
#ifndef DEVM_H
8
#include "devm.h"
9
#endif /* DEVM_H */
10
11
#ifndef CKHELPER_H
12
#include "ckhelper.h"
13
#endif /* CKHELPER_H */
14
15
#include "pk11func.h"
16
#include "dev3hack.h"
17
#include "secerr.h"
18
19
extern const NSSError NSS_ERROR_NOT_FOUND;
20
extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
21
extern const NSSError NSS_ERROR_PKCS11;
22
23
/* The number of object handles to grab during each call to C_FindObjects */
24
1.38M
#define OBJECT_STACK_SIZE 16
25
26
NSS_IMPLEMENT PRStatus
27
nssToken_Destroy(
28
    NSSToken *tok)
29
694k
{
30
694k
    if (tok) {
31
694k
        if (PR_ATOMIC_DECREMENT(&tok->base.refCount) == 0) {
32
28
            PK11_FreeSlot(tok->pk11slot);
33
28
            PR_DestroyLock(tok->base.lock);
34
28
            nssTokenObjectCache_Destroy(tok->cache);
35
28
            (void)nssSlot_Destroy(tok->slot);
36
28
            return nssArena_Destroy(tok->base.arena);
37
28
        }
38
694k
    }
39
694k
    return PR_SUCCESS;
40
694k
}
41
42
NSS_IMPLEMENT void
43
nssToken_Remove(
44
    NSSToken *tok)
45
0
{
46
0
    nssTokenObjectCache_Clear(tok->cache);
47
0
}
48
49
NSS_IMPLEMENT NSSToken *
50
nssToken_AddRef(
51
    NSSToken *tok)
52
694k
{
53
694k
    PR_ATOMIC_INCREMENT(&tok->base.refCount);
54
694k
    return tok;
55
694k
}
56
57
NSS_IMPLEMENT NSSSlot *
58
nssToken_GetSlot(
59
    NSSToken *tok)
60
684k
{
61
684k
    return nssSlot_AddRef(tok->slot);
62
684k
}
63
64
NSS_IMPLEMENT void *
65
nssToken_GetCryptokiEPV(
66
    NSSToken *token)
67
1.36M
{
68
1.36M
    return nssSlot_GetCryptokiEPV(token->slot);
69
1.36M
}
70
71
NSS_IMPLEMENT nssSession *
72
nssToken_GetDefaultSession(
73
    NSSToken *token)
74
215k
{
75
215k
    return token->defaultSession;
76
215k
}
77
78
NSS_IMPLEMENT NSSUTF8 *
79
nssToken_GetName(
80
    NSSToken *tok)
81
0
{
82
0
    if (tok == NULL) {
83
0
        return "";
84
0
    }
85
0
    if (tok->base.name[0] == 0) {
86
0
        (void)nssSlot_IsTokenPresent(tok->slot);
87
0
    }
88
0
    return tok->base.name;
89
0
}
90
91
NSS_IMPLEMENT NSSUTF8 *
92
NSSToken_GetName(
93
    NSSToken *token)
94
0
{
95
0
    return nssToken_GetName(token);
96
0
}
97
98
NSS_IMPLEMENT PRBool
99
nssToken_IsLoginRequired(
100
    NSSToken *token)
101
0
{
102
0
    return (token->ckFlags & CKF_LOGIN_REQUIRED);
103
0
}
104
105
NSS_IMPLEMENT PRBool
106
nssToken_NeedsPINInitialization(
107
    NSSToken *token)
108
0
{
109
0
    return (!(token->ckFlags & CKF_USER_PIN_INITIALIZED));
110
0
}
111
112
NSS_IMPLEMENT PRStatus
113
nssToken_DeleteStoredObject(
114
    nssCryptokiObject *instance)
115
0
{
116
0
    CK_RV ckrv;
117
0
    PRStatus status;
118
0
    PRBool createdSession = PR_FALSE;
119
0
    NSSToken *token = instance->token;
120
0
    nssSession *session = NULL;
121
0
    void *epv = nssToken_GetCryptokiEPV(instance->token);
122
0
    if (token->cache) {
123
0
        nssTokenObjectCache_RemoveObject(token->cache, instance);
124
0
    }
125
0
    if (instance->isTokenObject) {
126
0
        if (token->defaultSession &&
127
0
            nssSession_IsReadWrite(token->defaultSession)) {
128
0
            session = token->defaultSession;
129
0
        } else {
130
0
            session = nssSlot_CreateSession(token->slot, NULL, PR_TRUE);
131
0
            createdSession = PR_TRUE;
132
0
        }
133
0
    }
134
0
    if (session == NULL) {
135
0
        return PR_FAILURE;
136
0
    }
137
0
    nssSession_EnterMonitor(session);
138
0
    ckrv = CKAPI(epv)->C_DestroyObject(session->handle, instance->handle);
139
0
    nssSession_ExitMonitor(session);
140
0
    if (createdSession) {
141
0
        nssSession_Destroy(session);
142
0
    }
143
0
    status = PR_SUCCESS;
144
0
    if (ckrv != CKR_OK) {
145
0
        status = PR_FAILURE;
146
        /* use the error stack to pass the PKCS #11 error out  */
147
0
        nss_SetError(ckrv);
148
0
        nss_SetError(NSS_ERROR_PKCS11);
149
0
    }
150
0
    return status;
151
0
}
152
153
static nssCryptokiObject *
154
import_object(
155
    NSSToken *tok,
156
    nssSession *sessionOpt,
157
    CK_ATTRIBUTE_PTR objectTemplate,
158
    CK_ULONG otsize)
159
0
{
160
0
    nssSession *session = NULL;
161
0
    PRBool createdSession = PR_FALSE;
162
0
    nssCryptokiObject *object = NULL;
163
0
    CK_OBJECT_HANDLE handle;
164
0
    CK_RV ckrv;
165
0
    void *epv = nssToken_GetCryptokiEPV(tok);
166
0
    if (nssCKObject_IsTokenObjectTemplate(objectTemplate, otsize)) {
167
0
        if (sessionOpt) {
168
0
            if (!nssSession_IsReadWrite(sessionOpt)) {
169
0
                nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
170
0
                return NULL;
171
0
            }
172
0
            session = sessionOpt;
173
0
        } else if (tok->defaultSession &&
174
0
                   nssSession_IsReadWrite(tok->defaultSession)) {
175
0
            session = tok->defaultSession;
176
0
        } else {
177
0
            session = nssSlot_CreateSession(tok->slot, NULL, PR_TRUE);
178
0
            createdSession = PR_TRUE;
179
0
        }
180
0
    } else {
181
0
        session = (sessionOpt) ? sessionOpt : tok->defaultSession;
182
0
    }
183
0
    if (session == NULL) {
184
0
        nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
185
0
        return NULL;
186
0
    }
187
0
    nssSession_EnterMonitor(session);
188
0
    ckrv = CKAPI(epv)->C_CreateObject(session->handle,
189
0
                                      objectTemplate, otsize,
190
0
                                      &handle);
191
0
    nssSession_ExitMonitor(session);
192
0
    if (ckrv == CKR_OK) {
193
0
        object = nssCryptokiObject_Create(tok, session, handle);
194
0
    } else {
195
0
        nss_SetError(ckrv);
196
0
        nss_SetError(NSS_ERROR_PKCS11);
197
0
    }
198
0
    if (createdSession) {
199
0
        nssSession_Destroy(session);
200
0
    }
201
0
    return object;
202
0
}
203
204
static nssCryptokiObject **
205
create_objects_from_handles(
206
    NSSToken *tok,
207
    nssSession *session,
208
    CK_OBJECT_HANDLE *handles,
209
    PRUint32 numH)
210
0
{
211
0
    nssCryptokiObject **objects;
212
0
    if (numH == PR_UINT32_MAX) {
213
0
        return NULL; /* avoid overflow in ZNEWARRAY */
214
0
    }
215
0
    objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numH + 1);
216
0
    if (!objects) {
217
0
        return NULL;
218
0
    }
219
0
    for (PRUint32 i = 0; i < numH; i++) {
220
0
        objects[i] = nssCryptokiObject_Create(tok, session, handles[i]);
221
0
        if (!objects[i]) {
222
0
            for (; i > 0; --i) {
223
0
                nssCryptokiObject_Destroy(objects[i - 1]);
224
0
            }
225
0
            nss_ZFreeIf(objects);
226
0
            return NULL;
227
0
        }
228
0
    }
229
0
    return objects;
230
0
}
231
232
static nssCryptokiObject **
233
find_objects(
234
    NSSToken *tok,
235
    nssSession *sessionOpt,
236
    CK_ATTRIBUTE_PTR obj_template,
237
    CK_ULONG otsize,
238
    PRUint32 maximumOpt,
239
    PRStatus *statusOpt)
240
1.36M
{
241
1.36M
    CK_RV ckrv = CKR_OK;
242
1.36M
    CK_ULONG count;
243
1.36M
    CK_OBJECT_HANDLE *objectHandles = NULL;
244
1.36M
    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
245
1.36M
    PRUint32 arraySize, numHandles;
246
1.36M
    void *epv = nssToken_GetCryptokiEPV(tok);
247
1.36M
    nssCryptokiObject **objects;
248
1.36M
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
249
250
    /* Don't ask the module to use an invalid session handle. */
251
1.36M
    if (!session || session->handle == CK_INVALID_HANDLE) {
252
0
        ckrv = CKR_SESSION_HANDLE_INVALID;
253
0
        goto loser;
254
0
    }
255
256
    /* the arena is only for the array of object handles */
257
1.36M
    if (maximumOpt > 0) {
258
1.33M
        arraySize = maximumOpt;
259
1.33M
    } else {
260
25.8k
        arraySize = OBJECT_STACK_SIZE;
261
25.8k
    }
262
1.36M
    numHandles = 0;
263
1.36M
    if (arraySize <= OBJECT_STACK_SIZE) {
264
1.36M
        objectHandles = staticObjects;
265
1.36M
    } else {
266
0
        objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
267
0
    }
268
1.36M
    if (!objectHandles) {
269
0
        ckrv = CKR_HOST_MEMORY;
270
0
        goto loser;
271
0
    }
272
1.36M
    nssSession_EnterMonitor(session); /* ==== session lock === */
273
    /* Initialize the find with the template */
274
1.36M
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
275
1.36M
                                         obj_template, otsize);
276
1.36M
    if (ckrv != CKR_OK) {
277
0
        nssSession_ExitMonitor(session);
278
0
        goto loser;
279
0
    }
280
1.36M
    while (PR_TRUE) {
281
        /* Issue the find for up to arraySize - numHandles objects */
282
1.36M
        ckrv = CKAPI(epv)->C_FindObjects(session->handle,
283
1.36M
                                         objectHandles + numHandles,
284
1.36M
                                         arraySize - numHandles,
285
1.36M
                                         &count);
286
1.36M
        if (ckrv != CKR_OK) {
287
0
            nssSession_ExitMonitor(session);
288
0
            goto loser;
289
0
        }
290
        /* bump the number of found objects */
291
1.36M
        numHandles += count;
292
1.36M
        if (maximumOpt > 0 || numHandles < arraySize) {
293
            /* When a maximum is provided, the search is done all at once,
294
             * so the search is finished.  If the number returned was less
295
             * than the number sought, the search is finished.
296
             */
297
1.36M
            break;
298
1.36M
        }
299
        /* the array is filled, double it and continue */
300
0
        arraySize *= 2;
301
0
        if (objectHandles == staticObjects) {
302
0
            objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
303
0
            if (objectHandles) {
304
0
                PORT_Memcpy(objectHandles, staticObjects,
305
0
                            OBJECT_STACK_SIZE * sizeof(objectHandles[1]));
306
0
            }
307
0
        } else {
308
0
            objectHandles = nss_ZREALLOCARRAY(objectHandles,
309
0
                                              CK_OBJECT_HANDLE,
310
0
                                              arraySize);
311
0
        }
312
0
        if (!objectHandles) {
313
0
            nssSession_ExitMonitor(session);
314
0
            ckrv = CKR_HOST_MEMORY;
315
0
            goto loser;
316
0
        }
317
0
    }
318
1.36M
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
319
1.36M
    nssSession_ExitMonitor(session); /* ==== end session lock === */
320
1.36M
    if (ckrv != CKR_OK) {
321
0
        goto loser;
322
0
    }
323
1.36M
    if (numHandles > 0) {
324
0
        objects = create_objects_from_handles(tok, session,
325
0
                                              objectHandles, numHandles);
326
1.36M
    } else {
327
1.36M
        nss_SetError(NSS_ERROR_NOT_FOUND);
328
1.36M
        objects = NULL;
329
1.36M
    }
330
1.36M
    if (objectHandles && objectHandles != staticObjects) {
331
0
        nss_ZFreeIf(objectHandles);
332
0
    }
333
1.36M
    if (statusOpt)
334
405k
        *statusOpt = PR_SUCCESS;
335
1.36M
    return objects;
336
0
loser:
337
0
    if (objectHandles && objectHandles != staticObjects) {
338
0
        nss_ZFreeIf(objectHandles);
339
0
    }
340
    /*
341
     * These errors should be treated the same as if the objects just weren't
342
     * found..
343
     */
344
0
    if ((ckrv == CKR_ATTRIBUTE_TYPE_INVALID) ||
345
0
        (ckrv == CKR_ATTRIBUTE_VALUE_INVALID) ||
346
0
        (ckrv == CKR_DATA_INVALID) ||
347
0
        (ckrv == CKR_DATA_LEN_RANGE) ||
348
0
        (ckrv == CKR_FUNCTION_NOT_SUPPORTED) ||
349
0
        (ckrv == CKR_TEMPLATE_INCOMPLETE) ||
350
0
        (ckrv == CKR_TEMPLATE_INCONSISTENT)) {
351
352
0
        nss_SetError(NSS_ERROR_NOT_FOUND);
353
0
        if (statusOpt)
354
0
            *statusOpt = PR_SUCCESS;
355
0
    } else {
356
0
        nss_SetError(ckrv);
357
0
        nss_SetError(NSS_ERROR_PKCS11);
358
0
        if (statusOpt)
359
0
            *statusOpt = PR_FAILURE;
360
0
    }
361
0
    return (nssCryptokiObject **)NULL;
362
1.36M
}
363
364
NSS_IMPLEMENT nssCryptokiObject **
365
nssToken_FindObjectsByTemplate(
366
    NSSToken *token,
367
    nssSession *sessionOpt,
368
    CK_ATTRIBUTE_PTR obj_template,
369
    CK_ULONG otsize,
370
    PRUint32 maximumOpt,
371
    PRStatus *statusOpt)
372
1.34M
{
373
1.34M
    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
374
1.34M
    nssCryptokiObject **objects = NULL;
375
1.34M
    PRUint32 i;
376
377
1.34M
    if (!token) {
378
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
379
0
        if (statusOpt)
380
0
            *statusOpt = PR_FAILURE;
381
0
        return NULL;
382
0
    }
383
2.68M
    for (i = 0; i < otsize; i++) {
384
2.68M
        if (obj_template[i].type == CKA_CLASS) {
385
1.34M
            objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
386
1.34M
            break;
387
1.34M
        }
388
2.68M
    }
389
1.34M
    PR_ASSERT(i < otsize);
390
1.34M
    if (i == otsize) {
391
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
392
0
        if (statusOpt)
393
0
            *statusOpt = PR_FAILURE;
394
0
        return NULL;
395
0
    }
396
    /* If these objects are being cached, try looking there first */
397
1.34M
    if (token->cache &&
398
0
        nssTokenObjectCache_HaveObjectClass(token->cache, objclass)) {
399
0
        PRStatus status;
400
0
        objects = nssTokenObjectCache_FindObjectsByTemplate(token->cache,
401
0
                                                            objclass,
402
0
                                                            obj_template,
403
0
                                                            otsize,
404
0
                                                            maximumOpt,
405
0
                                                            &status);
406
0
        if (status == PR_SUCCESS) {
407
0
            if (statusOpt)
408
0
                *statusOpt = status;
409
0
            return objects;
410
0
        }
411
0
    }
412
    /* Either they are not cached, or cache failed; look on token. */
413
1.34M
    objects = find_objects(token, sessionOpt,
414
1.34M
                           obj_template, otsize,
415
1.34M
                           maximumOpt, statusOpt);
416
1.34M
    return objects;
417
1.34M
}
418
419
extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
420
421
NSS_IMPLEMENT nssCryptokiObject *
422
nssToken_ImportCertificate(
423
    NSSToken *tok,
424
    nssSession *sessionOpt,
425
    NSSCertificateType certType,
426
    NSSItem *id,
427
    const NSSUTF8 *nickname,
428
    NSSDER *encoding,
429
    NSSDER *issuer,
430
    NSSDER *subject,
431
    NSSDER *serial,
432
    NSSASCII7 *email,
433
    PRBool asTokenObject)
434
0
{
435
0
    PRStatus status;
436
0
    CK_CERTIFICATE_TYPE cert_type;
437
0
    CK_ATTRIBUTE_PTR attr;
438
0
    CK_ATTRIBUTE cert_tmpl[10];
439
0
    CK_ULONG ctsize;
440
0
    nssTokenSearchType searchType;
441
0
    nssCryptokiObject *rvObject = NULL;
442
443
0
    if (!tok) {
444
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
445
0
        return NULL;
446
0
    }
447
0
    if (certType == NSSCertificateType_PKIX) {
448
0
        cert_type = CKC_X_509;
449
0
    } else {
450
0
        return (nssCryptokiObject *)NULL;
451
0
    }
452
0
    NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
453
0
    if (asTokenObject) {
454
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
455
0
        searchType = nssTokenSearchType_TokenOnly;
456
0
    } else {
457
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
458
0
        searchType = nssTokenSearchType_SessionOnly;
459
0
    }
460
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
461
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CERTIFICATE_TYPE, cert_type);
462
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
463
0
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
464
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
465
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
466
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
467
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
468
0
    if (email) {
469
0
        NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
470
0
    }
471
0
    NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
472
    /* see if the cert is already there */
473
0
    rvObject = nssToken_FindCertificateByIssuerAndSerialNumber(tok,
474
0
                                                               sessionOpt,
475
0
                                                               issuer,
476
0
                                                               serial,
477
0
                                                               searchType,
478
0
                                                               NULL);
479
0
    if (rvObject) {
480
0
        NSSItem existingDER;
481
0
        NSSSlot *slot = nssToken_GetSlot(tok);
482
0
        nssSession *session = nssSlot_CreateSession(slot, NULL, PR_TRUE);
483
0
        if (!session) {
484
0
            nssCryptokiObject_Destroy(rvObject);
485
0
            nssSlot_Destroy(slot);
486
0
            return (nssCryptokiObject *)NULL;
487
0
        }
488
        /* Reject any attempt to import a new cert that has the same
489
         * issuer/serial as an existing cert, but does not have the
490
         * same encoding
491
         */
492
0
        NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
493
0
        NSS_CK_SET_ATTRIBUTE_NULL(attr, CKA_VALUE);
494
0
        NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
495
0
        status = nssCKObject_GetAttributes(rvObject->handle,
496
0
                                           cert_tmpl, ctsize, NULL,
497
0
                                           session, slot);
498
0
        NSS_CK_ATTRIBUTE_TO_ITEM(cert_tmpl, &existingDER);
499
0
        if (status == PR_SUCCESS) {
500
0
            if (!nssItem_Equal(encoding, &existingDER, NULL)) {
501
0
                nss_SetError(NSS_ERROR_INVALID_CERTIFICATE);
502
0
                status = PR_FAILURE;
503
0
            }
504
0
            nss_ZFreeIf(existingDER.data);
505
0
        }
506
0
        if (status == PR_FAILURE) {
507
0
            nssCryptokiObject_Destroy(rvObject);
508
0
            nssSession_Destroy(session);
509
0
            nssSlot_Destroy(slot);
510
0
            return (nssCryptokiObject *)NULL;
511
0
        }
512
        /* according to PKCS#11, label, ID, issuer, and serial number
513
         * may change after the object has been created.  For PKIX, the
514
         * last two attributes can't change, so for now we'll only worry
515
         * about the first two.
516
         */
517
0
        NSS_CK_TEMPLATE_START(cert_tmpl, attr, ctsize);
518
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
519
0
        if (!rvObject->label && nickname) {
520
0
            NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, nickname);
521
0
        }
522
0
        NSS_CK_TEMPLATE_FINISH(cert_tmpl, attr, ctsize);
523
        /* reset the mutable attributes on the token */
524
0
        nssCKObject_SetAttributes(rvObject->handle,
525
0
                                  cert_tmpl, ctsize,
526
0
                                  session, slot);
527
0
        if (!rvObject->label && nickname) {
528
0
            rvObject->label = nssUTF8_Duplicate(nickname, NULL);
529
0
        }
530
0
        nssSession_Destroy(session);
531
0
        nssSlot_Destroy(slot);
532
0
    } else {
533
        /* Import the certificate onto the token */
534
0
        rvObject = import_object(tok, sessionOpt, cert_tmpl, ctsize);
535
0
    }
536
0
    if (rvObject && tok->cache) {
537
        /* The cache will overwrite the attributes if the object already
538
         * exists.
539
         */
540
0
        nssTokenObjectCache_ImportObject(tok->cache, rvObject,
541
0
                                         CKO_CERTIFICATE,
542
0
                                         cert_tmpl, ctsize);
543
0
    }
544
0
    return rvObject;
545
0
}
546
547
/* traverse all objects of the given class - this should only happen
548
 * if the token has been marked as "traversable"
549
 */
550
NSS_IMPLEMENT nssCryptokiObject **
551
nssToken_FindObjects(
552
    NSSToken *token,
553
    nssSession *sessionOpt,
554
    CK_OBJECT_CLASS objclass,
555
    nssTokenSearchType searchType,
556
    PRUint32 maximumOpt,
557
    PRStatus *statusOpt)
558
0
{
559
0
    CK_ATTRIBUTE_PTR attr;
560
0
    CK_ATTRIBUTE obj_template[2];
561
0
    CK_ULONG obj_size;
562
0
    nssCryptokiObject **objects;
563
0
    NSS_CK_TEMPLATE_START(obj_template, attr, obj_size);
564
    /* Set the search to token/session only if provided */
565
0
    if (searchType == nssTokenSearchType_SessionOnly) {
566
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
567
0
    } else if (searchType == nssTokenSearchType_TokenOnly ||
568
0
               searchType == nssTokenSearchType_TokenForced) {
569
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
570
0
    }
571
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, objclass);
572
0
    NSS_CK_TEMPLATE_FINISH(obj_template, attr, obj_size);
573
574
0
    if (searchType == nssTokenSearchType_TokenForced) {
575
0
        objects = find_objects(token, sessionOpt,
576
0
                               obj_template, obj_size,
577
0
                               maximumOpt, statusOpt);
578
0
    } else {
579
0
        objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
580
0
                                                 obj_template, obj_size,
581
0
                                                 maximumOpt, statusOpt);
582
0
    }
583
0
    return objects;
584
0
}
585
586
NSS_IMPLEMENT nssCryptokiObject **
587
nssToken_FindCertificatesBySubject(
588
    NSSToken *token,
589
    nssSession *sessionOpt,
590
    NSSDER *subject,
591
    nssTokenSearchType searchType,
592
    PRUint32 maximumOpt,
593
    PRStatus *statusOpt)
594
25.8k
{
595
25.8k
    CK_ATTRIBUTE_PTR attr;
596
25.8k
    CK_ATTRIBUTE subj_template[3];
597
25.8k
    CK_ULONG stsize;
598
25.8k
    nssCryptokiObject **objects;
599
25.8k
    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
600
    /* Set the search to token/session only if provided */
601
25.8k
    if (searchType == nssTokenSearchType_SessionOnly) {
602
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
603
25.8k
    } else if (searchType == nssTokenSearchType_TokenOnly) {
604
25.8k
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
605
25.8k
    }
606
25.8k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
607
25.8k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
608
25.8k
    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
609
    /* now locate the token certs matching this template */
610
25.8k
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
611
25.8k
                                             subj_template, stsize,
612
25.8k
                                             maximumOpt, statusOpt);
613
25.8k
    return objects;
614
25.8k
}
615
616
NSS_IMPLEMENT nssCryptokiObject **
617
nssToken_FindCertificatesByNickname(
618
    NSSToken *token,
619
    nssSession *sessionOpt,
620
    const NSSUTF8 *name,
621
    nssTokenSearchType searchType,
622
    PRUint32 maximumOpt,
623
    PRStatus *statusOpt)
624
0
{
625
0
    CK_ATTRIBUTE_PTR attr;
626
0
    CK_ATTRIBUTE nick_template[3];
627
0
    CK_ULONG ntsize;
628
0
    nssCryptokiObject **objects;
629
0
    NSS_CK_TEMPLATE_START(nick_template, attr, ntsize);
630
0
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_LABEL, name);
631
    /* Set the search to token/session only if provided */
632
0
    if (searchType == nssTokenSearchType_SessionOnly) {
633
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
634
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
635
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
636
0
    }
637
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
638
0
    NSS_CK_TEMPLATE_FINISH(nick_template, attr, ntsize);
639
    /* now locate the token certs matching this template */
640
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
641
0
                                             nick_template, ntsize,
642
0
                                             maximumOpt, statusOpt);
643
0
    if (!objects) {
644
        /* This is to workaround the fact that PKCS#11 doesn't specify
645
         * whether the '\0' should be included.  XXX Is that still true?
646
         * im - this is not needed by the current softoken.  However, I'm
647
         * leaving it in until I have surveyed more tokens to see if it needed.
648
         * well, its needed by the builtin token...
649
         */
650
0
        nick_template[0].ulValueLen++;
651
0
        objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
652
0
                                                 nick_template, ntsize,
653
0
                                                 maximumOpt, statusOpt);
654
0
    }
655
0
    return objects;
656
0
}
657
658
/* XXX
659
 * This function *does not* use the token object cache, because not even
660
 * the softoken will return a value for CKA_NSS_EMAIL from a call
661
 * to GetAttributes.  The softoken does allow searches with that attribute,
662
 * it just won't return a value for it.
663
 */
664
NSS_IMPLEMENT nssCryptokiObject **
665
nssToken_FindCertificatesByEmail(
666
    NSSToken *token,
667
    nssSession *sessionOpt,
668
    NSSASCII7 *email,
669
    nssTokenSearchType searchType,
670
    PRUint32 maximumOpt,
671
    PRStatus *statusOpt)
672
0
{
673
0
    CK_ATTRIBUTE_PTR attr;
674
0
    CK_ATTRIBUTE email_template[3];
675
0
    CK_ULONG etsize;
676
0
    nssCryptokiObject **objects;
677
0
    NSS_CK_TEMPLATE_START(email_template, attr, etsize);
678
0
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_EMAIL, email);
679
    /* Set the search to token/session only if provided */
680
0
    if (searchType == nssTokenSearchType_SessionOnly) {
681
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
682
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
683
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
684
0
    }
685
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
686
0
    NSS_CK_TEMPLATE_FINISH(email_template, attr, etsize);
687
    /* now locate the token certs matching this template */
688
0
    objects = find_objects(token, sessionOpt,
689
0
                           email_template, etsize,
690
0
                           maximumOpt, statusOpt);
691
0
    if (!objects) {
692
        /* This is to workaround the fact that PKCS#11 doesn't specify
693
         * whether the '\0' should be included.  XXX Is that still true?
694
         * im - this is not needed by the current softoken.  However, I'm
695
         * leaving it in until I have surveyed more tokens to see if it needed.
696
         * well, its needed by the builtin token...
697
         */
698
0
        email_template[0].ulValueLen++;
699
0
        objects = find_objects(token, sessionOpt,
700
0
                               email_template, etsize,
701
0
                               maximumOpt, statusOpt);
702
0
    }
703
0
    return objects;
704
0
}
705
706
NSS_IMPLEMENT nssCryptokiObject **
707
nssToken_FindCertificatesByID(
708
    NSSToken *token,
709
    nssSession *sessionOpt,
710
    NSSItem *id,
711
    nssTokenSearchType searchType,
712
    PRUint32 maximumOpt,
713
    PRStatus *statusOpt)
714
0
{
715
0
    CK_ATTRIBUTE_PTR attr;
716
0
    CK_ATTRIBUTE id_template[3];
717
0
    CK_ULONG idtsize;
718
0
    nssCryptokiObject **objects;
719
0
    NSS_CK_TEMPLATE_START(id_template, attr, idtsize);
720
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, id);
721
    /* Set the search to token/session only if provided */
722
0
    if (searchType == nssTokenSearchType_SessionOnly) {
723
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
724
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
725
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
726
0
    }
727
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
728
0
    NSS_CK_TEMPLATE_FINISH(id_template, attr, idtsize);
729
    /* now locate the token certs matching this template */
730
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
731
0
                                             id_template, idtsize,
732
0
                                             maximumOpt, statusOpt);
733
0
    return objects;
734
0
}
735
736
/*
737
 * decode the serial item and return our result.
738
 * NOTE serialDecode's data is really stored in serial. Don't free it.
739
 */
740
static PRStatus
741
nssToken_decodeSerialItem(NSSItem *serial, NSSItem *serialDecode)
742
189k
{
743
189k
    unsigned char *data = (unsigned char *)serial->data;
744
189k
    int data_left, data_len, index;
745
746
189k
    if ((serial->size >= 3) && (data[0] == 0x2)) {
747
        /* remove the der encoding of the serial number before generating the
748
         * key.. */
749
189k
        data_left = serial->size - 2;
750
189k
        data_len = data[1];
751
189k
        index = 2;
752
753
        /* extended length ? (not very likely for a serial number) */
754
189k
        if (data_len & 0x80) {
755
44
            int len_count = data_len & 0x7f;
756
757
44
            data_len = 0;
758
44
            data_left -= len_count;
759
44
            if (data_left > 0) {
760
112
                while (len_count--) {
761
68
                    data_len = (data_len << 8) | data[index++];
762
68
                }
763
44
            }
764
44
        }
765
        /* XXX leaving any leading zeros on the serial number for backwards
766
         * compatibility
767
         */
768
        /* not a valid der, must be just an unlucky serial number value */
769
189k
        if (data_len == data_left) {
770
189k
            serialDecode->size = data_len;
771
189k
            serialDecode->data = &data[index];
772
189k
            return PR_SUCCESS;
773
189k
        }
774
189k
    }
775
198
    return PR_FAILURE;
776
189k
}
777
778
NSS_IMPLEMENT nssCryptokiObject *
779
nssToken_FindCertificateByIssuerAndSerialNumber(
780
    NSSToken *token,
781
    nssSession *sessionOpt,
782
    NSSDER *issuer,
783
    NSSDER *serial,
784
    nssTokenSearchType searchType,
785
    PRStatus *statusOpt)
786
189k
{
787
189k
    CK_ATTRIBUTE_PTR attr;
788
189k
    CK_ATTRIBUTE_PTR serialAttr;
789
189k
    CK_ATTRIBUTE cert_template[4];
790
189k
    CK_ULONG ctsize;
791
189k
    nssCryptokiObject **objects;
792
189k
    nssCryptokiObject *rvObject = NULL;
793
189k
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
794
795
189k
    if (!token) {
796
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
797
0
        if (statusOpt)
798
0
            *statusOpt = PR_FAILURE;
799
0
        return NULL;
800
0
    }
801
    /* Set the search to token/session only if provided */
802
189k
    if (searchType == nssTokenSearchType_SessionOnly) {
803
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
804
189k
    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
805
189k
               (searchType == nssTokenSearchType_TokenForced)) {
806
189k
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
807
189k
    }
808
    /* Set the unique id */
809
189k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
810
189k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
811
189k
    serialAttr = attr;
812
189k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
813
189k
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
814
    /* get the object handle */
815
189k
    if (searchType == nssTokenSearchType_TokenForced) {
816
10.0k
        objects = find_objects(token, sessionOpt,
817
10.0k
                               cert_template, ctsize,
818
10.0k
                               1, statusOpt);
819
179k
    } else {
820
179k
        objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
821
179k
                                                 cert_template, ctsize,
822
179k
                                                 1, statusOpt);
823
179k
    }
824
189k
    if (objects) {
825
0
        rvObject = objects[0];
826
0
        nss_ZFreeIf(objects);
827
0
    }
828
829
    /*
830
     * Some smart cards incorrectly store serial numbers in their decoded form.
831
     */
832
189k
    if (!objects) {
833
189k
        NSSItem serialDecode;
834
189k
        PRStatus status;
835
836
189k
        status = nssToken_decodeSerialItem(serial, &serialDecode);
837
189k
        if (status != PR_SUCCESS) {
838
198
            return NULL;
839
198
        }
840
189k
        NSS_CK_SET_ATTRIBUTE_ITEM(serialAttr, CKA_SERIAL_NUMBER, &serialDecode);
841
189k
        if (searchType == nssTokenSearchType_TokenForced) {
842
10.0k
            objects = find_objects(token, sessionOpt,
843
10.0k
                                   cert_template, ctsize,
844
10.0k
                                   1, statusOpt);
845
179k
        } else {
846
179k
            objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
847
179k
                                                     cert_template, ctsize,
848
179k
                                                     1, statusOpt);
849
179k
        }
850
189k
        if (objects) {
851
0
            rvObject = objects[0];
852
0
            nss_ZFreeIf(objects);
853
0
        }
854
189k
    }
855
189k
    return rvObject;
856
189k
}
857
858
NSS_IMPLEMENT nssCryptokiObject *
859
nssToken_FindCertificateByEncodedCertificate(
860
    NSSToken *token,
861
    nssSession *sessionOpt,
862
    NSSBER *encodedCertificate,
863
    nssTokenSearchType searchType,
864
    PRStatus *statusOpt)
865
0
{
866
0
    CK_ATTRIBUTE_PTR attr;
867
0
    CK_ATTRIBUTE cert_template[3];
868
0
    CK_ULONG ctsize;
869
0
    nssCryptokiObject **objects;
870
0
    nssCryptokiObject *rvObject = NULL;
871
0
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
872
    /* Set the search to token/session only if provided */
873
0
    if (searchType == nssTokenSearchType_SessionOnly) {
874
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
875
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
876
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
877
0
    }
878
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
879
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
880
0
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
881
    /* get the object handle */
882
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
883
0
                                             cert_template, ctsize,
884
0
                                             1, statusOpt);
885
0
    if (objects) {
886
0
        rvObject = objects[0];
887
0
        nss_ZFreeIf(objects);
888
0
    }
889
0
    return rvObject;
890
0
}
891
892
NSS_IMPLEMENT nssCryptokiObject **
893
nssToken_FindPrivateKeys(
894
    NSSToken *token,
895
    nssSession *sessionOpt,
896
    nssTokenSearchType searchType,
897
    PRUint32 maximumOpt,
898
    PRStatus *statusOpt)
899
0
{
900
0
    CK_ATTRIBUTE_PTR attr;
901
0
    CK_ATTRIBUTE key_template[2];
902
0
    CK_ULONG ktsize;
903
0
    nssCryptokiObject **objects;
904
905
0
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
906
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
907
0
    if (searchType == nssTokenSearchType_SessionOnly) {
908
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
909
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
910
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
911
0
    }
912
0
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
913
914
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
915
0
                                             key_template, ktsize,
916
0
                                             maximumOpt, statusOpt);
917
0
    return objects;
918
0
}
919
920
/* XXX ?there are no session cert objects, so only search token objects */
921
NSS_IMPLEMENT nssCryptokiObject *
922
nssToken_FindPrivateKeyByID(
923
    NSSToken *token,
924
    nssSession *sessionOpt,
925
    NSSItem *keyID)
926
0
{
927
0
    CK_ATTRIBUTE_PTR attr;
928
0
    CK_ATTRIBUTE key_template[3];
929
0
    CK_ULONG ktsize;
930
0
    nssCryptokiObject **objects;
931
0
    nssCryptokiObject *rvKey = NULL;
932
933
0
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
934
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
935
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
936
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
937
0
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
938
939
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
940
0
                                             key_template, ktsize,
941
0
                                             1, NULL);
942
0
    if (objects) {
943
0
        rvKey = objects[0];
944
0
        nss_ZFreeIf(objects);
945
0
    }
946
0
    return rvKey;
947
0
}
948
949
/* XXX ?there are no session cert objects, so only search token objects */
950
NSS_IMPLEMENT nssCryptokiObject *
951
nssToken_FindPublicKeyByID(
952
    NSSToken *token,
953
    nssSession *sessionOpt,
954
    NSSItem *keyID)
955
0
{
956
0
    CK_ATTRIBUTE_PTR attr;
957
0
    CK_ATTRIBUTE key_template[3];
958
0
    CK_ULONG ktsize;
959
0
    nssCryptokiObject **objects;
960
0
    nssCryptokiObject *rvKey = NULL;
961
962
0
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
963
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
964
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
965
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
966
0
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
967
968
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
969
0
                                             key_template, ktsize,
970
0
                                             1, NULL);
971
0
    if (objects) {
972
0
        rvKey = objects[0];
973
0
        nss_ZFreeIf(objects);
974
0
    }
975
0
    return rvKey;
976
0
}
977
978
static PRBool
979
nss_TokenUsePKCS11Trust(NSSToken *tok)
980
0
{
981
0
    void *evp = nssToken_GetCryptokiEPV(tok);
982
0
    CK_VERSION vers;
983
984
0
    if (!evp) {
985
0
        return PR_FALSE;
986
0
    }
987
0
    vers = CKAPI(evp)->version;
988
0
    if (vers.major < 3) {
989
0
        return PR_FALSE;
990
0
    }
991
0
    if ((vers.major == 3) && (vers.minor < 2)) {
992
0
        return PR_FALSE;
993
0
    }
994
    /* force the use of either PKCS11 trust or NSS trust */
995
    /* this only affects output, input always accepts both trust
996
     * types */
997
0
    char *envp = PR_GetEnvSecure("NSS_TRUST_TYPE");
998
0
    if (envp) {
999
0
        if (PORT_Strcasecmp(envp, "PKCS11") == 0) {
1000
0
            return PR_TRUE;
1001
0
        }
1002
0
        if (PORT_Strcasecmp(envp, "NSS") == 0) {
1003
0
            return PR_FALSE;
1004
0
        }
1005
0
    }
1006
0
    return PR_TRUE;
1007
0
}
1008
1009
static CK_TRUST
1010
get_ck_trust(
1011
    nssTrustLevel nssTrust, PRBool isPKCSTrust)
1012
0
{
1013
0
    CK_TRUST t;
1014
0
    switch (nssTrust) {
1015
0
        case nssTrustLevel_NotTrusted:
1016
0
            t = isPKCSTrust ? CKT_NOT_TRUSTED : CKT_NSS_NOT_TRUSTED;
1017
0
            break;
1018
0
        case nssTrustLevel_TrustedDelegator:
1019
0
            t = isPKCSTrust ? CKT_TRUST_ANCHOR : CKT_NSS_TRUSTED_DELEGATOR;
1020
0
            break;
1021
0
        case nssTrustLevel_ValidDelegator:
1022
0
            t = isPKCSTrust ? CKT_TRUST_MUST_VERIFY_TRUST : CKT_NSS_VALID_DELEGATOR;
1023
0
            break;
1024
0
        case nssTrustLevel_Trusted:
1025
0
            t = isPKCSTrust ? CKT_TRUSTED : CKT_NSS_TRUSTED;
1026
0
            break;
1027
0
        case nssTrustLevel_MustVerify:
1028
0
            t = isPKCSTrust ? CKT_TRUST_MUST_VERIFY_TRUST : CKT_NSS_MUST_VERIFY_TRUST;
1029
0
            break;
1030
0
        case nssTrustLevel_Unknown:
1031
0
        default:
1032
0
            t = isPKCSTrust ? CKT_TRUST_UNKNOWN : CKT_NSS_TRUST_UNKNOWN;
1033
0
            break;
1034
0
    }
1035
0
    return t;
1036
0
}
1037
1038
NSS_IMPLEMENT nssCryptokiObject *
1039
nssToken_ImportTrust(
1040
    NSSToken *tok,
1041
    nssSession *sessionOpt,
1042
    NSSDER *certEncoding,
1043
    NSSDER *certIssuer,
1044
    NSSDER *certSerial,
1045
    nssTrustLevel serverAuth,
1046
    nssTrustLevel clientAuth,
1047
    nssTrustLevel codeSigning,
1048
    nssTrustLevel emailProtection,
1049
    PRBool stepUpApproved,
1050
    PRBool asTokenObject)
1051
0
{
1052
0
    nssCryptokiObject *object;
1053
0
    CK_OBJECT_CLASS tobjc;
1054
0
    CK_TRUST ckSA, ckCA, ckCS, ckEP;
1055
0
    CK_ATTRIBUTE_PTR attr;
1056
0
    CK_ATTRIBUTE trust_tmpl[11];
1057
0
    CK_ULONG tsize;
1058
0
    PRBool usePKCS11TrustToken = nss_TokenUsePKCS11Trust(tok);
1059
0
    PRUint8 hashBuf[HASH_LENGTH_MAX];
1060
0
    PRUint8 hashBuf2[HASH_LENGTH_MAX];
1061
0
    CK_MECHANISM_TYPE hashMech;
1062
1063
0
    tobjc = usePKCS11TrustToken ? CKO_TRUST : CKO_NSS_TRUST;
1064
0
    ckSA = get_ck_trust(serverAuth, usePKCS11TrustToken);
1065
0
    ckCA = get_ck_trust(clientAuth, usePKCS11TrustToken);
1066
0
    ckCS = get_ck_trust(codeSigning, usePKCS11TrustToken);
1067
0
    ckEP = get_ck_trust(emailProtection, usePKCS11TrustToken);
1068
0
    hashMech = usePKCS11TrustToken ? CKM_SHA256 : CKM_SHA_1;
1069
1070
0
    NSSItem hash_result, hash2_result;
1071
0
    hash_result.data = hashBuf;
1072
0
    hash_result.size = sizeof(hashBuf);
1073
0
    NSSAlgorithm_DigestBuf(hashMech, certEncoding, &hash_result);
1074
0
    if (!usePKCS11TrustToken) {
1075
0
        hash2_result.data = hashBuf2;
1076
0
        hash2_result.size = sizeof(hashBuf2);
1077
0
        NSSAlgorithm_DigestBuf(CKM_MD5, certEncoding, &hash2_result);
1078
0
    }
1079
1080
0
    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
1081
0
    if (asTokenObject) {
1082
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1083
0
    } else {
1084
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1085
0
    }
1086
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1087
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1088
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1089
0
    if (usePKCS11TrustToken) {
1090
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_HASH_OF_CERTIFICATE, &hash_result);
1091
0
        NSS_CK_SET_ATTRIBUTE_FIXED_PTR(attr, CKA_NAME_HASH_ALGORITHM, &hashMech);
1092
        /* now set the trust values */
1093
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_SERVER_AUTH, ckSA);
1094
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CLIENT_AUTH, ckCA);
1095
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CODE_SIGNING, ckCS);
1096
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_EMAIL_PROTECTION, ckEP);
1097
0
    } else {
1098
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_SHA1_HASH, &hash_result);
1099
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_MD5_HASH, &hash2_result);
1100
        /* now set the trust values */
1101
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_SERVER_AUTH, ckSA);
1102
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CLIENT_AUTH, ckCA);
1103
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CODE_SIGNING, ckCS);
1104
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_EMAIL_PROTECTION, ckEP);
1105
0
        if (stepUpApproved) {
1106
0
            NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_TRUST_STEP_UP_APPROVED,
1107
0
                                      &g_ck_true);
1108
0
        } else {
1109
0
            NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_TRUST_STEP_UP_APPROVED,
1110
0
                                      &g_ck_false);
1111
0
        }
1112
0
    }
1113
0
    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
1114
    /* import the trust object onto the token */
1115
0
    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
1116
0
    if (object && tok->cache) {
1117
0
        nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
1118
0
                                         trust_tmpl, tsize);
1119
0
    }
1120
0
    return object;
1121
0
}
1122
1123
NSS_IMPLEMENT nssCryptokiObject *
1124
nssToken_FindTrustForCertificate(
1125
    NSSToken *token,
1126
    nssSession *sessionOpt,
1127
    NSSDER *certEncoding,
1128
    NSSDER *certIssuer,
1129
    NSSDER *certSerial,
1130
    nssTokenSearchType searchType)
1131
478k
{
1132
478k
    CK_OBJECT_CLASS tobjc = CKO_TRUST;
1133
478k
    CK_ATTRIBUTE_PTR attr;
1134
478k
    CK_ATTRIBUTE tobj_template[5];
1135
478k
    CK_ULONG tobj_size;
1136
478k
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1137
478k
    nssCryptokiObject *object = NULL, **objects;
1138
1139
    /* Don't ask the module to use an invalid session handle. */
1140
478k
    if (!session || session->handle == CK_INVALID_HANDLE) {
1141
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1142
0
        return object;
1143
0
    }
1144
1145
478k
    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1146
478k
    if (searchType == nssTokenSearchType_TokenOnly) {
1147
478k
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1148
478k
    }
1149
478k
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1150
478k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1151
478k
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1152
478k
    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1153
478k
    objects = nssToken_FindObjectsByTemplate(token, session,
1154
478k
                                             tobj_template, tobj_size,
1155
478k
                                             1, NULL);
1156
478k
    if (!objects) {
1157
478k
        tobjc = CKO_NSS_TRUST;
1158
478k
        objects = nssToken_FindObjectsByTemplate(token, session,
1159
478k
                                                 tobj_template, tobj_size,
1160
478k
                                                 1, NULL);
1161
478k
    }
1162
1163
478k
    if (objects) {
1164
0
        object = objects[0];
1165
0
        object->trustType = tobjc;
1166
0
        nss_ZFreeIf(objects);
1167
0
    }
1168
478k
    return object;
1169
478k
}
1170
1171
NSS_IMPLEMENT nssCryptokiObject *
1172
nssToken_ImportCRL(
1173
    NSSToken *token,
1174
    nssSession *sessionOpt,
1175
    NSSDER *subject,
1176
    NSSDER *encoding,
1177
    PRBool isKRL,
1178
    NSSUTF8 *url,
1179
    PRBool asTokenObject)
1180
0
{
1181
0
    nssCryptokiObject *object;
1182
0
    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1183
0
    CK_ATTRIBUTE_PTR attr;
1184
0
    CK_ATTRIBUTE crl_tmpl[6];
1185
0
    CK_ULONG crlsize;
1186
1187
0
    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
1188
0
    if (asTokenObject) {
1189
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1190
0
    } else {
1191
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1192
0
    }
1193
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1194
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1195
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
1196
0
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
1197
0
    if (isKRL) {
1198
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
1199
0
    } else {
1200
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
1201
0
    }
1202
0
    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
1203
1204
    /* import the crl object onto the token */
1205
0
    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
1206
0
    if (object && token->cache) {
1207
0
        nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
1208
0
                                         crl_tmpl, crlsize);
1209
0
    }
1210
0
    return object;
1211
0
}
1212
1213
NSS_IMPLEMENT nssCryptokiObject **
1214
nssToken_FindCRLsBySubject(
1215
    NSSToken *token,
1216
    nssSession *sessionOpt,
1217
    NSSDER *subject,
1218
    nssTokenSearchType searchType,
1219
    PRUint32 maximumOpt,
1220
    PRStatus *statusOpt)
1221
0
{
1222
0
    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1223
0
    CK_ATTRIBUTE_PTR attr;
1224
0
    CK_ATTRIBUTE crlobj_template[3];
1225
0
    CK_ULONG crlobj_size;
1226
0
    nssCryptokiObject **objects = NULL;
1227
0
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1228
1229
    /* Don't ask the module to use an invalid session handle. */
1230
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1231
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1232
0
        return objects;
1233
0
    }
1234
1235
0
    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1236
0
    if (searchType == nssTokenSearchType_SessionOnly) {
1237
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1238
0
    } else if (searchType == nssTokenSearchType_TokenOnly ||
1239
0
               searchType == nssTokenSearchType_TokenForced) {
1240
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1241
0
    }
1242
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1243
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1244
0
    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1245
1246
0
    objects = nssToken_FindObjectsByTemplate(token, session,
1247
0
                                             crlobj_template, crlobj_size,
1248
0
                                             maximumOpt, statusOpt);
1249
0
    return objects;
1250
0
}
1251
1252
NSS_IMPLEMENT PRStatus
1253
nssToken_GetCachedObjectAttributes(
1254
    NSSToken *token,
1255
    NSSArena *arenaOpt,
1256
    nssCryptokiObject *object,
1257
    CK_OBJECT_CLASS objclass,
1258
    CK_ATTRIBUTE_PTR atemplate,
1259
    CK_ULONG atlen)
1260
0
{
1261
0
    if (!token->cache) {
1262
0
        return PR_FAILURE;
1263
0
    }
1264
0
    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
1265
0
                                                   object, objclass,
1266
0
                                                   atemplate, atlen);
1267
0
}
1268
1269
NSS_IMPLEMENT NSSItem *
1270
nssToken_Digest(
1271
    NSSToken *tok,
1272
    nssSession *sessionOpt,
1273
    NSSAlgorithmAndParameters *ap,
1274
    NSSItem *data,
1275
    NSSItem *rvOpt,
1276
    NSSArena *arenaOpt)
1277
0
{
1278
0
    CK_RV ckrv;
1279
0
    CK_ULONG digestLen;
1280
0
    CK_BYTE_PTR digest;
1281
0
    NSSItem *rvItem = NULL;
1282
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1283
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1284
1285
    /* Don't ask the module to use an invalid session handle. */
1286
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1287
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1288
0
        return rvItem;
1289
0
    }
1290
1291
0
    nssSession_EnterMonitor(session);
1292
0
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1293
0
    if (ckrv != CKR_OK) {
1294
0
        nssSession_ExitMonitor(session);
1295
0
        return NULL;
1296
0
    }
1297
#if 0
1298
    /* XXX the standard says this should work, but it doesn't */
1299
    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
1300
    if (ckrv != CKR_OK) {
1301
  nssSession_ExitMonitor(session);
1302
  return NULL;
1303
    }
1304
#endif
1305
0
    digestLen = 0; /* XXX for now */
1306
0
    digest = NULL;
1307
0
    if (rvOpt) {
1308
0
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1309
0
            nssSession_ExitMonitor(session);
1310
            /* the error should be bad args */
1311
0
            return NULL;
1312
0
        }
1313
0
        if (rvOpt->data) {
1314
0
            digest = rvOpt->data;
1315
0
        }
1316
0
        digestLen = rvOpt->size;
1317
0
    }
1318
0
    if (!digest) {
1319
0
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1320
0
        if (!digest) {
1321
0
            nssSession_ExitMonitor(session);
1322
0
            return NULL;
1323
0
        }
1324
0
    }
1325
0
    ckrv = CKAPI(epv)->C_Digest(session->handle,
1326
0
                                (CK_BYTE_PTR)data->data,
1327
0
                                (CK_ULONG)data->size,
1328
0
                                (CK_BYTE_PTR)digest,
1329
0
                                &digestLen);
1330
0
    nssSession_ExitMonitor(session);
1331
0
    if (ckrv != CKR_OK) {
1332
0
        nss_ZFreeIf(digest);
1333
0
        return NULL;
1334
0
    }
1335
0
    if (!rvOpt) {
1336
0
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1337
0
    } else {
1338
0
        rvOpt->size = digestLen;
1339
0
        rvItem = rvOpt;
1340
0
    }
1341
0
    return rvItem;
1342
0
}
1343
1344
NSS_IMPLEMENT PRStatus
1345
nssToken_BeginDigest(
1346
    NSSToken *tok,
1347
    nssSession *sessionOpt,
1348
    NSSAlgorithmAndParameters *ap)
1349
0
{
1350
0
    CK_RV ckrv;
1351
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1352
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1353
1354
    /* Don't ask the module to use an invalid session handle. */
1355
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1356
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1357
0
        return PR_FAILURE;
1358
0
    }
1359
1360
0
    nssSession_EnterMonitor(session);
1361
0
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1362
0
    nssSession_ExitMonitor(session);
1363
0
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1364
0
}
1365
1366
NSS_IMPLEMENT PRStatus
1367
nssToken_ContinueDigest(
1368
    NSSToken *tok,
1369
    nssSession *sessionOpt,
1370
    NSSItem *item)
1371
0
{
1372
0
    CK_RV ckrv;
1373
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1374
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1375
1376
    /* Don't ask the module to use an invalid session handle. */
1377
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1378
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1379
0
        return PR_FAILURE;
1380
0
    }
1381
1382
0
    nssSession_EnterMonitor(session);
1383
0
    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
1384
0
                                      (CK_BYTE_PTR)item->data,
1385
0
                                      (CK_ULONG)item->size);
1386
0
    nssSession_ExitMonitor(session);
1387
0
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1388
0
}
1389
1390
NSS_IMPLEMENT NSSItem *
1391
nssToken_FinishDigest(
1392
    NSSToken *tok,
1393
    nssSession *sessionOpt,
1394
    NSSItem *rvOpt,
1395
    NSSArena *arenaOpt)
1396
0
{
1397
0
    CK_RV ckrv;
1398
0
    CK_ULONG digestLen;
1399
0
    CK_BYTE_PTR digest;
1400
0
    NSSItem *rvItem = NULL;
1401
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1402
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1403
1404
    /* Don't ask the module to use an invalid session handle. */
1405
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1406
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1407
0
        return NULL;
1408
0
    }
1409
1410
0
    nssSession_EnterMonitor(session);
1411
0
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
1412
0
    if (ckrv != CKR_OK || digestLen == 0) {
1413
0
        nssSession_ExitMonitor(session);
1414
0
        return NULL;
1415
0
    }
1416
0
    digest = NULL;
1417
0
    if (rvOpt) {
1418
0
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1419
0
            nssSession_ExitMonitor(session);
1420
            /* the error should be bad args */
1421
0
            return NULL;
1422
0
        }
1423
0
        if (rvOpt->data) {
1424
0
            digest = rvOpt->data;
1425
0
        }
1426
0
        digestLen = rvOpt->size;
1427
0
    }
1428
0
    if (!digest) {
1429
0
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1430
0
        if (!digest) {
1431
0
            nssSession_ExitMonitor(session);
1432
0
            return NULL;
1433
0
        }
1434
0
    }
1435
0
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
1436
0
    nssSession_ExitMonitor(session);
1437
0
    if (ckrv != CKR_OK) {
1438
0
        nss_ZFreeIf(digest);
1439
0
        return NULL;
1440
0
    }
1441
0
    if (!rvOpt) {
1442
0
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1443
0
    }
1444
0
    return rvItem;
1445
0
}
1446
1447
NSS_IMPLEMENT PRBool
1448
nssToken_IsPresent(
1449
    NSSToken *token)
1450
0
{
1451
0
    return nssSlot_IsTokenPresent(token->slot);
1452
0
}
1453
1454
/* Sigh.  The methods to find objects declared above cause problems with
1455
 * the low-level object cache in the softoken -- the objects are found in
1456
 * toto, then one wave of GetAttributes is done, then another.  Having a
1457
 * large number of objects causes the cache to be thrashed, as the objects
1458
 * are gone before there's any chance to ask for their attributes.
1459
 * So, for now, bringing back traversal methods for certs.  This way all of
1460
 * the cert's attributes can be grabbed immediately after finding it,
1461
 * increasing the likelihood that the cache takes care of it.
1462
 */
1463
NSS_IMPLEMENT PRStatus
1464
nssToken_TraverseCertificates(
1465
    NSSToken *token,
1466
    nssSession *sessionOpt,
1467
    nssTokenSearchType searchType,
1468
    PRStatus (*callback)(nssCryptokiObject *instance, void *arg),
1469
    void *arg)
1470
10
{
1471
10
    CK_RV ckrv;
1472
10
    CK_ULONG count;
1473
10
    CK_OBJECT_HANDLE *objectHandles;
1474
10
    CK_ATTRIBUTE_PTR attr;
1475
10
    CK_ATTRIBUTE cert_template[2];
1476
10
    CK_ULONG ctsize;
1477
10
    NSSArena *arena;
1478
10
    PRUint32 arraySize, numHandles;
1479
10
    nssCryptokiObject **objects;
1480
10
    void *epv = nssToken_GetCryptokiEPV(token);
1481
10
    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
1482
1483
    /* Don't ask the module to use an invalid session handle. */
1484
10
    if (!session || session->handle == CK_INVALID_HANDLE) {
1485
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1486
0
        return PR_FAILURE;
1487
0
    }
1488
1489
    /* template for all certs */
1490
10
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
1491
10
    if (searchType == nssTokenSearchType_SessionOnly) {
1492
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1493
10
    } else if (searchType == nssTokenSearchType_TokenOnly ||
1494
10
               searchType == nssTokenSearchType_TokenForced) {
1495
10
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1496
10
    }
1497
10
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
1498
10
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
1499
1500
    /* the arena is only for the array of object handles */
1501
10
    arena = nssArena_Create();
1502
10
    if (!arena) {
1503
0
        return PR_FAILURE;
1504
0
    }
1505
10
    arraySize = OBJECT_STACK_SIZE;
1506
10
    numHandles = 0;
1507
10
    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
1508
10
    if (!objectHandles) {
1509
0
        goto loser;
1510
0
    }
1511
10
    nssSession_EnterMonitor(session); /* ==== session lock === */
1512
    /* Initialize the find with the template */
1513
10
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
1514
10
                                         cert_template, ctsize);
1515
10
    if (ckrv != CKR_OK) {
1516
0
        nssSession_ExitMonitor(session);
1517
0
        goto loser;
1518
0
    }
1519
10
    while (PR_TRUE) {
1520
        /* Issue the find for up to arraySize - numHandles objects */
1521
10
        ckrv = CKAPI(epv)->C_FindObjects(session->handle,
1522
10
                                         objectHandles + numHandles,
1523
10
                                         arraySize - numHandles,
1524
10
                                         &count);
1525
10
        if (ckrv != CKR_OK) {
1526
0
            nssSession_ExitMonitor(session);
1527
0
            goto loser;
1528
0
        }
1529
        /* bump the number of found objects */
1530
10
        numHandles += count;
1531
10
        if (numHandles < arraySize) {
1532
10
            break;
1533
10
        }
1534
        /* the array is filled, double it and continue */
1535
0
        arraySize *= 2;
1536
0
        objectHandles = nss_ZREALLOCARRAY(objectHandles,
1537
0
                                          CK_OBJECT_HANDLE,
1538
0
                                          arraySize);
1539
0
        if (!objectHandles) {
1540
0
            nssSession_ExitMonitor(session);
1541
0
            goto loser;
1542
0
        }
1543
0
    }
1544
10
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
1545
10
    nssSession_ExitMonitor(session); /* ==== end session lock === */
1546
10
    if (ckrv != CKR_OK) {
1547
0
        goto loser;
1548
0
    }
1549
10
    if (numHandles > 0) {
1550
0
        objects = create_objects_from_handles(token, session,
1551
0
                                              objectHandles, numHandles);
1552
0
        if (objects) {
1553
0
            nssCryptokiObject **op;
1554
0
            for (op = objects; *op; op++) {
1555
0
                (void)(*callback)(*op, arg);
1556
0
            }
1557
0
            nss_ZFreeIf(objects);
1558
0
        }
1559
0
    }
1560
10
    nssArena_Destroy(arena);
1561
10
    return PR_SUCCESS;
1562
0
loser:
1563
0
    nssArena_Destroy(arena);
1564
0
    return PR_FAILURE;
1565
10
}
1566
1567
NSS_IMPLEMENT PRBool
1568
nssToken_IsPrivateKeyAvailable(
1569
    NSSToken *token,
1570
    NSSCertificate *c,
1571
    nssCryptokiObject *instance)
1572
0
{
1573
0
    CK_OBJECT_CLASS theClass;
1574
1575
0
    if (token == NULL)
1576
0
        return PR_FALSE;
1577
0
    if (c == NULL)
1578
0
        return PR_FALSE;
1579
1580
0
    theClass = CKO_PRIVATE_KEY;
1581
0
    if (!nssSlot_IsLoggedIn(token->slot)) {
1582
0
        theClass = CKO_PUBLIC_KEY;
1583
0
    }
1584
0
    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) !=
1585
0
        CK_INVALID_HANDLE) {
1586
0
        return PR_TRUE;
1587
0
    }
1588
0
    return PR_FALSE;
1589
0
}