Coverage Report

Created: 2025-07-11 07:04

/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 PRBool
909
nss_TokenUsePKCS11Trust(NSSToken *tok)
910
0
{
911
0
    void *evp = nssToken_GetCryptokiEPV(tok);
912
0
    CK_VERSION vers;
913
914
0
    if (!evp) {
915
0
        return PR_FALSE;
916
0
    }
917
0
    vers = CKAPI(evp)->version;
918
0
    if (vers.major < 3) {
919
0
        return PR_FALSE;
920
0
    }
921
0
    if ((vers.major == 3) && (vers.minor < 2)) {
922
0
        return PR_FALSE;
923
0
    }
924
0
    return PR_TRUE;
925
0
}
926
927
static CK_TRUST
928
get_ck_trust(
929
    nssTrustLevel nssTrust, PRBool isPKCSTrust)
930
0
{
931
0
    CK_TRUST t;
932
0
    switch (nssTrust) {
933
0
        case nssTrustLevel_NotTrusted:
934
0
            t = isPKCSTrust ? CKT_NOT_TRUSTED : CKT_NSS_NOT_TRUSTED;
935
0
            break;
936
0
        case nssTrustLevel_TrustedDelegator:
937
0
            t = isPKCSTrust ? CKT_TRUST_ANCHOR : CKT_NSS_TRUSTED_DELEGATOR;
938
0
            break;
939
0
        case nssTrustLevel_ValidDelegator:
940
0
            t = isPKCSTrust ? CKT_TRUST_MUST_VERIFY_TRUST : CKT_NSS_VALID_DELEGATOR;
941
0
            break;
942
0
        case nssTrustLevel_Trusted:
943
0
            t = isPKCSTrust ? CKT_TRUSTED : CKT_NSS_TRUSTED;
944
0
            break;
945
0
        case nssTrustLevel_MustVerify:
946
0
            t = isPKCSTrust ? CKT_TRUST_MUST_VERIFY_TRUST : CKT_NSS_MUST_VERIFY_TRUST;
947
0
            break;
948
0
        case nssTrustLevel_Unknown:
949
0
        default:
950
0
            t = isPKCSTrust ? CKT_TRUST_UNKNOWN : CKT_NSS_TRUST_UNKNOWN;
951
0
            break;
952
0
    }
953
0
    return t;
954
0
}
955
956
NSS_IMPLEMENT nssCryptokiObject *
957
nssToken_ImportTrust(
958
    NSSToken *tok,
959
    nssSession *sessionOpt,
960
    NSSDER *certEncoding,
961
    NSSDER *certIssuer,
962
    NSSDER *certSerial,
963
    nssTrustLevel serverAuth,
964
    nssTrustLevel clientAuth,
965
    nssTrustLevel codeSigning,
966
    nssTrustLevel emailProtection,
967
    PRBool stepUpApproved,
968
    PRBool asTokenObject)
969
0
{
970
0
    nssCryptokiObject *object;
971
0
    CK_OBJECT_CLASS tobjc;
972
0
    CK_TRUST ckSA, ckCA, ckCS, ckEP;
973
0
    CK_ATTRIBUTE_PTR attr;
974
0
    CK_ATTRIBUTE trust_tmpl[11];
975
0
    CK_ULONG tsize;
976
0
    PRBool usePKCS11TrustToken = nss_TokenUsePKCS11Trust(tok);
977
0
    PRUint8 hashBuf[HASH_LENGTH_MAX];
978
0
    PRUint8 hashBuf2[HASH_LENGTH_MAX];
979
0
    CK_MECHANISM_TYPE hashMech;
980
981
0
    tobjc = usePKCS11TrustToken ? CKO_TRUST : CKO_NSS_TRUST;
982
0
    ckSA = get_ck_trust(serverAuth, usePKCS11TrustToken);
983
0
    ckCA = get_ck_trust(clientAuth, usePKCS11TrustToken);
984
0
    ckCS = get_ck_trust(codeSigning, usePKCS11TrustToken);
985
0
    ckEP = get_ck_trust(emailProtection, usePKCS11TrustToken);
986
0
    hashMech = usePKCS11TrustToken ? CKM_SHA256 : CKM_SHA_1;
987
988
0
    NSSItem hash_result, hash2_result;
989
0
    hash_result.data = hashBuf;
990
0
    hash_result.size = sizeof(hashBuf);
991
0
    NSSAlgorithm_DigestBuf(hashMech, certEncoding, &hash_result);
992
0
    if (!usePKCS11TrustToken) {
993
0
        hash2_result.data = hashBuf2;
994
0
        hash2_result.size = sizeof(hashBuf2);
995
0
        NSSAlgorithm_DigestBuf(CKM_MD5, certEncoding, &hash2_result);
996
0
    }
997
998
0
    NSS_CK_TEMPLATE_START(trust_tmpl, attr, tsize);
999
0
    if (asTokenObject) {
1000
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1001
0
    } else {
1002
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1003
0
    }
1004
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1005
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1006
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1007
0
    if (usePKCS11TrustToken) {
1008
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_HASH_OF_CERTIFICATE, &hash_result);
1009
0
        NSS_CK_SET_ATTRIBUTE_FIXED_PTR(attr, CKA_NAME_HASH_ALGORITHM, &hashMech);
1010
        /* now set the trust values */
1011
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_SERVER_AUTH, ckSA);
1012
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CLIENT_AUTH, ckCA);
1013
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_CODE_SIGNING, ckCS);
1014
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_PKCS_TRUST_EMAIL_PROTECTION, ckEP);
1015
0
    } else {
1016
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_SHA1_HASH, &hash_result);
1017
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_CERT_MD5_HASH, &hash2_result);
1018
        /* now set the trust values */
