Coverage Report

Created: 2025-07-01 06:25

/src/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
            (void)nssSlot_Destroy(tok->slot);
36
0
            return nssArena_Destroy(tok->base.arena);
37
0
        }
38
0
    }
39
0
    return PR_SUCCESS;
40
0
}
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
0
{
53
0
    PR_ATOMIC_INCREMENT(&tok->base.refCount);
54
0
    return tok;
55
0
}
56
57
NSS_IMPLEMENT NSSSlot *
58
nssToken_GetSlot(
59
    NSSToken *tok)
60
0
{
61
0
    return nssSlot_AddRef(tok->slot);
62
0
}
63
64
NSS_IMPLEMENT void *
65
nssToken_GetCryptokiEPV(
66
    NSSToken *token)
67
0
{
68
0
    return nssSlot_GetCryptokiEPV(token->slot);
69
0
}
70
71
NSS_IMPLEMENT nssSession *
72
nssToken_GetDefaultSession(
73
    NSSToken *token)
74
0
{
75
0
    return token->defaultSession;
76
0
}
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
0
{
241
0
    CK_RV ckrv = CKR_OK;
242
0
    CK_ULONG count;
243
0
    CK_OBJECT_HANDLE *objectHandles = NULL;
244
0
    CK_OBJECT_HANDLE staticObjects[OBJECT_STACK_SIZE];
245
0
    PRUint32 arraySize, numHandles;
246
0
    void *epv = nssToken_GetCryptokiEPV(tok);
247
0
    nssCryptokiObject **objects;
248
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
249
250
    /* Don't ask the module to use an invalid session handle. */
251
0
    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
0
    if (maximumOpt > 0) {
258
0
        arraySize = maximumOpt;
259
0
    } else {
260
0
        arraySize = OBJECT_STACK_SIZE;
261
0
    }
262
0
    numHandles = 0;
263
0
    if (arraySize <= OBJECT_STACK_SIZE) {
264
0
        objectHandles = staticObjects;
265
0
    } else {
266
0
        objectHandles = nss_ZNEWARRAY(NULL, CK_OBJECT_HANDLE, arraySize);
267
0
    }
268
0
    if (!objectHandles) {
269
0
        ckrv = CKR_HOST_MEMORY;
270
0
        goto loser;
271
0
    }
272
0
    nssSession_EnterMonitor(session); /* ==== session lock === */
273
    /* Initialize the find with the template */
274
0
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
275
0
                                         obj_template, otsize);
276
0
    if (ckrv != CKR_OK) {
277
0
        nssSession_ExitMonitor(session);
278
0
        goto loser;
279
0
    }
280
0
    while (PR_TRUE) {
281
        /* Issue the find for up to arraySize - numHandles objects */
282
0
        ckrv = CKAPI(epv)->C_FindObjects(session->handle,
283
0
                                         objectHandles + numHandles,
284
0
                                         arraySize - numHandles,
285
0
                                         &count);
286
0
        if (ckrv != CKR_OK) {
287
0
            nssSession_ExitMonitor(session);
288
0
            goto loser;
289
0
        }
290
        /* bump the number of found objects */
291
0
        numHandles += count;
292
0
        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
0
            break;
298
0
        }
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
0
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
319
0
    nssSession_ExitMonitor(session); /* ==== end session lock === */
320
0
    if (ckrv != CKR_OK) {
321
0
        goto loser;
322
0
    }
323
0
    if (numHandles > 0) {
324
0
        objects = create_objects_from_handles(tok, session,
325
0
                                              objectHandles, numHandles);
326
0
    } else {
327
0
        nss_SetError(NSS_ERROR_NOT_FOUND);
328
0
        objects = NULL;
329
0
    }
330
0
    if (objectHandles && objectHandles != staticObjects) {
331
0
        nss_ZFreeIf(objectHandles);
332
0
    }
333
0
    if (statusOpt)
334
0
        *statusOpt = PR_SUCCESS;
335
0
    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
