Coverage Report

Created: 2018-09-25 14:53

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