1019
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_SERVER_AUTH, ckSA);
1020
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CLIENT_AUTH, ckCA);
1021
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_CODE_SIGNING, ckCS);
1022
0
        NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_NSS_TRUST_EMAIL_PROTECTION, ckEP);
1023
0
        if (stepUpApproved) {
1024
0
            NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_TRUST_STEP_UP_APPROVED,
1025
0
                                      &g_ck_true);
1026
0
        } else {
1027
0
            NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_TRUST_STEP_UP_APPROVED,
1028
0
                                      &g_ck_false);
1029
0
        }
1030
0
    }
1031
0
    NSS_CK_TEMPLATE_FINISH(trust_tmpl, attr, tsize);
1032
    /* import the trust object onto the token */
1033
0
    object = import_object(tok, sessionOpt, trust_tmpl, tsize);
1034
0
    if (object && tok->cache) {
1035
0
        nssTokenObjectCache_ImportObject(tok->cache, object, tobjc,
1036
0
                                         trust_tmpl, tsize);
1037
0
    }
1038
0
    return object;
1039
0
}
1040
1041
NSS_IMPLEMENT nssCryptokiObject *
1042
nssToken_FindTrustForCertificate(
1043
    NSSToken *token,
1044
    nssSession *sessionOpt,
1045
    NSSDER *certEncoding,
1046
    NSSDER *certIssuer,
1047
    NSSDER *certSerial,
1048
    nssTokenSearchType searchType)
1049
0
{
1050
0
    CK_OBJECT_CLASS tobjc = CKO_TRUST;
1051
0
    CK_ATTRIBUTE_PTR attr;
1052
0
    CK_ATTRIBUTE tobj_template[5];
1053
0
    CK_ULONG tobj_size;
1054
0
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1055
0
    nssCryptokiObject *object = NULL, **objects;
1056
1057
    /* Don't ask the module to use an invalid session handle. */
1058
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1059
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1060
0
        return object;
1061
0
    }
1062
1063
0
    NSS_CK_TEMPLATE_START(tobj_template, attr, tobj_size);
1064
0
    if (searchType == nssTokenSearchType_TokenOnly) {
1065
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1066
0
    }
1067
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, tobjc);
1068
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_ISSUER, certIssuer);
1069
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SERIAL_NUMBER, certSerial);
1070
0
    NSS_CK_TEMPLATE_FINISH(tobj_template, attr, tobj_size);
1071
0
    objects = nssToken_FindObjectsByTemplate(token, session,
1072
0
                                             tobj_template, tobj_size,
1073
0
                                             1, NULL);
1074
0
    if (!objects) {
1075
0
        tobjc = CKO_NSS_TRUST;
1076
0
        objects = nssToken_FindObjectsByTemplate(token, session,
1077
0
                                                 tobj_template, tobj_size,
1078
0
                                                 1, NULL);
1079
0
    }
1080
1081
0
    if (objects) {
1082
0
        object = objects[0];
1083
0
        object->trustType = tobjc;
1084
0
        nss_ZFreeIf(objects);
1085
0
    }
1086
0
    return object;