0
}
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
0
{
373
0
    CK_OBJECT_CLASS objclass = (CK_OBJECT_CLASS)-1;
374
0
    nssCryptokiObject **objects = NULL;
375
0
    PRUint32 i;
376
377
0
    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
0
    for (i = 0; i < otsize; i++) {
384
0
        if (obj_template[i].type == CKA_CLASS) {
385
0
            objclass = *(CK_OBJECT_CLASS *)obj_template[i].pValue;
386
0
            break;
387
0
        }
388
0
    }
389
0
    PR_ASSERT(i < otsize);
390
0
    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
0
    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
0
    objects = find_objects(token, sessionOpt,
414
0
                           obj_template, otsize,
415
0
                           maximumOpt, statusOpt);
416
0
    return objects;
417
0
}
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
0
{
595
0
    CK_ATTRIBUTE_PTR attr;
596
0
    CK_ATTRIBUTE subj_template[3];
597
0
    CK_ULONG stsize;
598
0
    nssCryptokiObject **objects;
599
0
    NSS_CK_TEMPLATE_START(subj_template, attr, stsize);
600
    /* Set the search to token/session only if provided */
601
0
    if (searchType == nssTokenSearchType_SessionOnly) {
602
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
603
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
604
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
605
0
    }
606
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
607
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
608
0
    NSS_CK_TEMPLATE_FINISH(subj_template, attr, stsize);
609
    /* now locate the token certs matching this template */
610
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
611
0
                                             subj_template, stsize,
612
0
                                             maximumOpt, statusOpt);
613
0
    return objects;
614
0
}
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
NSS_IMPLEMENT nssCryptokiObject *
737
nssToken_FindCertificateByIssuerAndSerialNumber(
738
    NSSToken *token,
739
    nssSession *sessionOpt,
740
    NSSDER *issuer,
741
    NSSDER *serial,
742
    nssTokenSearchType searchType,
743
    PRStatus *statusOpt)
744
0
{
745
0
    CK_ATTRIBUTE_PTR attr;
746
0
    CK_ATTRIBUTE cert_template[4];
747
0
    CK_ULONG ctsize;
748
0
    nssCryptokiObject **objects;
749
0
    nssCryptokiObject *rvObject = NULL;
750
0
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
751
752
0
    if (!token) {
753
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
754
0
        if (statusOpt)
755
0
            *statusOpt = PR_FAILURE;
756
0
        return NULL;
757
0
    }
758
    /* Set the search to token/session only if provided */
759
0
    if (searchType == nssTokenSearchType_SessionOnly) {
760
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
761
0
    } else if ((searchType == nssTokenSearchType_TokenOnly) ||
762
0
               (searchType == nssTokenSearchType_TokenForced)) {
763
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
764
0
    }
765
    /* Set the unique id */
766
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
767
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, issuer);
768
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, serial);
769
0
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
770
    /* get the object handle */
771
0
    if (searchType == nssTokenSearchType_TokenForced) {
772
0
        objects = find_objects(token, sessionOpt,
773
0
                               cert_template, ctsize,
774
0
                               1, statusOpt);
775
0
    } else {
776
0
        objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
777
0
                                                 cert_template, ctsize,
778
0
                                                 1, statusOpt);
779
0
    }
780
0
    if (objects) {
781
0
        rvObject = objects[0];
782
0
        nss_ZFreeIf(objects);
783
0
    }
784
785
0
    return rvObject;
786
0
}
787
788
NSS_IMPLEMENT nssCryptokiObject *
789
nssToken_FindCertificateByEncodedCertificate(
790
    NSSToken *token,
791
    nssSession *sessionOpt,
792
    NSSBER *encodedCertificate,
793
    nssTokenSearchType searchType,
794
    PRStatus *statusOpt)
795
0
{
796
0
    CK_ATTRIBUTE_PTR attr;
797
0
    CK_ATTRIBUTE cert_template[3];
798
0
    CK_ULONG ctsize;
799
0
    nssCryptokiObject **objects;
800
0
    nssCryptokiObject *rvObject = NULL;
801
0
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
802
    /* Set the search to token/session only if provided */
803
0
    if (searchType == nssTokenSearchType_SessionOnly) {
804
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
805
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
806
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
807
0
    }
808
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
809
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encodedCertificate);
810
0
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
811
    /* get the object handle */