1087
0
}
1088
1089
NSS_IMPLEMENT nssCryptokiObject *
1090
nssToken_ImportCRL(
1091
    NSSToken *token,
1092
    nssSession *sessionOpt,
1093
    NSSDER *subject,
1094
    NSSDER *encoding,
1095
    PRBool isKRL,
1096
    NSSUTF8 *url,
1097
    PRBool asTokenObject)
1098
0
{
1099
0
    nssCryptokiObject *object;
1100
0
    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1101
0
    CK_ATTRIBUTE_PTR attr;
1102
0
    CK_ATTRIBUTE crl_tmpl[6];
1103
0
    CK_ULONG crlsize;
1104
1105
0
    NSS_CK_TEMPLATE_START(crl_tmpl, attr, crlsize);
1106
0
    if (asTokenObject) {
1107
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1108
0
    } else {
1109
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1110
0
    }
1111
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1112
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1113
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_VALUE, encoding);
1114
0
    NSS_CK_SET_ATTRIBUTE_UTF8(attr, CKA_NSS_URL, url);
1115
0
    if (isKRL) {
1116
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_true);
1117
0
    } else {
1118
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_NSS_KRL, &g_ck_false);
1119
0
    }
1120
0
    NSS_CK_TEMPLATE_FINISH(crl_tmpl, attr, crlsize);
1121
1122
    /* import the crl object onto the token */
1123
0
    object = import_object(token, sessionOpt, crl_tmpl, crlsize);
1124
0
    if (object && token->cache) {
1125
0
        nssTokenObjectCache_ImportObject(token->cache, object, crlobjc,
1126
0
                                         crl_tmpl, crlsize);
1127
0
    }
1128
0
    return object;
1129
0
}
1130
1131
NSS_IMPLEMENT nssCryptokiObject **
1132
nssToken_FindCRLsBySubject(
1133
    NSSToken *token,
1134
    nssSession *sessionOpt,
1135
    NSSDER *subject,
1136
    nssTokenSearchType searchType,
1137
    PRUint32 maximumOpt,
1138
    PRStatus *statusOpt)
1139
0
{
1140
0
    CK_OBJECT_CLASS crlobjc = CKO_NSS_CRL;
1141
0
    CK_ATTRIBUTE_PTR attr;
1142
0
    CK_ATTRIBUTE crlobj_template[3];
1143
0
    CK_ULONG crlobj_size;
1144
0
    nssCryptokiObject **objects = NULL;
1145
0
    nssSession *session = sessionOpt ? sessionOpt : token->defaultSession;
1146
1147
    /* Don't ask the module to use an invalid session handle. */
1148
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1149
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1150
0
        return objects;
1151
0
    }
1152
1153
0
    NSS_CK_TEMPLATE_START(crlobj_template, attr, crlobj_size);
1154
0
    if (searchType == nssTokenSearchType_SessionOnly) {
1155
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1156
0
    } else if (searchType == nssTokenSearchType_TokenOnly ||
1157
0
               searchType == nssTokenSearchType_TokenForced) {
1158
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1159
0
    }
1160
0
    NSS_CK_SET_ATTRIBUTE_VAR(attr, CKA_CLASS, crlobjc);
1161
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_SUBJECT, subject);
1162
0
    NSS_CK_TEMPLATE_FINISH(crlobj_template, attr, crlobj_size);
1163
1164
0
    objects = nssToken_FindObjectsByTemplate(token, session,
1165
0
                                             crlobj_template, crlobj_size,
1166
0
                                             maximumOpt, statusOpt);
1167
0
    return objects;
1168
0
}
1169
1170
NSS_IMPLEMENT PRStatus
1171
nssToken_GetCachedObjectAttributes(
1172
    NSSToken *token,
1173
    NSSArena *arenaOpt,
1174
    nssCryptokiObject *object,
1175
    CK_OBJECT_CLASS objclass,
1176
    CK_ATTRIBUTE_PTR atemplate,
1177
    CK_ULONG atlen)
1178
0
{
1179
0
    if (!token->cache) {
1180
0
        return PR_FAILURE;
1181
0
    }
1182
0
    return nssTokenObjectCache_GetObjectAttributes(token->cache, arenaOpt,
1183
0
                                                   object, objclass,
1184
0
                                                   atemplate, atlen);
1185
0
}
1186
1187
NSS_IMPLEMENT NSSItem *
1188
nssToken_Digest(
1189
    NSSToken *tok,
1190
    nssSession *sessionOpt,
1191
    NSSAlgorithmAndParameters *ap,
1192
    NSSItem *data,
1193
    NSSItem *rvOpt,
1194
    NSSArena *arenaOpt)
1195
0
{
1196
0
    CK_RV ckrv;
1197
0
    CK_ULONG digestLen;
1198
0
    CK_BYTE_PTR digest;
1199
0
    NSSItem *rvItem = NULL;
1200
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1201
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1202
1203
    /* Don't ask the module to use an invalid session handle. */
1204
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1205
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1206
0
        return rvItem;
1207
0
    }
1208
1209
0
    nssSession_EnterMonitor(session);
1210
0
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1211
0
    if (ckrv != CKR_OK) {
1212
0
        nssSession_ExitMonitor(session);
1213
0
        return NULL;
1214
0
    }
1215
#if 0
1216
    /* XXX the standard says this should work, but it doesn't */
1217
    ckrv = CKAPI(epv)->C_Digest(session->handle, NULL, 0, NULL, &digestLen);
1218
    if (ckrv != CKR_OK) {
1219
  nssSession_ExitMonitor(session);
1220
  return NULL;
1221
    }
1222
#endif
1223
0
    digestLen = 0; /* XXX for now */
1224
0
    digest = NULL;
1225
0
    if (rvOpt) {
1226
0
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1227
0
            nssSession_ExitMonitor(session);
1228
            /* the error should be bad args */
1229
0
            return NULL;
1230
0
        }
1231
0
        if (rvOpt->data) {
1232
0
            digest = rvOpt->data;
1233
0
        }
1234
0
        digestLen = rvOpt->size;
1235
0
    }
1236
0
    if (!digest) {
1237
0
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1238
0
        if (!digest) {
1239
0
            nssSession_ExitMonitor(session);
1240
0
            return NULL;
1241
0
        }
1242
0
    }
1243
0
    ckrv = CKAPI(epv)->C_Digest(session->handle,
1244
0
                                (CK_BYTE_PTR)data->data,
1245
0
                                (CK_ULONG)data->size,
1246
0
                                (CK_BYTE_PTR)digest,
1247
0
                                &digestLen);
1248
0
    nssSession_ExitMonitor(session);
1249
0
    if (ckrv != CKR_OK) {
1250
0
        nss_ZFreeIf(digest);
1251
0
        return NULL;
1252
0
    }
1253
0
    if (!rvOpt) {
1254
0
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1255
0
    } else {
1256
0
        rvOpt->size = digestLen;
1257
0
        rvItem = rvOpt;
1258
0
    }
1259
0
    return rvItem;
1260
0
}
1261
1262
NSS_IMPLEMENT PRStatus
1263
nssToken_BeginDigest(
1264
    NSSToken *tok,
1265
    nssSession *sessionOpt,
1266
    NSSAlgorithmAndParameters *ap)
1267
0
{
1268
0
    CK_RV ckrv;
1269
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1270
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1271
1272
    /* Don't ask the module to use an invalid session handle. */
1273
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1274
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1275
0
        return PR_FAILURE;
1276
0
    }
1277
1278
0
    nssSession_EnterMonitor(session);
1279
0
    ckrv = CKAPI(epv)->C_DigestInit(session->handle, &ap->mechanism);
1280
0
    nssSession_ExitMonitor(session);
1281
0
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1282
0
}
1283
1284
NSS_IMPLEMENT PRStatus
1285
nssToken_ContinueDigest(
1286
    NSSToken *tok,
1287
    nssSession *sessionOpt,
1288
    NSSItem *item)
1289
0
{
1290
0
    CK_RV ckrv;
1291
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1292
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1293
1294
    /* Don't ask the module to use an invalid session handle. */
1295
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1296
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1297
0
        return PR_FAILURE;
1298
0
    }
1299
1300
0
    nssSession_EnterMonitor(session);
1301
0
    ckrv = CKAPI(epv)->C_DigestUpdate(session->handle,
1302
0
                                      (CK_BYTE_PTR)item->data,
1303
0
                                      (CK_ULONG)item->size);
1304
0
    nssSession_ExitMonitor(session);
1305
0
    return (ckrv == CKR_OK) ? PR_SUCCESS : PR_FAILURE;
1306
0
}
1307
1308
NSS_IMPLEMENT NSSItem *
1309
nssToken_FinishDigest(
1310
    NSSToken *tok,
1311
    nssSession *sessionOpt,
1312
    NSSItem *rvOpt,
1313
    NSSArena *arenaOpt)