812
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
813
0
                                             cert_template, ctsize,
814
0
                                             1, statusOpt);
815
0
    if (objects) {
816
0
        rvObject = objects[0];
817
0
        nss_ZFreeIf(objects);
818
0
    }
819
0
    return rvObject;
820
0
}
821
822
NSS_IMPLEMENT nssCryptokiObject **
823
nssToken_FindPrivateKeys(
824
    NSSToken *token,
825
    nssSession *sessionOpt,
826
    nssTokenSearchType searchType,
827
    PRUint32 maximumOpt,
828
    PRStatus *statusOpt)
829
0
{
830
0
    CK_ATTRIBUTE_PTR attr;
831
0
    CK_ATTRIBUTE key_template[2];
832
0
    CK_ULONG ktsize;
833
0
    nssCryptokiObject **objects;
834
835
0
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
836
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
837
0
    if (searchType == nssTokenSearchType_SessionOnly) {
838
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
839
0
    } else if (searchType == nssTokenSearchType_TokenOnly) {
840
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
841
0
    }
842
0
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
843
844
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
845
0
                                             key_template, ktsize,
846
0
                                             maximumOpt, statusOpt);
847
0
    return objects;
848
0
}
849
850
/* XXX ?there are no session cert objects, so only search token objects */
851
NSS_IMPLEMENT nssCryptokiObject *
852
nssToken_FindPrivateKeyByID(
853
    NSSToken *token,
854
    nssSession *sessionOpt,
855
    NSSItem *keyID)
856
0
{
857
0
    CK_ATTRIBUTE_PTR attr;
858
0
    CK_ATTRIBUTE key_template[3];
859
0
    CK_ULONG ktsize;
860
0
    nssCryptokiObject **objects;
861
0
    nssCryptokiObject *rvKey = NULL;
862
863
0
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
864
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_privkey);
865
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
866
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
867
0
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
868
869
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
870
0
                                             key_template, ktsize,
871
0
                                             1, NULL);
872
0
    if (objects) {
873
0
        rvKey = objects[0];
874
0
        nss_ZFreeIf(objects);
875
0
    }
876
0
    return rvKey;
877
0
}
878
879
/* XXX ?there are no session cert objects, so only search token objects */
880
NSS_IMPLEMENT nssCryptokiObject *
881
nssToken_FindPublicKeyByID(
882
    NSSToken *token,
883
    nssSession *sessionOpt,
884
    NSSItem *keyID)
885
0
{
886
0
    CK_ATTRIBUTE_PTR attr;
887
0
    CK_ATTRIBUTE key_template[3];
888
0
    CK_ULONG ktsize;
889
0
    nssCryptokiObject **objects;
890
0
    nssCryptokiObject *rvKey = NULL;
891
892
0
    NSS_CK_TEMPLATE_START(key_template, attr, ktsize);
893
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_pubkey);
894
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
895
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ID, keyID);
896
0
    NSS_CK_TEMPLATE_FINISH(key_template, attr, ktsize);
897
898
0
    objects = nssToken_FindObjectsByTemplate(token, sessionOpt,
899
0
                                             key_template, ktsize,
900
0
                                             1, NULL);
901
0
    if (objects) {
902
0
        rvKey = objects[0];
903
0
        nss_ZFreeIf(objects);
904
0
    }
905
0
    return rvKey;
906
0
}
907
908
static void
909
sha1_hash(NSSItem *input, NSSItem *output)
910
0
{
911
0
    NSSAlgorithmAndParameters *ap;
912
0
    PK11SlotInfo *internal = PK11_GetInternalSlot();
913
0
    NSSToken *token = PK11Slot_GetNSSToken(internal);
914
0
    ap = NSSAlgorithmAndParameters_CreateSHA1Digest(NULL);
915
0
    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
916
0
    nss_ZFreeIf(ap);
917
0
    (void)nssToken_Destroy(token);
918
0
    PK11_FreeSlot(internal);
919
0
}
920
921
static void
922
md5_hash(NSSItem *input, NSSItem *output)
923
0
{
924
0
    NSSAlgorithmAndParameters *ap;
925
0
    PK11SlotInfo *internal = PK11_GetInternalSlot();
926
0
    NSSToken *token = PK11Slot_GetNSSToken(internal);
927
0
    ap = NSSAlgorithmAndParameters_CreateMD5Digest(NULL);
928
0
    (void)nssToken_Digest(token, NULL, ap, input, output, NULL);
929
0
    nss_ZFreeIf(ap);
930
0
    (void)nssToken_Destroy(token);
931
0
    PK11_FreeSlot(internal);
932
0
}
933
934
static CK_TRUST
935
get_ck_trust(
936
    nssTrustLevel nssTrust)
937
0
{
938
0
    CK_TRUST t;
939
0
    switch (nssTrust) {
940
0
        case nssTrustLevel_NotTrusted:
941
0
            t = CKT_NSS_NOT_TRUSTED;
942
0
            break;
943
0
        case nssTrustLevel_TrustedDelegator:
944
0
            t = CKT_NSS_TRUSTED_DELEGATOR;
945
0
            break;
946
0
        case nssTrustLevel_ValidDelegator:
947
0
            t = CKT_NSS_VALID_DELEGATOR;
948
0
            break;
949
0
        case nssTrustLevel_Trusted:
950
0
            t = CKT_NSS_TRUSTED;
951
0
            break;
952
0
        case nssTrustLevel_MustVerify:
953
0
            t = CKT_NSS_MUST_VERIFY_TRUST;
954
0
            break;
955
0
        case nssTrustLevel_Unknown:
956
0
        default:
957
0
            t = CKT_NSS_TRUST_UNKNOWN;
958
0
            break;
959
0
    }
960
0
    return t;
961
0
}
962
963
NSS_IMPLEMENT nssCryptokiObject *
964
nssToken_ImportTrust(
965
    NSSToken *tok,
966
    nssSession *sessionOpt,
967
    NSSDER *certEncoding,
968
    NSSDER *certIssuer,
969
    NSSDER *certSerial,
970
    nssTrustLevel serverAuth,
971
    nssTrustLevel clientAuth,
972
    nssTrustLevel codeSigning,
973
    nssTrustLevel emailProtection,
974
    PRBool stepUpApproved,
975
    PRBool asTokenObject)
976
0
{
977
0
    nssCryptokiObject *object;
978
0
    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
979
0
    CK_TRUST ckSA, ckCA, ckCS, ckEP;
980
0
    CK_ATTRIBUTE_PTR attr;
981
0
    CK_ATTRIBUTE trust_tmpl[11];
982
0
    CK_ULONG tsize;
983
0
    PRUint8 sha1[20]; /* this is cheating... */
984
0
    PRUint8 md5[16];
985
0
    NSSItem sha1_result, md5_result;
986
0
    sha1_result.data = sha1;
987
0
    sha1_result.size = sizeof sha1;
988
0
    md5_result.data = md5;
989
0
    md5_result.size = sizeof md5;
990
0
    sha1_hash(certEncoding, &sha1_result);
991
0
    md5_hash(certEncoding, &md5_result);
992
0
    ckSA = get_ck_trust(serverAuth);
993
0
    ckCA = get_ck_trust(clientAuth);
994
0
    ckCS = get_ck_trust(codeSigning);
995
0
    ckEP = get_ck_trust(emailProtection);
996
0
    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
997
0
    if (asTokenObject) {
998
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
999
0
    } else {
1000
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1001
0
    }
1002
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1003
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1004
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1005
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_SHA1_HASH, &sha1_result);
1006
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CERT_MD5_HASH, &md5_result);
1007
    /* now set the trust values */
1008
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_SERVER_AUTH, ckSA);
1009
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CLIENT_AUTH, ckCA);
1010
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_CODE_SIGNING, ckCS);
1011
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_TRUST_EMAIL_PROTECTION, ckEP);
1012
0
    if (stepUpApproved) {
1013
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
1014
0
                                  &g_ck_true);
1015
0
    } else {
1016
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TRUST_STEP_UP_APPROVED,
1017
0
                                  &g_ck_false);
1018
0
    }
1019
0
    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
1020
    /* import the trust object onto the token */
1021
0
    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