1314
0
{
1315
0
    CK_RV ckrv;
1316
0
    CK_ULONG digestLen;
1317
0
    CK_BYTE_PTR digest;
1318
0
    NSSItem *rvItem = NULL;
1319
0
    void *epv = nssToken_GetCryptokiEPV(tok);
1320
0
    nssSession *session = (sessionOpt) ? sessionOpt : tok->defaultSession;
1321
1322
    /* Don't ask the module to use an invalid session handle. */
1323
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1324
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1325
0
        return NULL;
1326
0
    }
1327
1328
0
    nssSession_EnterMonitor(session);
1329
0
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, NULL, &digestLen);
1330
0
    if (ckrv != CKR_OK || digestLen == 0) {
1331
0
        nssSession_ExitMonitor(session);
1332
0
        return NULL;
1333
0
    }
1334
0
    digest = NULL;
1335
0
    if (rvOpt) {
1336
0
        if (rvOpt->size > 0 && rvOpt->size < digestLen) {
1337
0
            nssSession_ExitMonitor(session);
1338
            /* the error should be bad args */
1339
0
            return NULL;
1340
0
        }
1341
0
        if (rvOpt->data) {
1342
0
            digest = rvOpt->data;
1343
0
        }
1344
0
        digestLen = rvOpt->size;
1345
0
    }
1346
0
    if (!digest) {
1347
0
        digest = (CK_BYTE_PTR)nss_ZAlloc(arenaOpt, digestLen);
1348
0
        if (!digest) {
1349
0
            nssSession_ExitMonitor(session);
1350
0
            return NULL;
1351
0
        }
1352
0
    }
1353
0
    ckrv = CKAPI(epv)->C_DigestFinal(session->handle, digest, &digestLen);
1354
0
    nssSession_ExitMonitor(session);
1355
0
    if (ckrv != CKR_OK) {
1356
0
        nss_ZFreeIf(digest);
1357
0
        return NULL;
1358
0
    }
1359
0
    if (!rvOpt) {
1360
0
        rvItem = nssItem_Create(arenaOpt, NULL, digestLen, (void *)digest);
1361
0
    }
1362
0
    return rvItem;
1363
0
}
1364
1365
NSS_IMPLEMENT PRBool
1366
nssToken_IsPresent(
1367
    NSSToken *token)
1368
0
{
1369
0
    return nssSlot_IsTokenPresent(token->slot);
1370
0
}
1371
1372
/* Sigh.  The methods to find objects declared above cause problems with
1373
 * the low-level object cache in the softoken -- the objects are found in
1374
 * toto, then one wave of GetAttributes is done, then another.  Having a
1375
 * large number of objects causes the cache to be thrashed, as the objects
1376
 * are gone before there's any chance to ask for their attributes.
1377
 * So, for now, bringing back traversal methods for certs.  This way all of
1378
 * the cert's attributes can be grabbed immediately after finding it,
1379
 * increasing the likelihood that the cache takes care of it.
1380
 */
1381
NSS_IMPLEMENT PRStatus
1382
nssToken_TraverseCertificates(
1383
    NSSToken *token,
1384
    nssSession *sessionOpt,
1385
    nssTokenSearchType searchType,
1386
    PRStatus (*callback)(nssCryptokiObject *instance, void *arg),
1387
    void *arg)
1388
0
{
1389
0
    CK_RV ckrv;
1390
0
    CK_ULONG count;
1391
0
    CK_OBJECT_HANDLE *objectHandles;
1392
0
    CK_ATTRIBUTE_PTR attr;
1393
0
    CK_ATTRIBUTE cert_template[2];
1394
0
    CK_ULONG ctsize;
1395
0
    NSSArena *arena;
1396
0
    PRUint32 arraySize, numHandles;
1397
0
    nssCryptokiObject **objects;
1398
0
    void *epv = nssToken_GetCryptokiEPV(token);
1399
0
    nssSession *session = (sessionOpt) ? sessionOpt : token->defaultSession;
1400
1401
    /* Don't ask the module to use an invalid session handle. */
1402
0
    if (!session || session->handle == CK_INVALID_HANDLE) {
1403
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
1404
0
        return PR_FAILURE;
1405
0
    }
1406
1407
    /* template for all certs */
1408
0
    NSS_CK_TEMPLATE_START(cert_template, attr, ctsize);
1409
0
    if (searchType == nssTokenSearchType_SessionOnly) {
1410
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_false);
1411
0
    } else if (searchType == nssTokenSearchType_TokenOnly ||
1412
0
               searchType == nssTokenSearchType_TokenForced) {
1413
0
        NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_TOKEN, &g_ck_true);