1022
0
    if (object && tok->cache) {
1023
0
        nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
1024
0
                                         trust_tmpl, tsize);
1025
0
    }
1026
0
    return object;
1027
0
}
1028
1029
NSS_IMPLEMENT nssCryptokiObject *
1030
nssToken_FindTrustForCertificate(
1031
    NSSToken *token,
1032
    nssSession *sessionOpt,
1033
    NSSDER *certEncoding,
1034
    NSSDER *certIssuer,
1035
    NSSDER *certSerial,
1036
    nssTokenSearchType searchType)
1037
0
{
1038
0
    CK_OBJECT_CLASS tobjc = CKO_NSS_TRUST;
1039
0
    CK_ATTRIBUTE_PTR attr;
1040
0
    CK_ATTRIBUTE tobj_template[5];
1041
0
    CK_ULONG tobj_size;
1042
0
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1043
0
    nssCryptokiObject *object = NULL, **objects;
1044
1045
    /* Don't ask the module to use an invalid session handle. */
1046
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1047
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1048
0
        return object;
1049
0
    }
1050
1051
0
    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1052
0
    if (searchType == nssTokenSearchType_TokenOnly) {
1053
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1054
0
    }
1055
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1056
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1057
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1058
0
    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1059
0
    objects = nssToken_FindObjectsByTemplate(token, session,
1060
0
                                             tobj_template, tobj_size,
1061
0
                                             1, NULL);
1062
0
    if (objects) {
1063
0
        object = objects[0];
1064
0
        nss_ZFreeIf(objects);
1065
0
    }
1066
0
    return object;
1067
0
}
1068
1069
NSS_IMPLEMENT nssCryptokiObject *
1070
nssToken_ImportCRL(
1071
    NSSToken *token,
1072
    nssSession *sessionOpt,
1073
    NSSDER *subject,
1074
    NSSDER *encoding,
1075
    PRBool isKRL,
1076
    NSSUTF8 *url,
1077
    PRBool asTokenObject)
1078
0
{
1079
0
    nssCryptokiObject *object;
1080
0
    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1081
0
    CK_ATTRIBUTE_PTR attr;
1082
0
    CK_ATTRIBUTE crl_tmpl[6];
1083
0
    CK_ULONG crlsize;
1084
1085
0
    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
1086
0
    if (asTokenObject) {
1087
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1088
0
    } else {
1089
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1090
0
    }
1091
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1092
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1093
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
1094
0
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
1095
0
    if (isKRL) {
1096
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
1097
0
    } else {
1098
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
1099
0
    }
1100
0
    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
1101
1102
    /* import the crl object onto the token */
1103
0
    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
1104
0
    if (object && token->cache) {
1105
0
        nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
1106
0
                                         crl_tmpl, crlsize);
1107
0
    }
1108
0
    return object;
1109
0
}
1110
1111
NSS_IMPLEMENT nssCryptokiObject **
1112
nssToken_FindCRLsBySubject(
1113
    NSSToken *token,
1114
    nssSession *sessionOpt,
1115
    NSSDER *subject,
1116
    nssTokenSearchType searchType,
1117
    PRUint32 maximumOpt,
1118
    PRStatus *statusOpt)
1119
0
{
1120
0
    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1121
0
    CK_ATTRIBUTE_PTR attr;
1122
0
    CK_ATTRIBUTE crlobj_template[3];
1123
0
    CK_ULONG crlobj_size;
1124
0
    nssCryptokiObject **objects = NULL;
1125
0
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1126
1127
    /* Don't ask the module to use an invalid session handle. */
1128
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1129
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1130
0
        return objects;
1131
0
    }
1132
1133
0
    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1134
0
    if (searchType == nssTokenSearchType_SessionOnly) {
1135
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1136
0
    } else if (searchType == nssTokenSearchType_TokenOnly ||
1137
0
               searchType == nssTokenSearchType_TokenForced) {
1138
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1139
0
    }
1140
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1141
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1142
0
    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1143
1144
0
    objects = nssToken_FindObjectsByTemplate(token, session,
1145
0
                                             crlobj_template, crlobj_size,
1146
0
                                             maximumOpt, statusOpt);
1147
0
    return objects;
1148
0
}
1149
1150
NSS_IMPLEMENT PRStatus
1151
nssToken_GetCachedObjectAttributes(
1152
    NSSToken *token,
1153
    NSSArena *arenaOpt,
1154
    nssCryptokiObject *object,
1155
    CK_OBJECT_CLASS objclass,
1156
    CK_ATTRIBUTE_PTR atemplate,
1157
    CK_ULONG atlen)
1158
0
{
1159
0
    if (!token->cache) {
1160
0
        return PR_FAILURE;
1161
0
    }
1162
0
    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
1163
0
                                                   object, objclass,
1164
0
                                                   atemplate, atlen);
1165
0
}
1166
1167
NSS_IMPLEMENT NSSItem *
1168
nssToken_Digest(
1169
    NSSToken *tok,
1170
    nssSession *sessionOpt,
1171
    NSSAlgorithmAndParameters *ap,
1172
    NSSItem *data,
1173
    NSSItem *rvOpt,
1174
    NSSArena *arenaOpt)
1175
0
{
1176
0
    CK_RV ckrv;
1177
0
    CK_ULONG digestLen;
1178
0
    CK_BYTE_PTR digest;
1179
0
    NSSItem *rvItem = NULL;
1180
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1181
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1182
1183
    /* Don't ask the module to use an invalid session handle. */
1184
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1185
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1186
0
        return rvItem;
1187
0
    }
1188
1189
0
    nssSession_EnterMonitor(session);
1190
0
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1191
0
    if (ckrv != CKR_OK) {
1192
0
        nssSession_ExitMonitor(session);
1193
0
        return NULL;
1194
0
    }
1195
#if 0
1196
    /* XXX the standard says this should work, but it doesn't */
1197
    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
1198
    if (ckrv != CKR_OK) {
1199
  nssSession_ExitMonitor(session);
1200
  return NULL;
1201
    }
1202
#endif
1203
0
    digestLen = 0; /* XXX for now */
1204
0
    digest = NULL;
1205
0
    if (rvOpt) {
1206
0
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1207
0
            nssSession_ExitMonitor(session);
1208
            /* the error should be bad args */
1209
0
            return NULL;
1210
0
        }
1211
0
        if (rvOpt->data) {
1212
0
            digest = rvOpt->data;
1213
0
        }
1214
0
        digestLen = rvOpt->size;
1215
0
    }
1216
0
    if (!digest) {
1217
0
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1218
0
        if (!digest) {
1219
0
            nssSession_ExitMonitor(session);
1220
0
            return NULL;
1221
0
        }
1222
0
    }
1223
0
    ckrv = CKAPI(epv)->C_Digest(session->handle,
1224
0
                                (CK_BYTE_PTR)data->data,
1225
0
                                (CK_ULONG)data->size,
1226
0
                                (CK_BYTE_PTR)digest,
1227
0
                                &digestLen);
1228
0
    nssSession_ExitMonitor(session);
1229
0
    if (ckrv != CKR_OK) {
1230
0
        nss_ZFreeIf(digest);
1231
0
        return NULL;
1232
0
    }
1233
0
    if (!rvOpt) {
1234
0
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1235
0
    }
1236
0
    return rvItem;
1237
0
}
1238
1239
NSS_IMPLEMENT PRStatus
1240
nssToken_BeginDigest(
1241
    NSSToken *tok,
1242
    nssSession *sessionOpt,
1243
    NSSAlgorithmAndParameters *ap)
1244
0
{
1245
0
    CK_RV ckrv;
1246
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1247
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1248
1249
    /* Don't ask the module to use an invalid session handle. */
1250
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1251
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1252
0
        return PR_FAILURE;
1253
0
    }
1254
1255
0
    nssSession_EnterMonitor(session);
1256
0
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1257
0
    nssSession_ExitMonitor(session);
1258
0
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1259
0
}
1260
1261
NSS_IMPLEMENT PRStatus
1262
nssToken_ContinueDigest(
1263
    NSSToken *tok,
1264
    nssSession *sessionOpt,
1265
    NSSItem *item)