1414
0
    }
1415
0
    NSS_CK_SET_ATTRIBUTE_ITEM(attr, CKA_CLASS, &g_ck_class_cert);
1416
0
    NSS_CK_TEMPLATE_FINISH(cert_template, attr, ctsize);
1417
1418
    /* the arena is only for the array of object handles */
1419
0
    arena = nssArena_Create();
1420
0
    if (!arena) {
1421
0
        return PR_FAILURE;
1422
0
    }
1423
0
    arraySize = OBJECT_STACK_SIZE;
1424
0
    numHandles = 0;
1425
0
    objectHandles = nss_ZNEWARRAY(arena, CK_OBJECT_HANDLE, arraySize);
1426
0
    if (!objectHandles) {
1427
0
        goto loser;
1428
0
    }
1429
0
    nssSession_EnterMonitor(session); /* ==== session lock === */
1430
    /* Initialize the find with the template */
1431
0
    ckrv = CKAPI(epv)->C_FindObjectsInit(session->handle,
1432
0
                                         cert_template, ctsize);
1433
0
    if (ckrv != CKR_OK) {
1434
0
        nssSession_ExitMonitor(session);
1435
0
        goto loser;
1436
0
    }
1437
0
    while (PR_TRUE) {
1438
        /* Issue the find for up to arraySize - numHandles objects */
1439
0
        ckrv = CKAPI(epv)->C_FindObjects(session->handle,
1440
0
                                         objectHandles + numHandles,
1441
0
                                         arraySize - numHandles,
1442
0
                                         &count);
1443
0
        if (ckrv != CKR_OK) {
1444
0
            nssSession_ExitMonitor(session);
1445
0
            goto loser;
1446
0
        }
1447
        /* bump the number of found objects */
1448
0
        numHandles += count;
1449
0
        if (numHandles < arraySize) {
1450
0
            break;
1451
0
        }
1452
        /* the array is filled, double it and continue */
1453
0
        arraySize *= 2;
1454
0
        objectHandles = nss_ZREALLOCARRAY(objectHandles,
1455
0
                                          CK_OBJECT_HANDLE,
1456
0
                                          arraySize);
1457
0
        if (!objectHandles) {
1458
0
            nssSession_ExitMonitor(session);
1459
0
            goto loser;
1460
0
        }
1461
0
    }
1462
0
    ckrv = CKAPI(epv)->C_FindObjectsFinal(session->handle);
1463
0
    nssSession_ExitMonitor(session); /* ==== end session lock === */
1464
0
    if (ckrv != CKR_OK) {
1465
0
        goto loser;
1466
0
    }
1467
0
    if (numHandles > 0) {
1468
0
        objects = create_objects_from_handles(token, session,
1469
0
                                              objectHandles, numHandles);
1470
0
        if (objects) {
1471
0
            nssCryptokiObject **op;
1472
0
            for (op = objects; *op; op++) {
1473
0
                (void)(*callback)(*op, arg);
1474
0
            }
1475
0
            nss_ZFreeIf(objects);
1476
0
        }
1477
0
    }
1478
0
    nssArena_Destroy(arena);
1479
0
    return PR_SUCCESS;
1480
0
loser:
1481
0
    nssArena_Destroy(arena);
1482
0
    return PR_FAILURE;
1483
0
}
1484
1485
NSS_IMPLEMENT PRBool
1486
nssToken_IsPrivateKeyAvailable(
1487
    NSSToken *token,
1488
    NSSCertificate *c,
1489
    nssCryptokiObject *instance)
1490
0
{
1491
0
    CK_OBJECT_CLASS theClass;
1492
1493
0
    if (token == NULL)
1494
0
        return PR_FALSE;
1495
0
    if (c == NULL)
1496
0
        return PR_FALSE;
1497
1498
0
    theClass = CKO_PRIVATE_KEY;
1499
0
    if (!nssSlot_IsLoggedIn(token->slot)) {
1500
0
        theClass = CKO_PUBLIC_KEY;
1501
0
    }
1502
0
    if (PK11_MatchItem(token->pk11slot, instance->handle, theClass) !=
1503
0
        CK_INVALID_HANDLE) {
1504
0
        return PR_TRUE;
1505
0
    }
1506
0
    return PR_FALSE;
1507
0
}