1266
0
{
1267
0
    CK_RV ckrv;
1268
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1269
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1270
1271
    /* Don't ask the module to use an invalid session handle. */
1272
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1273
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1274
0
        return PR_FAILURE;
1275
0
    }
1276
1277
0
    nssSession_EnterMonitor(session);
1278
0
    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
1279
0
                                      (CK_BYTE_PTR)item->data,
1280
0
                                      (CK_ULONG)item->size);
1281
0
    nssSession_ExitMonitor(session);
1282
0
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1283
0
}
1284
1285
NSS_IMPLEMENT NSSItem *
1286
nssToken_FinishDigest(
1287
    NSSToken *tok,
1288
    nssSession *sessionOpt,
1289
    NSSItem *rvOpt,
1290
    NSSArena *arenaOpt)
1291
0
{
1292
0
    CK_RV ckrv;
1293
0
    CK_ULONG digestLen;
1294
0
    CK_BYTE_PTR digest;
1295
0
    NSSItem *rvItem = NULL;
1296
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1297
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1298
1299
    /* Don't ask the module to use an invalid session handle. */
1300
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1301
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1302
0
        return NULL;
1303
0
    }
1304
1305
0
    nssSession_EnterMonitor(session);
1306
0
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
1307
0
    if (ckrv != CKR_OK || digestLen == 0) {
1308
0
        nssSession_ExitMonitor(session);
1309
0
        return NULL;
1310
0
    }
1311
0
    digest = NULL;
1312
0
    if (rvOpt) {
1313
0
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1314
0
            nssSession_ExitMonitor(session);
1315
            /* the error should be bad args */
1316
0
            return NULL;
1317
0
        }
1318
0
        if (rvOpt->data) {
1319
0
            digest = rvOpt->data;
1320
0
        }
1321
0
        digestLen = rvOpt->size;
1322
0
    }
1323
0
    if (!digest) {
1324
0
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1325
0
        if (!digest) {
1326
0
            nssSession_ExitMonitor(session);
1327
0
            return NULL;
1328
0
        }
1329
0
    }
1330
0
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
1331
0
    nssSession_ExitMonitor(session);
1332
0
    if (ckrv != CKR_OK) {
1333
0
        nss_ZFreeIf(digest);
1334
0
        return NULL;
1335
0
    }
1336
0
    if (!rvOpt) {
1337
0
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1338
0
    }
1339
0
    return rvItem;
1340
0
}
1341
1342
NSS_IMPLEMENT PRBool
1343
nssToken_IsPresent(
1344
    NSSToken *token)
1345
0
{
1346
0
    return nssSlot_IsTokenPresent(token->slot);
1347
0
}
1348
1349
/* Sigh.  The methods to find objects declared above cause problems with
1350
 * the low-level object cache in the softoken -- the objects are found in
1351
 * toto, then one wave of GetAttributes is done, then another.  Having a
1352
 * large number of objects causes the cache to be thrashed, as the objects
1353
 * are gone before there's any chance to ask for their attributes.
1354
 * So, for now, bringing back traversal methods for certs.  This way all of
1355
 * the cert's attributes can be grabbed immediately after finding it,
1356
 * increasing the likelihood that the cache takes care of it.
1357
 */
1358
NSS_IMPLEMENT PRStatus
1359
nssToken_TraverseCertificates(
1360
    NSSToken *token,
1361
    nssSession *sessionOpt,
1362
    nssTokenSearchType searchType,
1363
    PRStatus (*callback)(nssCryptokiObject *instance, void *arg),
1364
    void *arg)
1365
0
{
1366
0
    CK_RV ckrv;
1367
0
    CK_ULONG count;
1368
0
    CK_OBJECT_HANDLE *objectHandles;
1369
0
    CK_ATTRIBUTE_PTR attr;
1370
0
    CK_ATTRIBUTE cert_template[2];
1371
0
    CK_ULONG ctsize;
1372
0
    NSSArena *arena;
1373
0
    PRUint32 arraySize, numHandles;
1374
0
    nssCryptokiObject **objects;
1375
0
    void *epv = nssToken_GetCryptokiEPV(token);
1376
0
    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
1377
1378
    /* Don't ask the module to use an invalid session handle. */
1379
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1380
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1381
0
        return PR_FAILURE;
1382
0
    }
1383
1384
    /* template for all certs */
1385
0
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
1386
0
    if (searchType == nssTokenSearchType_SessionOnly) {
1387
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1388
0
    } else if (searchType == nssTokenSearchType_TokenOnly ||
1389
0
               searchType == nssTokenSearchType_TokenForced) {
1390
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1391
0
    }
1392
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
1393
0
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
1394
1395
    /* the arena is only for the array of object handles */
1396
0
    arena = nssArena_Create();
1397
0
    if (!arena) {
1398
0
        return PR_FAILURE;
1399
0
    }
1400
0
    arraySize = OBJECT_STACK_SIZE;
1401
0
    numHandles = 0;
1402
0
    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
1403
0
    if (!objectHandles) {
1404
0
        goto loser;
1405
0
    }
1406
0
    nssSession_EnterMonitor(session); /* ==== session lock === */
1407
    /* Initialize the find with the template */
1408
0
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
1409
0
                                         cert_template, ctsize);
1410
0
    if (ckrv != CKR_OK) {
1411
0
        nssSession_ExitMonitor(session);
1412
0
        goto loser;
1413
0
    }
1414
0
    while (PR_TRUE) {
1415
        /* Issue the find for up to arraySize - numHandles objects */
1416
0
        ckrv = CKAPI(epv)->C_FindObjects(session->handle,
1417
0
                                         objectHandles + numHandles,
1418
0
                                         arraySize - numHandles,
1419
0
                                         &count);
1420
0
        if (ckrv != CKR_OK) {
1421
0
            nssSession_ExitMonitor(session);
1422
0
            goto loser;
1423
0
        }
1424
        /* bump the number of found objects */
1425
0
        numHandles += count;
1426
0
        if (numHandles < arraySize) {
1427
0
            break;
1428
0
        }
1429
        /* the array is filled, double it and continue */
1430
0
        arraySize *= 2;
1431
0
        objectHandles = nss_ZREALLOCARRAY(objectHandles,
1432
0
                                          CK_OBJECT_HANDLE,
1433
0
                                          arraySize);
1434
0
        if (!objectHandles) {
1435
0
            nssSession_ExitMonitor(session);
1436
0
            goto loser;
1437
0
        }
1438
0
    }
1439
0
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
1440
0
    nssSession_ExitMonitor(session); /* ==== end session lock === */
1441
0
    if (ckrv != CKR_OK) {
1442
0
        goto loser;
1443
0
    }
1444
0
    if (numHandles > 0) {
1445
0
        objects = create_objects_from_handles(token, session,
1446
0
                                              objectHandles, numHandles);
1447
0
        if (objects) {
1448
0
            nssCryptokiObject **op;
1449
0
            for (op = objects; *op; op++) {
1450
0
                (void)(*callback)(*op, arg);
1451
0
            }
1452
0
            nss_ZFreeIf(objects);
1453
0
        }
1454
0
    }
1455
0
    nssArena_Destroy(arena);
1456
0
    return PR_SUCCESS;
1457
0
loser:
1458
0
    nssArena_Destroy(arena);
1459
0
    return PR_FAILURE;
1460
0
}
1461
1462
NSS_IMPLEMENT PRBool
1463
nssToken_IsPrivateKeyAvailable(
1464
    NSSToken *token,
1465
    NSSCertificate *c,
1466
    nssCryptokiObject *instance)
1467
0
{
1468
0
    CK_OBJECT_CLASS theClass;
1469
1470
0
    if (token == NULL)
1471
0
        return PR_FALSE;
1472
0
    if (c == NULL)
1473
0
        return PR_FALSE;
1474
1475
0
    theClass = CKO_PRIVATE_KEY;
1476
0
    if (!nssSlot_IsLoggedIn(token->slot)) {
1477
0
        theClass = CKO_PUBLIC_KEY;
1478
0
    }
1479
0
    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) !=
1480
0
        CK_INVALID_HANDLE) {
1481
0
        return PR_TRUE;
1482
0
    }
1483
0
    return PR_FALSE;
1484
0
}