Coverage Report

Created: 2026-02-05 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/pk11wrap/pk11slot.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
/*
5
 * Deal with PKCS #11 Slots.
6
 */
7
8
#include <stddef.h>
9
10
#include "seccomon.h"
11
#include "secmod.h"
12
#include "nssilock.h"
13
#include "secmodi.h"
14
#include "secmodti.h"
15
#include "pkcs11t.h"
16
#include "pk11func.h"
17
#include "secitem.h"
18
#include "secerr.h"
19
20
#include "dev.h"
21
#include "dev3hack.h"
22
#include "pkim.h"
23
#include "utilpars.h"
24
#include "pkcs11uri.h"
25
26
/*************************************************************
27
 * local static and global data
28
 *************************************************************/
29
30
/*
31
 * This array helps parsing between names, mechanisms, and flags.
32
 * to make the config files understand more entries, add them
33
 * to this table.
34
 */
35
const PK11DefaultArrayEntry PK11_DefaultArray[] = {
36
    { "RSA", SECMOD_RSA_FLAG, CKM_RSA_PKCS },
37
    { "DSA", SECMOD_DSA_FLAG, CKM_DSA },
38
    { "ECC", SECMOD_ECC_FLAG, CKM_ECDSA },
39
    { "EDDSA", SECMOD_ECC_FLAG, CKM_EDDSA },
40
    { "DH", SECMOD_DH_FLAG, CKM_DH_PKCS_DERIVE },
41
    { "RC2", SECMOD_RC2_FLAG, CKM_RC2_CBC },
42
    { "RC4", SECMOD_RC4_FLAG, CKM_RC4 },
43
    { "DES", SECMOD_DES_FLAG, CKM_DES_CBC },
44
    { "AES", SECMOD_AES_FLAG, CKM_AES_CBC },
45
    { "Camellia", SECMOD_CAMELLIA_FLAG, CKM_CAMELLIA_CBC },
46
    { "SEED", SECMOD_SEED_FLAG, CKM_SEED_CBC },
47
    { "RC5", SECMOD_RC5_FLAG, CKM_RC5_CBC },
48
    { "SHA-1", SECMOD_SHA1_FLAG, CKM_SHA_1 },
49
    /*  { "SHA224", SECMOD_SHA256_FLAG, CKM_SHA224 }, */
50
    { "SHA256", SECMOD_SHA256_FLAG, CKM_SHA256 },
51
    /*  { "SHA384", SECMOD_SHA512_FLAG, CKM_SHA384 }, */
52
    { "SHA512", SECMOD_SHA512_FLAG, CKM_SHA512 },
53
    { "MD5", SECMOD_MD5_FLAG, CKM_MD5 },
54
    { "MD2", SECMOD_MD2_FLAG, CKM_MD2 },
55
    { "SSL", SECMOD_SSL_FLAG, CKM_SSL3_PRE_MASTER_KEY_GEN },
56
    { "TLS", SECMOD_TLS_FLAG, CKM_TLS_MASTER_KEY_DERIVE },
57
    { "SKIPJACK", SECMOD_FORTEZZA_FLAG, CKM_SKIPJACK_CBC64 },
58
    { "Publicly-readable certs", SECMOD_FRIENDLY_FLAG, CKM_INVALID_MECHANISM },
59
    { "Random Num Generator", SECMOD_RANDOM_FLAG, CKM_FAKE_RANDOM },
60
    { "ML-DSA", SECMOD_MLDSA_FLAG, CKM_ML_DSA },
61
};
62
const int num_pk11_default_mechanisms =
63
    sizeof(PK11_DefaultArray) / sizeof(PK11_DefaultArray[0]);
64
65
const PK11DefaultArrayEntry *
66
PK11_GetDefaultArray(int *size)
67
0
{
68
0
    if (size) {
69
0
        *size = num_pk11_default_mechanisms;
70
0
    }
71
0
    return PK11_DefaultArray;
72
0
}
73
74
/*
75
 * These  slotlists are lists of modules which provide default support for
76
 *  a given algorithm or mechanism.
77
 */
78
static PK11SlotList
79
    pk11_seedSlotList,
80
    pk11_camelliaSlotList,
81
    pk11_aesSlotList,
82
    pk11_desSlotList,
83
    pk11_rc4SlotList,
84
    pk11_rc2SlotList,
85
    pk11_rc5SlotList,
86
    pk11_sha1SlotList,
87
    pk11_md5SlotList,
88
    pk11_md2SlotList,
89
    pk11_rsaSlotList,
90
    pk11_dsaSlotList,
91
    pk11_dhSlotList,
92
    pk11_ecSlotList,
93
    pk11_ideaSlotList,
94
    pk11_sslSlotList,
95
    pk11_tlsSlotList,
96
    pk11_randomSlotList,
97
    pk11_sha256SlotList,
98
    pk11_sha512SlotList, /* slots do SHA512 and SHA384 */
99
    pk11_mldsaSlotList;
100
101
/************************************************************
102
 * Generic Slot List and Slot List element manipulations
103
 ************************************************************/
104
105
/*
106
 * allocate a new list
107
 */
108
PK11SlotList *
109
PK11_NewSlotList(void)
110
113k
{
111
113k
    PK11SlotList *list;
112
113
113k
    list = (PK11SlotList *)PORT_Alloc(sizeof(PK11SlotList));
114
113k
    if (list == NULL)
115
0
        return NULL;
116
113k
    list->head = NULL;
117
113k
    list->tail = NULL;
118
113k
    list->lock = PZ_NewLock(nssILockList);
119
113k
    if (list->lock == NULL) {
120
0
        PORT_Free(list);
121
0
        return NULL;
122
0
    }
123
124
113k
    return list;
125
113k
}
126
127
/*
128
 * free a list element when all the references go away.
129
 */
130
SECStatus
131
PK11_FreeSlotListElement(PK11SlotList *list, PK11SlotListElement *le)
132
1.42M
{
133
1.42M
    PRBool freeit = PR_FALSE;
134
135
1.42M
    if (list == NULL || le == NULL) {
136
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
137
0
        return SECFailure;
138
0
    }
139
140
1.42M
    PZ_Lock(list->lock);
141
1.42M
    if (le->refCount-- == 1) {
142
74.1k
        freeit = PR_TRUE;
143
74.1k
    }
144
1.42M
    PZ_Unlock(list->lock);
145
1.42M
    if (freeit) {
146
74.1k
        PK11_FreeSlot(le->slot);
147
74.1k
        PORT_Free(le);
148
74.1k
    }
149
1.42M
    return SECSuccess;
150
1.42M
}
151
152
static void
153
pk11_FreeSlotListStatic(PK11SlotList *list)
154
113k
{
155
113k
    PK11SlotListElement *le, *next;
156
113k
    if (list == NULL)
157
0
        return;
158
159
187k
    for (le = list->head; le; le = next) {
160
73.8k
        next = le->next;
161
73.8k
        PK11_FreeSlotListElement(list, le);
162
73.8k
    }
163
113k
    if (list->lock) {
164
113k
        PZ_DestroyLock(list->lock);
165
113k
    }
166
113k
    list->lock = NULL;
167
113k
    list->head = NULL;
168
113k
}
169
170
/*
171
 * if we are freeing the list, we must be the only ones with a pointer
172
 * to the list.
173
 */
174
void
175
PK11_FreeSlotList(PK11SlotList *list)
176
113k
{
177
113k
    pk11_FreeSlotListStatic(list);
178
113k
    PORT_Free(list);
179
113k
}
180
181
/*
182
 * add a slot to a list
183
 * "slot" is the slot to be added. Ownership is not transferred.
184
 * "sorted" indicates whether or not the slot should be inserted according to
185
 *   cipherOrder of the associated module. PR_FALSE indicates that the slot
186
 *   should be inserted to the head of the list.
187
 */
188
SECStatus
189
PK11_AddSlotToList(PK11SlotList *list, PK11SlotInfo *slot, PRBool sorted)
190
74.1k
{
191
74.1k
    PK11SlotListElement *le;
192
74.1k
    PK11SlotListElement *element;
193
194
74.1k
    le = (PK11SlotListElement *)PORT_Alloc(sizeof(PK11SlotListElement));
195
74.1k
    if (le == NULL)
196
0
        return SECFailure;
197
198
74.1k
    le->slot = PK11_ReferenceSlot(slot);
199
74.1k
    le->prev = NULL;
200
74.1k
    le->refCount = 1;
201
74.1k
    PZ_Lock(list->lock);
202
74.1k
    element = list->head;
203
    /* Insertion sort, with higher cipherOrders are sorted first in the list */
204
74.1k
    while (element && sorted && (element->slot->module->cipherOrder > le->slot->module->cipherOrder)) {
205
0
        element = element->next;
206
0
    }
207
74.1k
    if (element) {
208
36.9k
        le->prev = element->prev;
209
36.9k
        element->prev = le;
210
36.9k
        le->next = element;
211
37.2k
    } else {
212
37.2k
        le->prev = list->tail;
213
37.2k
        le->next = NULL;
214
37.2k
        list->tail = le;
215
37.2k
    }
216
74.1k
    if (le->prev)
217
0
        le->prev->next = le;
218
74.1k
    if (list->head == element)
219
74.1k
        list->head = le;
220
74.1k
    PZ_Unlock(list->lock);
221
222
74.1k
    return SECSuccess;
223
74.1k
}
224
225
/*
226
 * remove a slot entry from the list
227
 */
228
SECStatus
229
PK11_DeleteSlotFromList(PK11SlotList *list, PK11SlotListElement *le)
230
252
{
231
252
    PZ_Lock(list->lock);
232
252
    if (le->prev)
233
0
        le->prev->next = le->next;
234
252
    else
235
252
        list->head = le->next;
236
252
    if (le->next)
237
14
        le->next->prev = le->prev;
238
238
    else
239
238
        list->tail = le->prev;
240
252
    le->next = le->prev = NULL;
241
252
    PZ_Unlock(list->lock);
242
252
    PK11_FreeSlotListElement(list, le);
243
252
    return SECSuccess;
244
252
}
245
246
/*
247
 * Move a list to the end of the target list.
248
 * NOTE: There is no locking here... This assumes BOTH lists are private copy
249
 * lists. It also does not re-sort the target list.
250
 */
251
SECStatus
252
pk11_MoveListToList(PK11SlotList *target, PK11SlotList *src)
253
75.5k
{
254
75.5k
    if (src->head == NULL)
255
75.5k
        return SECSuccess;
256
257
0
    if (target->tail == NULL) {
258
0
        target->head = src->head;
259
0
    } else {
260
0
        target->tail->next = src->head;
261
0
    }
262
0
    src->head->prev = target->tail;
263
0
    target->tail = src->tail;
264
0
    src->head = src->tail = NULL;
265
0
    return SECSuccess;
266
75.5k
}
267
268
/*
269
 * get an element from the list with a reference. You must own the list.
270
 */
271
PK11SlotListElement *
272
PK11_GetFirstRef(PK11SlotList *list)
273
0
{
274
0
    PK11SlotListElement *le;
275
276
0
    le = list->head;
277
0
    if (le != NULL)
278
0
        (le)->refCount++;
279
0
    return le;
280
0
}
281
282
/*
283
 * get the next element from the list with a reference. You must own the list.
284
 */
285
PK11SlotListElement *
286
PK11_GetNextRef(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
287
0
{
288
0
    PK11SlotListElement *new_le;
289
0
    new_le = le->next;
290
0
    if (new_le)
291
0
        new_le->refCount++;
292
0
    PK11_FreeSlotListElement(list, le);
293
0
    return new_le;
294
0
}
295
296
/*
297
 * get an element safely from the list. This just makes sure that if
298
 * this element is not deleted while we deal with it.
299
 */
300
PK11SlotListElement *
301
PK11_GetFirstSafe(PK11SlotList *list)
302
1.34M
{
303
1.34M
    PK11SlotListElement *le;
304
305
1.34M
    PZ_Lock(list->lock);
306
1.34M
    le = list->head;
307
1.34M
    if (le != NULL)
308
1.34M
        (le)->refCount++;
309
1.34M
    PZ_Unlock(list->lock);
310
1.34M
    return le;
311
1.34M
}
312
313
/*
314
 * NOTE: if this element gets deleted, we can no longer safely traverse using
315
 * it's pointers. We can either terminate the loop, or restart from the
316
 * beginning. This is controlled by the restart option.
317
 */
318
PK11SlotListElement *
319
PK11_GetNextSafe(PK11SlotList *list, PK11SlotListElement *le, PRBool restart)
320
3.92k
{
321
3.92k
    PK11SlotListElement *new_le;
322
3.92k
    PZ_Lock(list->lock);
323
3.92k
    new_le = le->next;
324
3.92k
    if (le->next == NULL) {
325
        /* if the prev and next fields are NULL then either this element
326
         * has been removed and we need to walk the list again (if restart
327
         * is true) or this was the only element on the list */
328
3.50k
        if ((le->prev == NULL) && restart && (list->head != le)) {
329
0
            new_le = list->head;
330
0
        }
331
3.50k
    }
332
3.92k
    if (new_le)
333
420
        new_le->refCount++;
334
3.92k
    PZ_Unlock(list->lock);
335
3.92k
    PK11_FreeSlotListElement(list, le);
336
3.92k
    return new_le;
337
3.92k
}
338
339
/*
340
 * Find the element that holds this slot
341
 */
342
PK11SlotListElement *
343
PK11_FindSlotElement(PK11SlotList *list, PK11SlotInfo *slot)
344
252
{
345
252
    PK11SlotListElement *le;
346
347
252
    for (le = PK11_GetFirstSafe(list); le;
348
252
         le = PK11_GetNextSafe(list, le, PR_TRUE)) {
349
252
        if (le->slot == slot)
350
252
            return le;
351
252
    }
352
0
    return NULL;
353
252
}
354
355
/* like PORT_Memcmp, return -1 if the version is less then the
356
 * passed in version, 0 if it's equal to and 1 if it's greater than
357
 * the passed in version, PKCS #11 returns versions in 2 places,
358
 * once in the function table and once in the module. the former
359
 * is good to determine if it is safe to call a new function,
360
 * the latter is good for module functionality */
361
PRInt32
362
PK11_CheckPKCS11Version(PK11SlotInfo *slot, CK_BYTE major, CK_BYTE minor,
363
                        PRBool useFunctionTable)
364
216k
{
365
216k
    CK_VERSION version = useFunctionTable ? PK11_GETTAB(slot)->version : slot->module->cryptokiVersion;
366
367
216k
    if (version.major < major) {
368
0
        return -1;
369
216k
    } else if (version.major > major) {
370
0
        return 1;
371
216k
    } else if (version.minor < minor) {
372
0
        return -1;
373
216k
    } else if (version.minor > minor) {
374
204k
        return 1;
375
204k
    }
376
    /* if we get here, they must both be equal */
377
12.0k
    return 0;
378
216k
}
379
380
/************************************************************
381
 * Generic Slot Utilities
382
 ************************************************************/
383
/*
384
 * Create a new slot structure
385
 */
386
PK11SlotInfo *
387
PK11_NewSlotInfo(SECMODModule *mod)
388
32
{
389
32
    PK11SlotInfo *slot;
390
391
32
    slot = (PK11SlotInfo *)PORT_Alloc(sizeof(PK11SlotInfo));
392
32
    if (slot == NULL) {
393
0
        return slot;
394
0
    }
395
32
    slot->freeListLock = PZ_NewLock(nssILockFreelist);
396
32
    if (slot->freeListLock == NULL) {
397
0
        PORT_Free(slot);
398
0
        return NULL;
399
0
    }
400
32
    slot->nssTokenLock = PZ_NewLock(nssILockOther);
401
32
    if (slot->nssTokenLock == NULL) {
402
0
        PZ_DestroyLock(slot->freeListLock);
403
0
        PORT_Free(slot);
404
0
        return NULL;
405
0
    }
406
32
    slot->sessionLock = mod->isThreadSafe ? PZ_NewLock(nssILockSession) : mod->refLock;
407
32
    if (slot->sessionLock == NULL) {
408
0
        PZ_DestroyLock(slot->nssTokenLock);
409
0
        PZ_DestroyLock(slot->freeListLock);
410
0
        PORT_Free(slot);
411
0
        return NULL;
412
0
    }
413
32
    slot->freeSymKeysWithSessionHead = NULL;
414
32
    slot->freeSymKeysHead = NULL;
415
32
    slot->keyCount = 0;
416
32
    slot->maxKeyCount = 0;
417
32
    slot->functionList = NULL;
418
32
    slot->needTest = PR_TRUE;
419
32
    slot->isPerm = PR_FALSE;
420
32
    slot->isHW = PR_FALSE;
421
32
    slot->isInternal = PR_FALSE;
422
32
    slot->isThreadSafe = PR_FALSE;
423
32
    slot->disabled = PR_FALSE;
424
32
    slot->series = 1;
425
32
    slot->flagSeries = 0;
426
32
    slot->flagState = PR_FALSE;
427
32
    slot->wrapKey = 0;
428
32
    slot->wrapMechanism = CKM_INVALID_MECHANISM;
429
32
    slot->refKeys[0] = CK_INVALID_HANDLE;
430
32
    slot->reason = PK11_DIS_NONE;
431
32
    slot->readOnly = PR_TRUE;
432
32
    slot->needLogin = PR_FALSE;
433
32
    slot->hasRandom = PR_FALSE;
434
32
    slot->defRWSession = PR_FALSE;
435
32
    slot->protectedAuthPath = PR_FALSE;
436
32
    slot->flags = 0;
437
32
    slot->session = CK_INVALID_HANDLE;
438
32
    slot->slotID = 0;
439
32
    slot->defaultFlags = 0;
440
32
    slot->refCount = 1;
441
32
    slot->askpw = 0;
442
32
    slot->timeout = 0;
443
32
    slot->mechanismList = NULL;
444
32
    slot->mechanismCount = 0;
445
32
    slot->cert_array = NULL;
446
32
    slot->cert_count = 0;
447
32
    slot->slot_name[0] = 0;
448
32
    slot->token_name[0] = 0;
449
32
    PORT_Memset(slot->serial, ' ', sizeof(slot->serial));
450
32
    PORT_Memset(&slot->tokenInfo, 0, sizeof(slot->tokenInfo));
451
32
    slot->module = NULL;
452
32
    slot->authTransact = 0;
453
32
    slot->authTime = LL_ZERO;
454
32
    slot->minPassword = 0;
455
32
    slot->maxPassword = 0;
456
32
    slot->hasRootCerts = PR_FALSE;
457
32
    slot->hasRootTrust = PR_FALSE;
458
32
    slot->nssToken = NULL;
459
32
    slot->profileList = NULL;
460
32
    slot->profileCount = 0;
461
32
    slot->validationFIPSFlags = 0;
462
32
    return slot;
463
32
}
464
465
/* create a new reference to a slot so it doesn't go away */
466
PK11SlotInfo *
467
PK11_ReferenceSlot(PK11SlotInfo *slot)
468
51.7M
{
469
51.7M
    PR_ATOMIC_INCREMENT(&slot->refCount);
470
51.7M
    return slot;
471
51.7M
}
472
473
/* Destroy all info on a slot we have built up */
474
void
475
PK11_DestroySlot(PK11SlotInfo *slot)
476
28
{
477
    /* free up the cached keys and sessions */
478
28
    PK11_CleanKeyList(slot);
479
480
    /* free up all the sessions on this slot */
481
28
    if (slot->functionList) {
482
28
        PK11_GETTAB(slot)
483
28
            ->C_CloseAllSessions(slot->slotID);
484
28
    }
485
486
28
    if (slot->mechanismList) {
487
28
        PORT_Free(slot->mechanismList);
488
28
    }
489
28
    if (slot->profileList) {
490
0
        PORT_Free(slot->profileList);
491
0
    }
492
28
    if (slot->isThreadSafe && slot->sessionLock) {
493
28
        PZ_DestroyLock(slot->sessionLock);
494
28
    }
495
28
    slot->sessionLock = NULL;
496
28
    if (slot->freeListLock) {
497
28
        PZ_DestroyLock(slot->freeListLock);
498
28
        slot->freeListLock = NULL;
499
28
    }
500
28
    if (slot->nssTokenLock) {
501
28
        PZ_DestroyLock(slot->nssTokenLock);
502
28
        slot->nssTokenLock = NULL;
503
28
    }
504
505
    /* finally Tell our parent module that we've gone away so it can unload */
506
28
    if (slot->module) {
507
28
        SECMOD_SlotDestroyModule(slot->module, PR_TRUE);
508
28
    }
509
510
    /* ok, well not quit finally... now we free the memory */
511
28
    PORT_Free(slot);
512
28
}
513
514
/* We're all done with the slot, free it */
515
void
516
PK11_FreeSlot(PK11SlotInfo *slot)
517
51.7M
{
518
51.7M
    if (PR_ATOMIC_DECREMENT(&slot->refCount) == 0) {
519
28
        PK11_DestroySlot(slot);
520
28
    }
521
51.7M
}
522
523
void
524
PK11_EnterSlotMonitor(PK11SlotInfo *slot)
525
1.98M
{
526
1.98M
    PZ_Lock(slot->sessionLock);
527
1.98M
}
528
529
void
530
PK11_ExitSlotMonitor(PK11SlotInfo *slot)
531
1.98M
{
532
1.98M
    PZ_Unlock(slot->sessionLock);
533
1.98M
}
534
535
/***********************************************************
536
 * Functions to find specific slots.
537
 ***********************************************************/
538
PRBool
539
SECMOD_HasRootCerts(void)
540
0
{
541
0
    SECMODModuleList *mlp;
542
0
    SECMODModuleList *modules;
543
0
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
544
0
    int i;
545
0
    PRBool found = PR_FALSE;
546
547
0
    if (!moduleLock) {
548
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
549
0
        return found;
550
0
    }
551
552
    /* work through all the slots */
553
0
    SECMOD_GetReadLock(moduleLock);
554
0
    modules = SECMOD_GetDefaultModuleList();
555
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
556
0
        for (i = 0; i < mlp->module->slotCount; i++) {
557
0
            PK11SlotInfo *tmpSlot = mlp->module->slots[i];
558
0
            if (PK11_IsPresent(tmpSlot)) {
559
0
                if (tmpSlot->hasRootCerts) {
560
0
                    found = PR_TRUE;
561
0
                    break;
562
0
                }
563
0
            }
564
0
        }
565
0
        if (found)
566
0
            break;
567
0
    }
568
0
    SECMOD_ReleaseReadLock(moduleLock);
569
570
0
    return found;
571
0
}
572
573
/***********************************************************
574
 * Functions to find specific slots.
575
 ***********************************************************/
576
PK11SlotList *
577
PK11_FindSlotsByNames(const char *dllName, const char *slotName,
578
                      const char *tokenName, PRBool presentOnly)
579
0
{
580
0
    SECMODModuleList *mlp;
581
0
    SECMODModuleList *modules;
582
0
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
583
0
    int i;
584
0
    PK11SlotList *slotList = NULL;
585
0
    PRUint32 slotcount = 0;
586
0
    SECStatus rv = SECSuccess;
587
588
0
    if (!moduleLock) {
589
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
590
0
        return slotList;
591
0
    }
592
593
0
    slotList = PK11_NewSlotList();
594
0
    if (!slotList) {
595
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
596
0
        return slotList;
597
0
    }
598
599
0
    if (((NULL == dllName) || (0 == *dllName)) &&
600
0
        ((NULL == slotName) || (0 == *slotName)) &&
601
0
        ((NULL == tokenName) || (0 == *tokenName))) {
602
        /* default to softoken */
603
        /* PK11_GetInternalKeySlot increments the refcount on the internal slot,
604
         * but so does PK11_AddSlotToList. To avoid erroneously increasing the
605
         * refcount twice, we get our own reference to the internal slot and
606
         * decrement its refcount when we're done with it. */
607
0
        PK11SlotInfo *internalKeySlot = PK11_GetInternalKeySlot();
608
0
        PK11_AddSlotToList(slotList, internalKeySlot, PR_TRUE);
609
0
        PK11_FreeSlot(internalKeySlot);
610
0
        return slotList;
611
0
    }
612
613
    /* work through all the slots */
614
0
    SECMOD_GetReadLock(moduleLock);
615
0
    modules = SECMOD_GetDefaultModuleList();
616
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
617
0
        PORT_Assert(mlp->module);
618
0
        if (!mlp->module) {
619
0
            rv = SECFailure;
620
0
            break;
621
0
        }
622
0
        if ((!dllName) || (mlp->module->dllName &&
623
0
                           (0 == PORT_Strcmp(mlp->module->dllName, dllName)))) {
624
0
            for (i = 0; i < mlp->module->slotCount; i++) {
625
0
                PK11SlotInfo *tmpSlot = (mlp->module->slots ? mlp->module->slots[i] : NULL);
626
0
                PORT_Assert(tmpSlot);
627
0
                if (!tmpSlot) {
628
0
                    rv = SECFailure;
629
0
                    break;
630
0
                }
631
0
                if ((PR_FALSE == presentOnly || PK11_IsPresent(tmpSlot)) &&
632
0
                    ((!tokenName) ||
633
0
                     (0 == PORT_Strcmp(tmpSlot->token_name, tokenName))) &&
634
0
                    ((!slotName) ||
635
0
                     (0 == PORT_Strcmp(tmpSlot->slot_name, slotName)))) {
636
0
                    PK11_AddSlotToList(slotList, tmpSlot, PR_TRUE);
637
0
                    slotcount++;
638
0
                }
639
0
            }
640
0
        }
641
0
    }
642
0
    SECMOD_ReleaseReadLock(moduleLock);
643
644
0
    if ((0 == slotcount) || (SECFailure == rv)) {
645
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
646
0
        PK11_FreeSlotList(slotList);
647
0
        slotList = NULL;
648
0
    }
649
650
0
    if (SECFailure == rv) {
651
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
652
0
    }
653
654
0
    return slotList;
655
0
}
656
657
typedef PRBool (*PK11SlotMatchFunc)(PK11SlotInfo *slot, const void *arg);
658
659
static PRBool
660
pk11_MatchSlotByTokenName(PK11SlotInfo *slot, const void *arg)
661
0
{
662
0
    return PORT_Strcmp(slot->token_name, arg) == 0;
663
0
}
664
665
static PRBool
666
pk11_MatchSlotBySerial(PK11SlotInfo *slot, const void *arg)
667
0
{
668
0
    return PORT_Memcmp(slot->serial, arg, sizeof(slot->serial)) == 0;
669
0
}
670
671
static PRBool
672
pk11_MatchSlotByTokenURI(PK11SlotInfo *slot, const void *arg)
673
0
{
674
0
    return pk11_MatchUriTokenInfo(slot, (PK11URI *)arg);
675
0
}
676
677
static PK11SlotInfo *
678
pk11_FindSlot(const void *arg, PK11SlotMatchFunc func)
679
0
{
680
0
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
681
0
    SECMODModuleList *mlp;
682
0
    SECMODModuleList *modules;
683
0
    int i;
684
0
    PK11SlotInfo *slot = NULL;
685
686
0
    if (!moduleLock) {
687
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
688
0
        return slot;
689
0
    }
690
    /* work through all the slots */
691
0
    SECMOD_GetReadLock(moduleLock);
692
0
    modules = SECMOD_GetDefaultModuleList();
693
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
694
0
        for (i = 0; i < mlp->module->slotCount; i++) {
695
0
            PK11SlotInfo *tmpSlot = mlp->module->slots[i];
696
0
            if (PK11_IsPresent(tmpSlot)) {
697
0
                if (func(tmpSlot, arg)) {
698
0
                    slot = PK11_ReferenceSlot(tmpSlot);
699
0
                    break;
700
0
                }
701
0
            }
702
0
        }
703
0
        if (slot != NULL)
704
0
            break;
705
0
    }
706
0
    SECMOD_ReleaseReadLock(moduleLock);
707
708
0
    if (slot == NULL) {
709
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
710
0
    }
711
712
0
    return slot;
713
0
}
714
715
static PK11SlotInfo *
716
pk11_FindSlotByTokenURI(const char *uriString)
717
0
{
718
0
    PK11SlotInfo *slot = NULL;
719
0
    PK11URI *uri;
720
721
0
    uri = PK11URI_ParseURI(uriString);
722
0
    if (!uri) {
723
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
724
0
        return slot;
725
0
    }
726
727
0
    slot = pk11_FindSlot(uri, pk11_MatchSlotByTokenURI);
728
0
    PK11URI_DestroyURI(uri);
729
0
    return slot;
730
0
}
731
732
PK11SlotInfo *
733
PK11_FindSlotByName(const char *name)
734
0
{
735
0
    if ((name == NULL) || (*name == 0)) {
736
0
        return PK11_GetInternalKeySlot();
737
0
    }
738
739
0
    if (!PORT_Strncasecmp(name, "pkcs11:", strlen("pkcs11:"))) {
740
0
        return pk11_FindSlotByTokenURI(name);
741
0
    }
742
743
0
    return pk11_FindSlot(name, pk11_MatchSlotByTokenName);
744
0
}
745
746
PK11SlotInfo *
747
PK11_FindSlotBySerial(char *serial)
748
0
{
749
0
    return pk11_FindSlot(serial, pk11_MatchSlotBySerial);
750
0
}
751
752
/*
753
 * notification stub. If we ever get interested in any events that
754
 * the pkcs11 functions may pass back to use, we can catch them here...
755
 * currently pdata is a slotinfo structure.
756
 */
757
CK_RV
758
pk11_notify(CK_SESSION_HANDLE session, CK_NOTIFICATION event,
759
            CK_VOID_PTR pdata)
760
0
{
761
0
    return CKR_OK;
762
0
}
763
764
/*
765
 * grab a new RW session
766
 * !!! has a side effect of grabbing the Monitor if either the slot's default
767
 * session is RW or the slot is not thread safe. Monitor is release in function
768
 * below
769
 */
770
CK_SESSION_HANDLE
771
PK11_GetRWSession(PK11SlotInfo *slot)
772
0
{
773
0
    CK_SESSION_HANDLE rwsession;
774
0
    CK_RV crv;
775
0
    PRBool haveMonitor = PR_FALSE;
776
777
0
    if (!slot->isThreadSafe || slot->defRWSession) {
778
0
        PK11_EnterSlotMonitor(slot);
779
0
        haveMonitor = PR_TRUE;
780
0
    }
781
0
    if (slot->defRWSession) {
782
0
        PORT_Assert(slot->session != CK_INVALID_HANDLE);
783
0
        if (slot->session != CK_INVALID_HANDLE)
784
0
            return slot->session;
785
0
    }
786
787
0
    crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
788
0
                                           CKF_RW_SESSION | CKF_SERIAL_SESSION,
789
0
                                           slot, pk11_notify, &rwsession);
790
0
    PORT_Assert(rwsession != CK_INVALID_HANDLE || crv != CKR_OK);
791
0
    if (crv != CKR_OK || rwsession == CK_INVALID_HANDLE) {
792
0
        if (crv == CKR_OK)
793
0
            crv = CKR_DEVICE_ERROR;
794
0
        if (haveMonitor)
795
0
            PK11_ExitSlotMonitor(slot);
796
0
        PORT_SetError(PK11_MapError(crv));
797
0
        return CK_INVALID_HANDLE;
798
0
    }
799
0
    if (slot->defRWSession) { /* we have the monitor */
800
0
        slot->session = rwsession;
801
0
    }
802
0
    return rwsession;
803
0
}
804
805
PRBool
806
PK11_RWSessionHasLock(PK11SlotInfo *slot, CK_SESSION_HANDLE session_handle)
807
0
{
808
0
    PRBool hasLock;
809
0
    hasLock = (PRBool)(!slot->isThreadSafe ||
810
0
                       (slot->defRWSession && slot->session != CK_INVALID_HANDLE));
811
0
    return hasLock;
812
0
}
813
814
static PRBool
815
pk11_RWSessionIsDefault(PK11SlotInfo *slot, CK_SESSION_HANDLE rwsession)
816
0
{
817
0
    PRBool isDefault;
818
0
    isDefault = (PRBool)(slot->session == rwsession &&
819
0
                         slot->defRWSession &&
820
0
                         slot->session != CK_INVALID_HANDLE);
821
0
    return isDefault;
822
0
}
823
824
/*
825
 * close the rwsession and restore our readonly session
826
 * !!! has a side effect of releasing the Monitor if either the slot's default
827
 * session is RW or the slot is not thread safe.
828
 */
829
void
830
PK11_RestoreROSession(PK11SlotInfo *slot, CK_SESSION_HANDLE rwsession)
831
0
{
832
0
    PORT_Assert(rwsession != CK_INVALID_HANDLE);
833
0
    if (rwsession != CK_INVALID_HANDLE) {
834
0
        PRBool doExit = PK11_RWSessionHasLock(slot, rwsession);
835
0
        if (!pk11_RWSessionIsDefault(slot, rwsession))
836
0
            PK11_GETTAB(slot)
837
0
                ->C_CloseSession(rwsession);
838
0
        if (doExit)
839
0
            PK11_ExitSlotMonitor(slot);
840
0
    }
841
0
}
842
843
/************************************************************
844
 * Manage the built-In Slot Lists
845
 ************************************************************/
846
847
/* Init the static built int slot list (should actually integrate
848
 * with PK11_NewSlotList */
849
static void
850
pk11_InitSlotListStatic(PK11SlotList *list)
851
336
{
852
336
    list->lock = PZ_NewLock(nssILockList);
853
336
    list->head = NULL;
854
336
}
855
856
/* initialize the system slotlists */
857
SECStatus
858
PK11_InitSlotLists(void)
859
16
{
860
16
    pk11_InitSlotListStatic(&pk11_seedSlotList);
861
16
    pk11_InitSlotListStatic(&pk11_camelliaSlotList);
862
16
    pk11_InitSlotListStatic(&pk11_aesSlotList);
863
16
    pk11_InitSlotListStatic(&pk11_desSlotList);
864
16
    pk11_InitSlotListStatic(&pk11_rc4SlotList);
865
16
    pk11_InitSlotListStatic(&pk11_rc2SlotList);
866
16
    pk11_InitSlotListStatic(&pk11_rc5SlotList);
867
16
    pk11_InitSlotListStatic(&pk11_md5SlotList);
868
16
    pk11_InitSlotListStatic(&pk11_md2SlotList);
869
16
    pk11_InitSlotListStatic(&pk11_sha1SlotList);
870
16
    pk11_InitSlotListStatic(&pk11_rsaSlotList);
871
16
    pk11_InitSlotListStatic(&pk11_dsaSlotList);
872
16
    pk11_InitSlotListStatic(&pk11_dhSlotList);
873
16
    pk11_InitSlotListStatic(&pk11_ecSlotList);
874
16
    pk11_InitSlotListStatic(&pk11_ideaSlotList);
875
16
    pk11_InitSlotListStatic(&pk11_sslSlotList);
876
16
    pk11_InitSlotListStatic(&pk11_tlsSlotList);
877
16
    pk11_InitSlotListStatic(&pk11_randomSlotList);
878
16
    pk11_InitSlotListStatic(&pk11_sha256SlotList);
879
16
    pk11_InitSlotListStatic(&pk11_sha512SlotList);
880
16
    pk11_InitSlotListStatic(&pk11_mldsaSlotList);
881
16
    return SECSuccess;
882
16
}
883
884
void
885
PK11_DestroySlotLists(void)
886
14
{
887
14
    pk11_FreeSlotListStatic(&pk11_seedSlotList);
888
14
    pk11_FreeSlotListStatic(&pk11_camelliaSlotList);
889
14
    pk11_FreeSlotListStatic(&pk11_aesSlotList);
890
14
    pk11_FreeSlotListStatic(&pk11_desSlotList);
891
14
    pk11_FreeSlotListStatic(&pk11_rc4SlotList);
892
14
    pk11_FreeSlotListStatic(&pk11_rc2SlotList);
893
14
    pk11_FreeSlotListStatic(&pk11_rc5SlotList);
894
14
    pk11_FreeSlotListStatic(&pk11_md5SlotList);
895
14
    pk11_FreeSlotListStatic(&pk11_md2SlotList);
896
14
    pk11_FreeSlotListStatic(&pk11_sha1SlotList);
897
14
    pk11_FreeSlotListStatic(&pk11_rsaSlotList);
898
14
    pk11_FreeSlotListStatic(&pk11_dsaSlotList);
899
14
    pk11_FreeSlotListStatic(&pk11_dhSlotList);
900
14
    pk11_FreeSlotListStatic(&pk11_ecSlotList);
901
14
    pk11_FreeSlotListStatic(&pk11_ideaSlotList);
902
14
    pk11_FreeSlotListStatic(&pk11_sslSlotList);
903
14
    pk11_FreeSlotListStatic(&pk11_tlsSlotList);
904
14
    pk11_FreeSlotListStatic(&pk11_randomSlotList);
905
14
    pk11_FreeSlotListStatic(&pk11_sha256SlotList);
906
14
    pk11_FreeSlotListStatic(&pk11_sha512SlotList);
907
14
    pk11_FreeSlotListStatic(&pk11_mldsaSlotList);
908
14
    return;
909
14
}
910
911
/* return a system slot list based on mechanism */
912
PK11SlotList *
913
PK11_GetSlotList(CK_MECHANISM_TYPE type)
914
1.34M
{
915
/* XXX a workaround for Bugzilla bug #55267 */
916
#if defined(HPUX) && defined(__LP64__)
917
    if (CKM_INVALID_MECHANISM == type)
918
        return NULL;
919
#endif
920
1.34M
    switch (type) {
921
30
        case CKM_SEED_CBC:
922
30
        case CKM_SEED_ECB:
923
30
            return &pk11_seedSlotList;
924
30
        case CKM_CAMELLIA_CBC:
925
30
        case CKM_CAMELLIA_ECB:
926
30
            return &pk11_camelliaSlotList;
927
34
        case CKM_AES_CBC:
928
41
        case CKM_AES_CCM:
929
41
        case CKM_AES_CTR:
930
41
        case CKM_AES_CTS:
931
105
        case CKM_AES_GCM:
932
518
        case CKM_AES_ECB:
933
518
            return &pk11_aesSlotList;
934
30
        case CKM_DES_CBC:
935
30
        case CKM_DES_ECB:
936
30
        case CKM_DES3_ECB:
937
30
        case CKM_DES3_CBC:
938
30
            return &pk11_desSlotList;
939
30
        case CKM_RC4:
940
30
            return &pk11_rc4SlotList;
941
184
        case CKM_RC5_CBC:
942
184
            return &pk11_rc5SlotList;
943
277k
        case CKM_SHA_1:
944
277k
            return &pk11_sha1SlotList;
945
210k
        case CKM_SHA224:
946
350k
        case CKM_SHA256:
947
358k
        case CKM_SHA3_224:
948
370k
        case CKM_SHA3_256:
949
370k
            return &pk11_sha256SlotList;
950
55.0k
        case CKM_SHA384:
951
117k
        case CKM_SHA512:
952
127k
        case CKM_SHA3_384:
953
129k
        case CKM_SHA3_512:
954
129k
            return &pk11_sha512SlotList;
955
51.5k
        case CKM_MD5:
956
51.5k
            return &pk11_md5SlotList;
957
175
        case CKM_MD2:
958
175
            return &pk11_md2SlotList;
959
0
        case CKM_RC2_ECB:
960
666
        case CKM_RC2_CBC:
961
666
            return &pk11_rc2SlotList;
962
1.41k
        case CKM_RSA_PKCS:
963
1.41k
        case CKM_RSA_PKCS_KEY_PAIR_GEN:
964
1.41k
        case CKM_RSA_X_509:
965
1.41k
            return &pk11_rsaSlotList;
966
3.60k
        case CKM_DSA:
967
3.60k
            return &pk11_dsaSlotList;
968
7.76k
        case CKM_DH_PKCS_KEY_PAIR_GEN:
969
7.79k
        case CKM_DH_PKCS_DERIVE:
970
7.79k
            return &pk11_dhSlotList;
971
30
        case CKM_EDDSA:
972
30
        case CKM_EC_EDWARDS_KEY_PAIR_GEN:
973
232
        case CKM_ECDSA:
974
446
        case CKM_ECDSA_SHA1:
975
20.0k
        case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */
976
20.0k
        case CKM_NSS_ECDHE_NO_PAIRWISE_CHECK_KEY_PAIR_GEN:
977
161k
        case CKM_ECDH1_DERIVE:
978
161k
        case CKM_NSS_KYBER_KEY_PAIR_GEN: /* Bug 1893029 */
979
161k
        case CKM_NSS_KYBER:
980
161k
        case CKM_NSS_ML_KEM_KEY_PAIR_GEN: /* Bug 1893029 */
981
161k
        case CKM_NSS_ML_KEM:
982
176k
        case CKM_ML_KEM_KEY_PAIR_GEN: /* Bug 1893029 */
983
176k
        case CKM_ML_KEM:
984
176k
            return &pk11_ecSlotList;
985
17.6k
        case CKM_SSL3_PRE_MASTER_KEY_GEN:
986
17.6k
        case CKM_SSL3_MASTER_KEY_DERIVE:
987
17.6k
        case CKM_SSL3_SHA1_MAC:
988
17.6k
        case CKM_SSL3_MD5_MAC:
989
17.6k
            return &pk11_sslSlotList;
990
30
        case CKM_TLS_MASTER_KEY_DERIVE:
991
30
        case CKM_TLS_KEY_AND_MAC_DERIVE:
992
30
        case CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256:
993
30
            return &pk11_tlsSlotList;
994
13
        case CKM_IDEA_CBC:
995
23
        case CKM_IDEA_ECB:
996
23
            return &pk11_ideaSlotList;
997
276k
        case CKM_FAKE_RANDOM:
998
276k
            return &pk11_randomSlotList;
999
0
        case CKM_ML_DSA:
1000
0
            return &pk11_mldsaSlotList;
1001
1.34M
    }
1002
33.7k
    return NULL;
1003
1.34M
}
1004
1005
/*
1006
 * load the static SlotInfo structures used to select a PKCS11 slot.
1007
 * preSlotInfo has a list of all the default flags for the slots on this
1008
 * module.
1009
 */
1010
void
1011
PK11_LoadSlotList(PK11SlotInfo *slot, PK11PreSlotInfo *psi, int count)
1012
32
{
1013
32
    int i;
1014
1015
48
    for (i = 0; i < count; i++) {
1016
32
        if (psi[i].slotID == slot->slotID)
1017
16
            break;
1018
32
    }
1019
1020
32
    if (i == count)
1021
16
        return;
1022
1023
16
    slot->defaultFlags = psi[i].defaultFlags;
1024
16
    slot->askpw = psi[i].askpw;
1025
16
    slot->timeout = psi[i].timeout;
1026
16
    slot->hasRootCerts = psi[i].hasRootCerts;
1027
1028
    /* if the slot is already disabled, don't load them into the
1029
     * default slot lists. We get here so we can save the default
1030
     * list value. */
1031
16
    if (slot->disabled)
1032
0
        return;
1033
1034
    /* if the user has disabled us, don't load us in */
1035
16
    if (slot->defaultFlags & PK11_DISABLE_FLAG) {
1036
0
        slot->disabled = PR_TRUE;
1037
0
        slot->reason = PK11_DIS_USER_SELECTED;
1038
        /* free up sessions and things?? */
1039
0
        return;
1040
0
    }
1041
1042
384
    for (i = 0; i < num_pk11_default_mechanisms; i++) {
1043
368
        if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
1044
288
            CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
1045
288
            PK11SlotList *slotList = PK11_GetSlotList(mechanism);
1046
1047
288
            if (slotList)
1048
288
                PK11_AddSlotToList(slotList, slot, PR_FALSE);
1049
288
        }
1050
368
    }
1051
1052
16
    return;
1053
16
}
1054
1055
/*
1056
 * update a slot to its new attribute according to the slot list
1057
 * returns: SECSuccess if nothing to do or add/delete is successful
1058
 */
1059
SECStatus
1060
PK11_UpdateSlotAttribute(PK11SlotInfo *slot,
1061
                         const PK11DefaultArrayEntry *entry,
1062
                         PRBool add)
1063
/* add: PR_TRUE if want to turn on */
1064
0
{
1065
0
    SECStatus result = SECSuccess;
1066
0
    PK11SlotList *slotList = PK11_GetSlotList(entry->mechanism);
1067
1068
0
    if (add) { /* trying to turn on a mechanism */
1069
1070
        /* turn on the default flag in the slot */
1071
0
        slot->defaultFlags |= entry->flag;
1072
1073
        /* add this slot to the list */
1074
0
        if (slotList != NULL)
1075
0
            result = PK11_AddSlotToList(slotList, slot, PR_FALSE);
1076
1077
0
    } else { /* trying to turn off */
1078
1079
        /* turn OFF the flag in the slot */
1080
0
        slot->defaultFlags &= ~entry->flag;
1081
1082
0
        if (slotList) {
1083
            /* find the element in the list & delete it */
1084
0
            PK11SlotListElement *le = PK11_FindSlotElement(slotList, slot);
1085
1086
            /* remove the slot from the list */
1087
0
            if (le)
1088
0
                result = PK11_DeleteSlotFromList(slotList, le);
1089
0
        }
1090
0
    }
1091
0
    return result;
1092
0
}
1093
1094
/*
1095
 * clear a slot off of all of it's default list
1096
 */
1097
void
1098
PK11_ClearSlotList(PK11SlotInfo *slot)
1099
28
{
1100
28
    int i;
1101
1102
28
    if (slot->disabled)
1103
0
        return;
1104
28
    if (slot->defaultFlags == 0)
1105
14
        return;
1106
1107
336
    for (i = 0; i < num_pk11_default_mechanisms; i++) {
1108
322
        if (slot->defaultFlags & PK11_DefaultArray[i].flag) {
1109
252
            CK_MECHANISM_TYPE mechanism = PK11_DefaultArray[i].mechanism;
1110
252
            PK11SlotList *slotList = PK11_GetSlotList(mechanism);
1111
252
            PK11SlotListElement *le = NULL;
1112
1113
252
            if (slotList)
1114
252
                le = PK11_FindSlotElement(slotList, slot);
1115
1116
252
            if (le) {
1117
252
                PK11_DeleteSlotFromList(slotList, le);
1118
252
                PK11_FreeSlotListElement(slotList, le);
1119
252
            }
1120
252
        }
1121
322
    }
1122
14
}
1123
1124
/******************************************************************
1125
 *           Slot initialization
1126
 ******************************************************************/
1127
/*
1128
 * turn a PKCS11 Static Label into a string
1129
 */
1130
char *
1131
PK11_MakeString(PLArenaPool *arena, char *space,
1132
                char *staticString, int stringLen)
1133
64
{
1134
64
    int i;
1135
64
    char *newString;
1136
1.13k
    for (i = (stringLen - 1); i >= 0; i--) {
1137
1.13k
        if (staticString[i] != ' ')
1138
64
            break;
1139
1.13k
    }
1140
    /* move i to point to the last space */
1141
64
    i++;
1142
64
    if (arena) {
1143
0
        newString = (char *)PORT_ArenaAlloc(arena, i + 1 /* space for NULL */);
1144
64
    } else if (space) {
1145
64
        newString = space;
1146
64
    } else {
1147
0
        newString = (char *)PORT_Alloc(i + 1 /* space for NULL */);
1148
0
    }
1149
64
    if (newString == NULL)
1150
0
        return NULL;
1151
1152
64
    if (i)
1153
64
        PORT_Memcpy(newString, staticString, i);
1154
64
    newString[i] = 0;
1155
1156
64
    return newString;
1157
64
}
1158
1159
/*
1160
 * check if a null-terminated string matches with a PKCS11 Static Label
1161
 */
1162
PRBool
1163
pk11_MatchString(const char *string,
1164
                 const char *staticString, size_t staticStringLen)
1165
0
{
1166
0
    size_t i = staticStringLen;
1167
1168
    /* move i to point to the last space */
1169
0
    while (i > 0) {
1170
0
        if (staticString[i - 1] != ' ')
1171
0
            break;
1172
0
        i--;
1173
0
    }
1174
1175
0
    if (strlen(string) == i && memcmp(string, staticString, i) == 0) {
1176
0
        return PR_TRUE;
1177
0
    }
1178
1179
0
    return PR_FALSE;
1180
0
}
1181
1182
/*
1183
 * Reads in the slots mechanism list for later use
1184
 */
1185
SECStatus
1186
PK11_ReadMechanismList(PK11SlotInfo *slot)
1187
32
{
1188
32
    CK_ULONG count;
1189
32
    CK_RV crv;
1190
32
    PRUint32 i;
1191
1192
32
    if (slot->mechanismList) {
1193
0
        PORT_Free(slot->mechanismList);
1194
0
        slot->mechanismList = NULL;
1195
0
    }
1196
32
    slot->mechanismCount = 0;
1197
1198
32
    if (!slot->isThreadSafe)
1199
0
        PK11_EnterSlotMonitor(slot);
1200
32
    crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID, NULL, &count);
1201
32
    if (crv != CKR_OK) {
1202
0
        if (!slot->isThreadSafe)
1203
0
            PK11_ExitSlotMonitor(slot);
1204
0
        PORT_SetError(PK11_MapError(crv));
1205
0
        return SECFailure;
1206
0
    }
1207
1208
32
    slot->mechanismList = (CK_MECHANISM_TYPE *)
1209
32
        PORT_Alloc(count * sizeof(CK_MECHANISM_TYPE));
1210
32
    if (slot->mechanismList == NULL) {
1211
0
        if (!slot->isThreadSafe)
1212
0
            PK11_ExitSlotMonitor(slot);
1213
0
        return SECFailure;
1214
0
    }
1215
32
    crv = PK11_GETTAB(slot)->C_GetMechanismList(slot->slotID,
1216
32
                                                slot->mechanismList, &count);
1217
32
    if (!slot->isThreadSafe)
1218
0
        PK11_ExitSlotMonitor(slot);
1219
32
    if (crv != CKR_OK) {
1220
0
        PORT_Free(slot->mechanismList);
1221
0
        slot->mechanismList = NULL;
1222
0
        PORT_SetError(PK11_MapError(crv));
1223
0
        return SECSuccess;
1224
0
    }
1225
32
    slot->mechanismCount = count;
1226
32
    PORT_Memset(slot->mechanismBits, 0, sizeof(slot->mechanismBits));
1227
1228
6.76k
    for (i = 0; i < count; i++) {
1229
6.73k
        CK_MECHANISM_TYPE mech = slot->mechanismList[i];
1230
6.73k
        if (mech < 0x7ff) {
1231
3.93k
            slot->mechanismBits[mech & 0xff] |= 1 << (mech >> 8);
1232
3.93k
        }
1233
6.73k
    }
1234
32
    return SECSuccess;
1235
32
}
1236
1237
static SECStatus
1238
pk11_ReadProfileList(PK11SlotInfo *slot)
1239
32
{
1240
32
    CK_ATTRIBUTE findTemp[2];
1241
32
    CK_ATTRIBUTE *attrs;
1242
32
    CK_BBOOL cktrue = CK_TRUE;
1243
32
    CK_OBJECT_CLASS oclass = CKO_PROFILE;
1244
32
    size_t tsize;
1245
32
    int objCount;
1246
32
    CK_OBJECT_HANDLE *handles = NULL;
1247
32
    int i;
1248
1249
32
    attrs = findTemp;
1250
32
    PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue));
1251
32
    attrs++;
1252
32
    PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass));
1253
32
    attrs++;
1254
32
    tsize = attrs - findTemp;
1255
32
    PORT_Assert(tsize <= sizeof(findTemp) / sizeof(CK_ATTRIBUTE));
1256
1257
32
    if (slot->profileList) {
1258
0
        PORT_Free(slot->profileList);
1259
0
        slot->profileList = NULL;
1260
0
    }
1261
32
    slot->profileCount = 0;
1262
1263
32
    objCount = 0;
1264
32
    handles = pk11_FindObjectsByTemplate(slot, findTemp, tsize, &objCount);
1265
32
    if (handles == NULL) {
1266
32
        if (objCount < 0) {
1267
0
            return SECFailure; /* error code is set */
1268
0
        }
1269
32
        PORT_Assert(objCount == 0);
1270
32
        return SECSuccess;
1271
32
    }
1272
1273
0
    slot->profileList = (CK_PROFILE_ID *)
1274
0
        PORT_Alloc(objCount * sizeof(CK_PROFILE_ID));
1275
0
    if (slot->profileList == NULL) {
1276
0
        PORT_Free(handles);
1277
0
        return SECFailure; /* error code is set */
1278
0
    }
1279
1280
0
    for (i = 0; i < objCount; i++) {
1281
0
        CK_ULONG value;
1282
1283
0
        value = PK11_ReadULongAttribute(slot, handles[i], CKA_PROFILE_ID);
1284
0
        if (value == CK_UNAVAILABLE_INFORMATION) {
1285
0
            continue;
1286
0
        }
1287
0
        slot->profileList[slot->profileCount++] = value;
1288
0
    }
1289
1290
0
    PORT_Free(handles);
1291
0
    return SECSuccess;
1292
0
}
1293
1294
static PRBool
1295
pk11_HasProfile(PK11SlotInfo *slot, CK_PROFILE_ID id)
1296
0
{
1297
0
    int i;
1298
1299
0
    for (i = 0; i < slot->profileCount; i++) {
1300
0
        if (slot->profileList[i] == id) {
1301
0
            return PR_TRUE;
1302
0
        }
1303
0
    }
1304
0
    return PR_FALSE;
1305
0
}
1306
1307
static CK_FLAGS
1308
pk11_GetValidationFlags(PK11SlotInfo *slot, CK_VALIDATION_AUTHORITY_TYPE auth)
1309
32
{
1310
32
    CK_ATTRIBUTE findTemp[2];
1311
32
    CK_ATTRIBUTE *attrs;
1312
32
    CK_OBJECT_CLASS oclass = CKO_VALIDATION;
1313
32
    size_t tsize;
1314
32
    int objCount;
1315
32
    CK_OBJECT_HANDLE *handles = NULL;
1316
32
    CK_FLAGS validation_flags = 0;
1317
32
    int i;
1318
1319
    /* only used with tokens with verison >= 3.2 */
1320
32
    if (PK11_CheckPKCS11Version(slot, 3, 2, PR_FALSE) < 0) {
1321
0
        return validation_flags;
1322
0
    }
1323
1324
32
    attrs = findTemp;
1325
32
    PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass));
1326
32
    attrs++;
1327
32
    PK11_SETATTRS(attrs, CKA_VALIDATION_AUTHORITY_TYPE, &auth, sizeof(auth));
1328
32
    attrs++;
1329
32
    tsize = attrs - findTemp;
1330
32
    PORT_Assert(tsize <= sizeof(findTemp) / sizeof(CK_ATTRIBUTE));
1331
1332
32
    objCount = 0;
1333
32
    handles = pk11_FindObjectsByTemplate(slot, findTemp, tsize, &objCount);
1334
32
    if (handles == NULL) {
1335
        /* none found, return or empty flags */
1336
32
        return validation_flags;
1337
32
    }
1338
1339
0
    for (i = 0; i < objCount; i++) {
1340
0
        CK_FLAGS value;
1341
0
        value = PK11_ReadULongAttribute(slot, handles[i], CKA_VALIDATION_FLAG);
1342
0
        if (value == CK_UNAVAILABLE_INFORMATION) {
1343
0
            continue;
1344
0
        }
1345
0
        validation_flags |= value;
1346
0
    }
1347
1348
0
    PORT_Free(handles);
1349
0
    return validation_flags;
1350
32
}
1351
1352
/*
1353
 * initialize a new token
1354
 * unlike initialize slot, this can be called multiple times in the lifetime
1355
 * of NSS. It reads the information associated with a card or token,
1356
 * that is not going to change unless the card or token changes.
1357
 */
1358
SECStatus
1359
PK11_InitToken(PK11SlotInfo *slot, PRBool loadCerts)
1360
32
{
1361
32
    CK_RV crv;
1362
32
    SECStatus rv;
1363
32
    PRStatus status;
1364
32
    NSSToken *nssToken;
1365
1366
    /* set the slot flags to the current token values */
1367
32
    if (!slot->isThreadSafe)
1368
0
        PK11_EnterSlotMonitor(slot);
1369
32
    crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID, &slot->tokenInfo);
1370
32
    if (!slot->isThreadSafe)
1371
0
        PK11_ExitSlotMonitor(slot);
1372
32
    if (crv != CKR_OK) {
1373
0
        PORT_SetError(PK11_MapError(crv));
1374
0
        return SECFailure;
1375
0
    }
1376
1377
    /* set the slot flags to the current token values */
1378
32
    slot->series++; /* allow other objects to detect that the
1379
                     * slot is different */
1380
32
    slot->flags = slot->tokenInfo.flags;
1381
32
    slot->needLogin = ((slot->tokenInfo.flags & CKF_LOGIN_REQUIRED) ? PR_TRUE : PR_FALSE);
1382
32
    slot->readOnly = ((slot->tokenInfo.flags & CKF_WRITE_PROTECTED) ? PR_TRUE : PR_FALSE);
1383
1384
32
    slot->hasRandom = ((slot->tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
1385
32
    slot->protectedAuthPath =
1386
32
        ((slot->tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
1387
32
             ? PR_TRUE
1388
32
             : PR_FALSE);
1389
32
    slot->lastLoginCheck = 0;
1390
32
    slot->lastState = 0;
1391
    /* on some platforms Active Card incorrectly sets the
1392
     * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
1393
32
    if (slot->isActiveCard) {
1394
0
        slot->protectedAuthPath = PR_FALSE;
1395
0
    }
1396
32
    (void)PK11_MakeString(NULL, slot->token_name,
1397
32
                          (char *)slot->tokenInfo.label, sizeof(slot->tokenInfo.label));
1398
32
    slot->minPassword = slot->tokenInfo.ulMinPinLen;
1399
32
    slot->maxPassword = slot->tokenInfo.ulMaxPinLen;
1400
32
    PORT_Memcpy(slot->serial, slot->tokenInfo.serialNumber, sizeof(slot->serial));
1401
1402
32
    nssToken = PK11Slot_GetNSSToken(slot);
1403
32
    nssToken_UpdateName(nssToken); /* null token is OK */
1404
32
    (void)nssToken_Destroy(nssToken);
1405
1406
32
    slot->defRWSession = (PRBool)((!slot->readOnly) &&
1407
0
                                  (slot->tokenInfo.ulMaxSessionCount == 1));
1408
32
    rv = PK11_ReadMechanismList(slot);
1409
32
    if (rv != SECSuccess)
1410
0
        return rv;
1411
1412
32
    slot->hasRSAInfo = PR_FALSE;
1413
32
    slot->RSAInfoFlags = 0;
1414
1415
    /* initialize the maxKeyCount value */
1416
32
    if (slot->tokenInfo.ulMaxSessionCount == 0) {
1417
32
        slot->maxKeyCount = 800; /* should be #define or a config param */
1418
32
    } else if (slot->tokenInfo.ulMaxSessionCount < 20) {
1419
        /* don't have enough sessions to keep that many keys around */
1420
0
        slot->maxKeyCount = 0;
1421
0
    } else {
1422
0
        slot->maxKeyCount = slot->tokenInfo.ulMaxSessionCount / 2;
1423
0
    }
1424
1425
    /* Make sure our session handle is valid */
1426
32
    if (slot->session == CK_INVALID_HANDLE) {
1427
        /* we know we don't have a valid session, go get one */
1428
32
        CK_SESSION_HANDLE session;
1429
1430
        /* session should be Readonly, serial */
1431
32
        if (!slot->isThreadSafe)
1432
0
            PK11_EnterSlotMonitor(slot);
1433
32
        crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
1434
32
                                               (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
1435
32
                                               slot, pk11_notify, &session);
1436
32
        if (!slot->isThreadSafe)
1437
0
            PK11_ExitSlotMonitor(slot);
1438
32
        if (crv != CKR_OK) {
1439
0
            PORT_SetError(PK11_MapError(crv));
1440
0
            return SECFailure;
1441
0
        }
1442
32
        slot->session = session;
1443
32
    } else {
1444
        /* The session we have may be defunct (the token associated with it)
1445
         * has been removed   */
1446
0
        CK_SESSION_INFO sessionInfo;
1447
1448
0
        if (!slot->isThreadSafe)
1449
0
            PK11_EnterSlotMonitor(slot);
1450
0
        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
1451
0
        if (crv == CKR_DEVICE_ERROR) {
1452
0
            PK11_GETTAB(slot)
1453
0
                ->C_CloseSession(slot->session);
1454
0
            crv = CKR_SESSION_CLOSED;
1455
0
        }
1456
0
        if ((crv == CKR_SESSION_CLOSED) || (crv == CKR_SESSION_HANDLE_INVALID)) {
1457
0
            crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
1458
0
                                                   (slot->defRWSession ? CKF_RW_SESSION : 0) | CKF_SERIAL_SESSION,
1459
0
                                                   slot, pk11_notify, &slot->session);
1460
0
            if (crv != CKR_OK) {
1461
0
                PORT_SetError(PK11_MapError(crv));
1462
0
                slot->session = CK_INVALID_HANDLE;
1463
0
                if (!slot->isThreadSafe)
1464
0
                    PK11_ExitSlotMonitor(slot);
1465
0
                return SECFailure;
1466
0
            }
1467
0
        }
1468
0
        if (!slot->isThreadSafe)
1469
0
            PK11_ExitSlotMonitor(slot);
1470
0
    }
1471
1472
32
    nssToken = PK11Slot_GetNSSToken(slot);
1473
32
    status = nssToken_Refresh(nssToken); /* null token is OK */
1474
32
    (void)nssToken_Destroy(nssToken);
1475
32
    if (status != PR_SUCCESS)
1476
0
        return SECFailure;
1477
1478
    /* Not all tokens have profile objects or even recognize what profile
1479
     * objects are it's OK for pk11_ReadProfileList to fail */
1480
32
    (void)pk11_ReadProfileList(slot);
1481
32
    slot->validationFIPSFlags =
1482
32
        pk11_GetValidationFlags(slot, CKV_AUTHORITY_TYPE_NIST_CMVP);
1483
1484
32
    if (!(slot->isInternal) && (slot->hasRandom)) {
1485
        /* if this slot has a random number generater, use it to add entropy
1486
         * to the internal slot. */
1487
0
        PK11SlotInfo *int_slot = PK11_GetInternalSlot();
1488
1489
0
        if (int_slot) {
1490
0
            unsigned char random_bytes[32];
1491
1492
            /* if this slot can issue random numbers, get some entropy from
1493
             * that random number generater and give it to our internal token.
1494
             */
1495
0
            PK11_EnterSlotMonitor(slot);
1496
0
            crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session, random_bytes, sizeof(random_bytes));
1497
0
            PK11_ExitSlotMonitor(slot);
1498
0
            if (crv == CKR_OK) {
1499
0
                PK11_EnterSlotMonitor(int_slot);
1500
0
                PK11_GETTAB(int_slot)
1501
0
                    ->C_SeedRandom(int_slot->session,
1502
0
                                   random_bytes, sizeof(random_bytes));
1503
0
                PK11_ExitSlotMonitor(int_slot);
1504
0
            }
1505
1506
            /* Now return the favor and send entropy to the token's random
1507
             * number generater */
1508
0
            PK11_EnterSlotMonitor(int_slot);
1509
0
            crv = PK11_GETTAB(int_slot)->C_GenerateRandom(int_slot->session,
1510
0
                                                          random_bytes, sizeof(random_bytes));
1511
0
            PK11_ExitSlotMonitor(int_slot);
1512
0
            if (crv == CKR_OK) {
1513
0
                PK11_EnterSlotMonitor(slot);
1514
0
                crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session,
1515
0
                                                      random_bytes, sizeof(random_bytes));
1516
0
                PK11_ExitSlotMonitor(slot);
1517
0
            }
1518
0
            PK11_FreeSlot(int_slot);
1519
0
        }
1520
0
    }
1521
    /* work around a problem in softoken where it incorrectly
1522
     * reports databases opened read only as read/write. */
1523
32
    if (slot->isInternal && !slot->readOnly) {
1524
0
        CK_SESSION_HANDLE session = CK_INVALID_HANDLE;
1525
1526
        /* try to open a R/W session */
1527
0
        crv = PK11_GETTAB(slot)->C_OpenSession(slot->slotID,
1528
0
                                               CKF_RW_SESSION | CKF_SERIAL_SESSION, slot, pk11_notify, &session);
1529
        /* what a well behaved token should return if you open
1530
         * a RW session on a read only token */
1531
0
        if (crv == CKR_TOKEN_WRITE_PROTECTED) {
1532
0
            slot->readOnly = PR_TRUE;
1533
0
        } else if (crv == CKR_OK) {
1534
0
            CK_SESSION_INFO sessionInfo;
1535
1536
            /* Because of a second bug in softoken, which silently returns
1537
             * a RO session, we need to check what type of session we got. */
1538
0
            crv = PK11_GETTAB(slot)->C_GetSessionInfo(session, &sessionInfo);
1539
0
            if (crv == CKR_OK) {
1540
0
                if ((sessionInfo.flags & CKF_RW_SESSION) == 0) {
1541
                    /* session was readonly, so this softoken slot must be readonly */
1542
0
                    slot->readOnly = PR_TRUE;
1543
0
                }
1544
0
            }
1545
0
            PK11_GETTAB(slot)
1546
0
                ->C_CloseSession(session);
1547
0
        }
1548
0
    }
1549
1550
32
    return SECSuccess;
1551
32
}
1552
1553
/*
1554
 * initialize a new token
1555
 * unlike initialize slot, this can be called multiple times in the lifetime
1556
 * of NSS. It reads the information associated with a card or token,
1557
 * that is not going to change unless the card or token changes.
1558
 */
1559
SECStatus
1560
PK11_TokenRefresh(PK11SlotInfo *slot)
1561
0
{
1562
0
    CK_RV crv;
1563
1564
    /* set the slot flags to the current token values */
1565
0
    if (!slot->isThreadSafe)
1566
0
        PK11_EnterSlotMonitor(slot);
1567
0
    crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID, &slot->tokenInfo);
1568
0
    if (!slot->isThreadSafe)
1569
0
        PK11_ExitSlotMonitor(slot);
1570
0
    if (crv != CKR_OK) {
1571
0
        PORT_SetError(PK11_MapError(crv));
1572
0
        return SECFailure;
1573
0
    }
1574
1575
0
    slot->flags = slot->tokenInfo.flags;
1576
0
    slot->needLogin = ((slot->tokenInfo.flags & CKF_LOGIN_REQUIRED) ? PR_TRUE : PR_FALSE);
1577
0
    slot->readOnly = ((slot->tokenInfo.flags & CKF_WRITE_PROTECTED) ? PR_TRUE : PR_FALSE);
1578
0
    slot->hasRandom = ((slot->tokenInfo.flags & CKF_RNG) ? PR_TRUE : PR_FALSE);
1579
0
    slot->protectedAuthPath =
1580
0
        ((slot->tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
1581
0
             ? PR_TRUE
1582
0
             : PR_FALSE);
1583
    /* on some platforms Active Card incorrectly sets the
1584
     * CKF_PROTECTED_AUTHENTICATION_PATH bit when it doesn't mean to. */
1585
0
    if (slot->isActiveCard) {
1586
0
        slot->protectedAuthPath = PR_FALSE;
1587
0
    }
1588
0
    return SECSuccess;
1589
0
}
1590
1591
static PRBool
1592
pk11_isRootSlot(PK11SlotInfo *slot)
1593
32
{
1594
32
    CK_ATTRIBUTE findTemp[1];
1595
32
    CK_ATTRIBUTE *attrs;
1596
32
    CK_OBJECT_CLASS oclass = CKO_NSS_BUILTIN_ROOT_LIST;
1597
32
    size_t tsize;
1598
32
    CK_OBJECT_HANDLE handle;
1599
1600
32
    attrs = findTemp;
1601
32
    PK11_SETATTRS(attrs, CKA_CLASS, &oclass, sizeof(oclass));
1602
32
    attrs++;
1603
32
    tsize = attrs - findTemp;
1604
32
    PORT_Assert(tsize <= sizeof(findTemp) / sizeof(CK_ATTRIBUTE));
1605
1606
32
    handle = pk11_FindObjectByTemplate(slot, findTemp, tsize);
1607
32
    if (handle == CK_INVALID_HANDLE) {
1608
32
        return PR_FALSE;
1609
32
    }
1610
0
    return PR_TRUE;
1611
32
}
1612
1613
/*
1614
 * Initialize the slot :
1615
 * This initialization code is called on each slot a module supports when
1616
 * it is loaded. It does the bringup initialization. The difference between
1617
 * this and InitToken is Init slot does those one time initialization stuff,
1618
 * usually associated with the reader, while InitToken may get called multiple
1619
 * times as tokens are removed and re-inserted.
1620
 */
1621
void
1622
PK11_InitSlot(SECMODModule *mod, CK_SLOT_ID slotID, PK11SlotInfo *slot)
1623
32
{
1624
32
    SECStatus rv;
1625
32
    CK_SLOT_INFO slotInfo;
1626
1627
32
    slot->functionList = mod->functionList;
1628
32
    slot->isInternal = mod->internal;
1629
32
    slot->slotID = slotID;
1630
32
    slot->isThreadSafe = mod->isThreadSafe;
1631
32
    slot->hasRSAInfo = PR_FALSE;
1632
32
    slot->module = mod; /* NOTE: we don't make a reference here because
1633
                         * modules have references to their slots. This
1634
                         * works because modules keep implicit references
1635
                         * from their slots, and won't unload and disappear
1636
                         * until all their slots have been freed */
1637
1638
32
    if (PK11_GetSlotInfo(slot, &slotInfo) != SECSuccess) {
1639
0
        slot->disabled = PR_TRUE;
1640
0
        slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1641
0
        return;
1642
0
    }
1643
1644
    /* test to make sure claimed mechanism work */
1645
32
    slot->needTest = mod->internal ? PR_FALSE : PR_TRUE;
1646
32
    (void)PK11_MakeString(NULL, slot->slot_name,
1647
32
                          (char *)slotInfo.slotDescription, sizeof(slotInfo.slotDescription));
1648
32
    slot->isHW = (PRBool)((slotInfo.flags & CKF_HW_SLOT) == CKF_HW_SLOT);
1649
64
#define ACTIVE_CARD "ActivCard SA"
1650
32
    slot->isActiveCard = (PRBool)(PORT_Strncmp((char *)slotInfo.manufacturerID,
1651
32
                                               ACTIVE_CARD, sizeof(ACTIVE_CARD) - 1) == 0);
1652
32
    if ((slotInfo.flags & CKF_REMOVABLE_DEVICE) == 0) {
1653
32
        slot->isPerm = PR_TRUE;
1654
        /* permanment slots must have the token present always */
1655
32
        if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
1656
0
            slot->disabled = PR_TRUE;
1657
0
            slot->reason = PK11_DIS_TOKEN_NOT_PRESENT;
1658
0
            return; /* nothing else to do */
1659
0
        }
1660
32
    }
1661
    /* if the token is present, initialize it */
1662
32
    if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
1663
32
        rv = PK11_InitToken(slot, PR_TRUE);
1664
        /* the only hard failures are on permanent devices, or function
1665
         * verify failures... function verify failures are already handled
1666
         * by tokenInit */
1667
32
        if ((rv != SECSuccess) && (slot->isPerm) && (!slot->disabled)) {
1668
0
            slot->disabled = PR_TRUE;
1669
0
            slot->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1670
0
        }
1671
32
        if (rv == SECSuccess && pk11_isRootSlot(slot)) {
1672
0
            if (!slot->hasRootCerts) {
1673
0
                slot->module->trustOrder = 100;
1674
0
            }
1675
0
            slot->hasRootCerts = PR_TRUE;
1676
0
        }
1677
32
    }
1678
32
    if ((slotInfo.flags & CKF_USER_PIN_INITIALIZED) != 0) {
1679
32
        slot->flags |= CKF_USER_PIN_INITIALIZED;
1680
32
    }
1681
32
}
1682
1683
/*********************************************************************
1684
 *            Slot mapping utility functions.
1685
 *********************************************************************/
1686
1687
/*
1688
 * determine if the token is present. If the token is present, make sure
1689
 * we have a valid session handle. Also set the value of needLogin
1690
 * appropriately.
1691
 */
1692
static PRBool
1693
pk11_IsPresentCertLoad(PK11SlotInfo *slot, PRBool loadCerts)
1694
1.45M
{
1695
1.45M
    CK_SLOT_INFO slotInfo;
1696
1.45M
    CK_SESSION_INFO sessionInfo;
1697
1.45M
    CK_RV crv;
1698
1699
    /* disabled slots are never present */
1700
1.45M
    if (slot->disabled) {
1701
0
        return PR_FALSE;
1702
0
    }
1703
1704
    /* permanent slots are always present */
1705
1.45M
    if (slot->isPerm && (slot->session != CK_INVALID_HANDLE)) {
1706
1.45M
        return PR_TRUE;
1707
1.45M
    }
1708
1709
0
    NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1710
0
    if (nssToken) {
1711
0
        PRBool present = nssToken_IsPresent(nssToken);
1712
0
        (void)nssToken_Destroy(nssToken);
1713
0
        return present;
1714
0
    }
1715
1716
    /* removable slots have a flag that says they are present */
1717
0
    if (PK11_GetSlotInfo(slot, &slotInfo) != SECSuccess) {
1718
0
        return PR_FALSE;
1719
0
    }
1720
1721
0
    if ((slotInfo.flags & CKF_TOKEN_PRESENT) == 0) {
1722
        /* if the slot is no longer present, close the session */
1723
0
        if (slot->session != CK_INVALID_HANDLE) {
1724
0
            if (!slot->isThreadSafe) {
1725
0
                PK11_EnterSlotMonitor(slot);
1726
0
            }
1727
0
            PK11_GETTAB(slot)
1728
0
                ->C_CloseSession(slot->session);
1729
0
            slot->session = CK_INVALID_HANDLE;
1730
0
            if (!slot->isThreadSafe) {
1731
0
                PK11_ExitSlotMonitor(slot);
1732
0
            }
1733
0
        }
1734
0
        return PR_FALSE;
1735
0
    }
1736
1737
    /* use the session Info to determine if the card has been removed and then
1738
     * re-inserted */
1739
0
    if (slot->session != CK_INVALID_HANDLE) {
1740
0
        if (slot->isThreadSafe) {
1741
0
            PK11_EnterSlotMonitor(slot);
1742
0
        }
1743
0
        crv = PK11_GETTAB(slot)->C_GetSessionInfo(slot->session, &sessionInfo);
1744
0
        if (crv != CKR_OK) {
1745
0
            PK11_GETTAB(slot)
1746
0
                ->C_CloseSession(slot->session);
1747
0
            slot->session = CK_INVALID_HANDLE;
1748
0
        }
1749
0
        if (slot->isThreadSafe) {
1750
0
            PK11_ExitSlotMonitor(slot);
1751
0
        }
1752
0
    }
1753
1754
    /* card has not been removed, current token info is correct */
1755
0
    if (slot->session != CK_INVALID_HANDLE)
1756
0
        return PR_TRUE;
1757
1758
    /* initialize the token info state */
1759
0
    if (PK11_InitToken(slot, loadCerts) != SECSuccess) {
1760
0
        return PR_FALSE;
1761
0
    }
1762
1763
0
    return PR_TRUE;
1764
0
}
1765
1766
/*
1767
 * old version of the routine
1768
 */
1769
PRBool
1770
PK11_IsPresent(PK11SlotInfo *slot)
1771
1.37M
{
1772
1.37M
    return pk11_IsPresentCertLoad(slot, PR_TRUE);
1773
1.37M
}
1774
1775
/* is the slot disabled? */
1776
PRBool
1777
PK11_IsDisabled(PK11SlotInfo *slot)
1778
1.19M
{
1779
1.19M
    return slot->disabled;
1780
1.19M
}
1781
1782
/* and why? */
1783
PK11DisableReasons
1784
PK11_GetDisabledReason(PK11SlotInfo *slot)
1785
0
{
1786
0
    return slot->reason;
1787
0
}
1788
1789
/* returns PR_TRUE if successfully disable the slot */
1790
/* returns PR_FALSE otherwise */
1791
PRBool
1792
PK11_UserDisableSlot(PK11SlotInfo *slot)
1793
0
{
1794
1795
    /* Prevent users from disabling the internal module. */
1796
0
    if (slot->isInternal) {
1797
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1798
0
        return PR_FALSE;
1799
0
    }
1800
1801
0
    slot->defaultFlags |= PK11_DISABLE_FLAG;
1802
0
    slot->disabled = PR_TRUE;
1803
0
    slot->reason = PK11_DIS_USER_SELECTED;
1804
1805
0
    return PR_TRUE;
1806
0
}
1807
1808
PRBool
1809
PK11_UserEnableSlot(PK11SlotInfo *slot)
1810
0
{
1811
1812
0
    slot->defaultFlags &= ~PK11_DISABLE_FLAG;
1813
0
    slot->disabled = PR_FALSE;
1814
0
    slot->reason = PK11_DIS_NONE;
1815
0
    return PR_TRUE;
1816
0
}
1817
1818
PRBool
1819
PK11_HasRootCerts(PK11SlotInfo *slot)
1820
0
{
1821
0
    return slot->hasRootCerts;
1822
0
}
1823
1824
/* Get the module this slot is attached to */
1825
SECMODModule *
1826
PK11_GetModule(PK11SlotInfo *slot)
1827
0
{
1828
0
    return slot->module;
1829
0
}
1830
1831
/* return the default flags of a slot */
1832
unsigned long
1833
PK11_GetDefaultFlags(PK11SlotInfo *slot)
1834
0
{
1835
0
    return slot->defaultFlags;
1836
0
}
1837
1838
/*
1839
 * The following wrapper functions allow us to export an opaque slot
1840
 * function to the rest of libsec and the world... */
1841
PRBool
1842
PK11_IsReadOnly(PK11SlotInfo *slot)
1843
0
{
1844
0
    return slot->readOnly;
1845
0
}
1846
1847
PRBool
1848
PK11_IsHW(PK11SlotInfo *slot)
1849
4.50k
{
1850
4.50k
    return slot->isHW;
1851
4.50k
}
1852
1853
PRBool
1854
PK11_IsRemovable(PK11SlotInfo *slot)
1855
0
{
1856
0
    return !slot->isPerm;
1857
0
}
1858
1859
PRBool
1860
PK11_IsInternal(PK11SlotInfo *slot)
1861
12.2k
{
1862
12.2k
    return slot->isInternal;
1863
12.2k
}
1864
1865
PRBool
1866
PK11_IsInternalKeySlot(PK11SlotInfo *slot)
1867
0
{
1868
0
    PK11SlotInfo *int_slot;
1869
0
    PRBool result;
1870
1871
0
    if (!slot->isInternal) {
1872
0
        return PR_FALSE;
1873
0
    }
1874
1875
0
    int_slot = PK11_GetInternalKeySlot();
1876
0
    result = (int_slot == slot) ? PR_TRUE : PR_FALSE;
1877
0
    PK11_FreeSlot(int_slot);
1878
0
    return result;
1879
0
}
1880
1881
PRBool
1882
PK11_NeedLogin(PK11SlotInfo *slot)
1883
0
{
1884
0
    return slot->needLogin;
1885
0
}
1886
1887
PRBool
1888
PK11_IsFriendly(PK11SlotInfo *slot)
1889
302
{
1890
    /* internal slot always has public readable certs */
1891
302
    return (PRBool)(slot->isInternal ||
1892
0
                    pk11_HasProfile(slot, CKP_PUBLIC_CERTIFICATES_TOKEN) ||
1893
0
                    ((slot->defaultFlags & SECMOD_FRIENDLY_FLAG) ==
1894
0
                     SECMOD_FRIENDLY_FLAG));
1895
302
}
1896
1897
char *
1898
PK11_GetTokenName(PK11SlotInfo *slot)
1899
0
{
1900
0
    return slot->token_name;
1901
0
}
1902
1903
char *
1904
PK11_GetTokenURI(PK11SlotInfo *slot)
1905
0
{
1906
0
    PK11URI *uri;
1907
0
    char *ret = NULL;
1908
0
    char label[32 + 1], manufacturer[32 + 1], serial[16 + 1], model[16 + 1];
1909
0
    PK11URIAttribute attrs[4];
1910
0
    size_t nattrs = 0;
1911
1912
0
    PK11_MakeString(NULL, label, (char *)slot->tokenInfo.label,
1913
0
                    sizeof(slot->tokenInfo.label));
1914
0
    if (*label != '\0') {
1915
0
        attrs[nattrs].name = PK11URI_PATTR_TOKEN;
1916
0
        attrs[nattrs].value = label;
1917
0
        nattrs++;
1918
0
    }
1919
1920
0
    PK11_MakeString(NULL, manufacturer, (char *)slot->tokenInfo.manufacturerID,
1921
0
                    sizeof(slot->tokenInfo.manufacturerID));
1922
0
    if (*manufacturer != '\0') {
1923
0
        attrs[nattrs].name = PK11URI_PATTR_MANUFACTURER;
1924
0
        attrs[nattrs].value = manufacturer;
1925
0
        nattrs++;
1926
0
    }
1927
1928
0
    PK11_MakeString(NULL, serial, (char *)slot->tokenInfo.serialNumber,
1929
0
                    sizeof(slot->tokenInfo.serialNumber));
1930
0
    if (*serial != '\0') {
1931
0
        attrs[nattrs].name = PK11URI_PATTR_SERIAL;
1932
0
        attrs[nattrs].value = serial;
1933
0
        nattrs++;
1934
0
    }
1935
1936
0
    PK11_MakeString(NULL, model, (char *)slot->tokenInfo.model,
1937
0
                    sizeof(slot->tokenInfo.model));
1938
0
    if (*model != '\0') {
1939
0
        attrs[nattrs].name = PK11URI_PATTR_MODEL;
1940
0
        attrs[nattrs].value = model;
1941
0
        nattrs++;
1942
0
    }
1943
1944
0
    uri = PK11URI_CreateURI(attrs, nattrs, NULL, 0);
1945
0
    if (uri == NULL) {
1946
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1947
0
        return NULL;
1948
0
    }
1949
1950
0
    ret = PK11URI_FormatURI(NULL, uri);
1951
0
    PK11URI_DestroyURI(uri);
1952
1953
0
    if (ret == NULL) {
1954
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1955
0
    }
1956
1957
0
    return ret;
1958
0
}
1959
1960
char *
1961
PK11_GetSlotName(PK11SlotInfo *slot)
1962
0
{
1963
0
    return slot->slot_name;
1964
0
}
1965
1966
int
1967
PK11_GetSlotSeries(PK11SlotInfo *slot)
1968
24.9k
{
1969
24.9k
    return slot->series;
1970
24.9k
}
1971
1972
int
1973
PK11_GetCurrentWrapIndex(PK11SlotInfo *slot)
1974
24.7k
{
1975
24.7k
    return slot->wrapKey;
1976
24.7k
}
1977
1978
CK_SLOT_ID
1979
PK11_GetSlotID(PK11SlotInfo *slot)
1980
24.7k
{
1981
24.7k
    return slot->slotID;
1982
24.7k
}
1983
1984
SECMODModuleID
1985
PK11_GetModuleID(PK11SlotInfo *slot)
1986
24.7k
{
1987
24.7k
    return slot->module->moduleID;
1988
24.7k
}
1989
1990
static void
1991
pk11_zeroTerminatedToBlankPadded(CK_CHAR *buffer, size_t buffer_size)
1992
64
{
1993
64
    CK_CHAR *walk = buffer;
1994
64
    CK_CHAR *end = buffer + buffer_size;
1995
1996
    /* find the NULL */
1997
3.13k
    while (walk < end && *walk != '\0') {
1998
3.07k
        walk++;
1999
3.07k
    }
2000
2001
    /* clear out the buffer */
2002
64
    while (walk < end) {
2003
0
        *walk++ = ' ';
2004
0
    }
2005
64
}
2006
2007
/* return the slot info structure */
2008
SECStatus
2009
PK11_GetSlotInfo(PK11SlotInfo *slot, CK_SLOT_INFO *info)
2010
32
{
2011
32
    CK_RV crv;
2012
2013
32
    if (!slot->isThreadSafe)
2014
0
        PK11_EnterSlotMonitor(slot);
2015
    /*
2016
     * some buggy drivers do not fill the buffer completely,
2017
     * erase the buffer first
2018
     */
2019
32
    PORT_Memset(info->slotDescription, ' ', sizeof(info->slotDescription));
2020
32
    PORT_Memset(info->manufacturerID, ' ', sizeof(info->manufacturerID));
2021
32
    crv = PK11_GETTAB(slot)->C_GetSlotInfo(slot->slotID, info);
2022
32
    pk11_zeroTerminatedToBlankPadded(info->slotDescription,
2023
32
                                     sizeof(info->slotDescription));
2024
32
    pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
2025
32
                                     sizeof(info->manufacturerID));
2026
32
    if (!slot->isThreadSafe)
2027
0
        PK11_ExitSlotMonitor(slot);
2028
32
    if (crv != CKR_OK) {
2029
0
        PORT_SetError(PK11_MapError(crv));
2030
0
        return SECFailure;
2031
0
    }
2032
32
    return SECSuccess;
2033
32
}
2034
2035
/*  return the token info structure */
2036
SECStatus
2037
PK11_GetTokenInfo(PK11SlotInfo *slot, CK_TOKEN_INFO *info)
2038
0
{
2039
0
    CK_RV crv;
2040
0
    if (!slot->isThreadSafe)
2041
0
        PK11_EnterSlotMonitor(slot);
2042
    /*
2043
     * some buggy drivers do not fill the buffer completely,
2044
     * erase the buffer first
2045
     */
2046
0
    PORT_Memset(info->label, ' ', sizeof(info->label));
2047
0
    PORT_Memset(info->manufacturerID, ' ', sizeof(info->manufacturerID));
2048
0
    PORT_Memset(info->model, ' ', sizeof(info->model));
2049
0
    PORT_Memset(info->serialNumber, ' ', sizeof(info->serialNumber));
2050
0
    crv = PK11_GETTAB(slot)->C_GetTokenInfo(slot->slotID, info);
2051
0
    pk11_zeroTerminatedToBlankPadded(info->label, sizeof(info->label));
2052
0
    pk11_zeroTerminatedToBlankPadded(info->manufacturerID,
2053
0
                                     sizeof(info->manufacturerID));
2054
0
    pk11_zeroTerminatedToBlankPadded(info->model, sizeof(info->model));
2055
0
    pk11_zeroTerminatedToBlankPadded(info->serialNumber,
2056
0
                                     sizeof(info->serialNumber));
2057
0
    if (!slot->isThreadSafe)
2058
0
        PK11_ExitSlotMonitor(slot);
2059
0
    if (crv != CKR_OK) {
2060
0
        PORT_SetError(PK11_MapError(crv));
2061
0
        return SECFailure;
2062
0
    }
2063
0
    return SECSuccess;
2064
0
}
2065
2066
PRBool
2067
pk11_MatchUriTokenInfo(PK11SlotInfo *slot, PK11URI *uri)
2068
0
{
2069
0
    const char *value;
2070
2071
0
    value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_TOKEN);
2072
0
    if (value) {
2073
0
        if (!pk11_MatchString(value, (char *)slot->tokenInfo.label,
2074
0
                              sizeof(slot->tokenInfo.label))) {
2075
0
            return PR_FALSE;
2076
0
        }
2077
0
    }
2078
2079
0
    value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MANUFACTURER);
2080
0
    if (value) {
2081
0
        if (!pk11_MatchString(value, (char *)slot->tokenInfo.manufacturerID,
2082
0
                              sizeof(slot->tokenInfo.manufacturerID))) {
2083
0
            return PR_FALSE;
2084
0
        }
2085
0
    }
2086
2087
0
    value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_SERIAL);
2088
0
    if (value) {
2089
0
        if (!pk11_MatchString(value, (char *)slot->tokenInfo.serialNumber,
2090
0
                              sizeof(slot->tokenInfo.serialNumber))) {
2091
0
            return PR_FALSE;
2092
0
        }
2093
0
    }
2094
2095
0
    value = PK11URI_GetPathAttribute(uri, PK11URI_PATTR_MODEL);
2096
0
    if (value) {
2097
0
        if (!pk11_MatchString(value, (char *)slot->tokenInfo.model,
2098
0
                              sizeof(slot->tokenInfo.model))) {
2099
0
            return PR_FALSE;
2100
0
        }
2101
0
    }
2102
2103
0
    return PR_TRUE;
2104
0
}
2105
2106
/* Find out if we need to initialize the user's pin */
2107
PRBool
2108
PK11_NeedUserInit(PK11SlotInfo *slot)
2109
0
{
2110
0
    PRBool needUserInit = (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
2111
2112
0
    if (needUserInit) {
2113
0
        CK_TOKEN_INFO info;
2114
0
        SECStatus rv;
2115
2116
        /* see if token has been initialized off line */
2117
0
        rv = PK11_GetTokenInfo(slot, &info);
2118
0
        if (rv == SECSuccess) {
2119
0
            slot->flags = info.flags;
2120
0
        }
2121
0
    }
2122
0
    return (PRBool)((slot->flags & CKF_USER_PIN_INITIALIZED) == 0);
2123
0
}
2124
2125
static PK11SlotInfo *pk11InternalKeySlot = NULL;
2126
2127
/*
2128
 * Set a new default internal keyslot. If one has already been set, clear it.
2129
 * Passing NULL falls back to the NSS normally selected default internal key
2130
 * slot.
2131
 */
2132
void
2133
pk11_SetInternalKeySlot(PK11SlotInfo *slot)
2134
14
{
2135
14
    if (pk11InternalKeySlot) {
2136
14
        PK11_FreeSlot(pk11InternalKeySlot);
2137
14
    }
2138
14
    pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
2139
14
}
2140
2141
/*
2142
 * Set a new default internal keyslot if the normal key slot has not already
2143
 * been overridden. Subsequent calls to this function will be ignored unless
2144
 * pk11_SetInternalKeySlot is used to clear the current default.
2145
 */
2146
void
2147
pk11_SetInternalKeySlotIfFirst(PK11SlotInfo *slot)
2148
16
{
2149
16
    if (pk11InternalKeySlot) {
2150
0
        return;
2151
0
    }
2152
16
    pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
2153
16
}
2154
2155
/*
2156
 * Swap out a default internal keyslot.  Caller owns the Slot Reference
2157
 */
2158
PK11SlotInfo *
2159
pk11_SwapInternalKeySlot(PK11SlotInfo *slot)
2160
0
{
2161
0
    PK11SlotInfo *swap = pk11InternalKeySlot;
2162
2163
0
    pk11InternalKeySlot = slot ? PK11_ReferenceSlot(slot) : NULL;
2164
0
    return swap;
2165
0
}
2166
2167
/* get the internal key slot. FIPS has only one slot for both key slots and
2168
 * default slots */
2169
PK11SlotInfo *
2170
PK11_GetInternalKeySlot(void)
2171
0
{
2172
0
    SECMODModule *mod;
2173
2174
0
    if (pk11InternalKeySlot) {
2175
0
        return PK11_ReferenceSlot(pk11InternalKeySlot);
2176
0
    }
2177
2178
0
    mod = SECMOD_GetInternalModule();
2179
0
    PORT_Assert(mod != NULL);
2180
0
    if (!mod) {
2181
0
        PORT_SetError(SEC_ERROR_NO_MODULE);
2182
0
        return NULL;
2183
0
    }
2184
0
    return PK11_ReferenceSlot(mod->isFIPS ? mod->slots[0] : mod->slots[1]);
2185
0
}
2186
2187
/* get the internal default slot */
2188
PK11SlotInfo *
2189
PK11_GetInternalSlot(void)
2190
46.4M
{
2191
46.4M
    SECMODModule *mod = SECMOD_GetInternalModule();
2192
46.4M
    PORT_Assert(mod != NULL);
2193
46.4M
    if (!mod) {
2194
0
        PORT_SetError(SEC_ERROR_NO_MODULE);
2195
0
        return NULL;
2196
0
    }
2197
46.4M
    if (mod->isFIPS) {
2198
0
        return PK11_GetInternalKeySlot();
2199
0
    }
2200
46.4M
    return PK11_ReferenceSlot(mod->slots[0]);
2201
46.4M
}
2202
2203
/*
2204
 * check if a given slot supports the requested mechanism
2205
 */
2206
PRBool
2207
PK11_DoesMechanism(PK11SlotInfo *slot, CK_MECHANISM_TYPE type)
2208
50.0M
{
2209
50.0M
    int i;
2210
2211
    /* CKM_FAKE_RANDOM is not a real PKCS mechanism. It's a marker to
2212
     * tell us we're looking form someone that has implemented get
2213
     * random bits */
2214
50.0M
    if (type == CKM_FAKE_RANDOM) {
2215
276k
        return slot->hasRandom;
2216
276k
    }
2217
2218
    /* for most mechanism, bypass the linear lookup */
2219
49.7M
    if (type < 0x7ff) {
2220
28.1M
        return (slot->mechanismBits[type & 0xff] & (1 << (type >> 8))) ? PR_TRUE : PR_FALSE;
2221
28.1M
    }
2222
2223
1.15G
    for (i = 0; i < (int)slot->mechanismCount; i++) {
2224
1.15G
        if (slot->mechanismList[i] == type)
2225
21.5M
            return PR_TRUE;
2226
1.15G
    }
2227
4.51k
    return PR_FALSE;
2228
21.5M
}
2229
2230
PRBool pk11_filterSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
2231
                       CK_FLAGS mechanismInfoFlags, unsigned int keySize);
2232
/*
2233
 * Check that the given mechanism has the appropriate flags. This function
2234
 * presumes that slot can already do the given mechanism.
2235
 */
2236
PRBool
2237
PK11_DoesMechanismFlag(PK11SlotInfo *slot, CK_MECHANISM_TYPE type,
2238
                       CK_FLAGS flags)
2239
207k
{
2240
207k
    return !pk11_filterSlot(slot, type, flags, 0);
2241
207k
}
2242
2243
/*
2244
 * Return true if a token that can do the desired mechanism exists.
2245
 * This allows us to have hardware tokens that can do function XYZ magically
2246
 * allow SSL Ciphers to appear if they are plugged in.
2247
 */
2248
PRBool
2249
PK11_TokenExists(CK_MECHANISM_TYPE type)
2250
46.3M
{
2251
46.3M
    SECMODModuleList *mlp;
2252
46.3M
    SECMODModuleList *modules;
2253
46.3M
    SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
2254
46.3M
    PK11SlotInfo *slot;
2255
46.3M
    PRBool found = PR_FALSE;
2256
46.3M
    int i;
2257
2258
46.3M
    if (!moduleLock) {
2259
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
2260
0
        return found;
2261
0
    }
2262
    /* we only need to know if there is a token that does this mechanism.
2263
     * check the internal module first because it's fast, and supports
2264
     * almost everything. */
2265
46.3M
    slot = PK11_GetInternalSlot();
2266
46.3M
    if (slot) {
2267
46.3M
        found = PK11_DoesMechanism(slot, type);
2268
46.3M
        PK11_FreeSlot(slot);
2269
46.3M
    }
2270
46.3M
    if (found)
2271
46.3M
        return PR_TRUE; /* bypass getting module locks */
2272
2273
0
    SECMOD_GetReadLock(moduleLock);
2274
0
    modules = SECMOD_GetDefaultModuleList();
2275
0
    for (mlp = modules; mlp != NULL && (!found); mlp = mlp->next) {
2276
0
        for (i = 0; i < mlp->module->slotCount; i++) {
2277
0
            slot = mlp->module->slots[i];
2278
0
            if (PK11_IsPresent(slot)) {
2279
0
                if (PK11_DoesMechanism(slot, type)) {
2280
0
                    found = PR_TRUE;
2281
0
                    break;
2282
0
                }
2283
0
            }
2284
0
        }
2285
0
    }
2286
0
    SECMOD_ReleaseReadLock(moduleLock);
2287
0
    return found;
2288
46.3M
}
2289
2290
/*
2291
 * get all the currently available tokens in a list.
2292
 * that can perform the given mechanism. If mechanism is CKM_INVALID_MECHANISM,
2293
 * get all the tokens. Make sure tokens that need authentication are put at
2294
 * the end of this list.
2295
 */
2296
PK11SlotList *
2297
PK11_GetAllTokens(CK_MECHANISM_TYPE type, PRBool needRW, PRBool loadCerts,
2298
                  void *wincx)
2299
37.7k
{
2300
37.7k
    PK11SlotList *list;
2301
37.7k
    PK11SlotList *loginList;
2302
37.7k
    PK11SlotList *friendlyList;
2303
37.7k
    SECMODModuleList *mlp;
2304
37.7k
    SECMODModuleList *modules;
2305
37.7k
    SECMODListLock *moduleLock;
2306
37.7k
    int i;
2307
2308
37.7k
    moduleLock = SECMOD_GetDefaultModuleListLock();
2309
37.7k
    if (!moduleLock) {
2310
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
2311
0
        return NULL;
2312
0
    }
2313
2314
37.7k
    list = PK11_NewSlotList();
2315
37.7k
    loginList = PK11_NewSlotList();
2316
37.7k
    friendlyList = PK11_NewSlotList();
2317
37.7k
    if ((list == NULL) || (loginList == NULL) || (friendlyList == NULL)) {
2318
0
        if (list)
2319
0
            PK11_FreeSlotList(list);
2320
0
        if (loginList)
2321
0
            PK11_FreeSlotList(loginList);
2322
0
        if (friendlyList)
2323
0
            PK11_FreeSlotList(friendlyList);
2324
0
        return NULL;
2325
0
    }
2326
2327
37.7k
    SECMOD_GetReadLock(moduleLock);
2328
2329
37.7k
    modules = SECMOD_GetDefaultModuleList();
2330
75.5k
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
2331
113k
        for (i = 0; i < mlp->module->slotCount; i++) {
2332
75.5k
            PK11SlotInfo *slot = mlp->module->slots[i];
2333
2334
75.5k
            if (pk11_IsPresentCertLoad(slot, loadCerts)) {
2335
75.5k
                if (needRW && slot->readOnly)
2336
0
                    continue;
2337
75.5k
                if ((type == CKM_INVALID_MECHANISM) || PK11_DoesMechanism(slot, type)) {
2338
73.8k
                    if (pk11_LoginStillRequired(slot, wincx)) {
2339
0
                        if (PK11_IsFriendly(slot)) {
2340
0
                            PK11_AddSlotToList(friendlyList, slot, PR_TRUE);
2341
0
                        } else {
2342
0
                            PK11_AddSlotToList(loginList, slot, PR_TRUE);
2343
0
                        }
2344
73.8k
                    } else {
2345
73.8k
                        PK11_AddSlotToList(list, slot, PR_TRUE);
2346
73.8k
                    }
2347
73.8k
                }
2348
75.5k
            }
2349
75.5k
        }
2350
37.7k
    }
2351
37.7k
    SECMOD_ReleaseReadLock(moduleLock);
2352
2353
37.7k
    pk11_MoveListToList(list, friendlyList);
2354
37.7k
    PK11_FreeSlotList(friendlyList);
2355
37.7k
    pk11_MoveListToList(list, loginList);
2356
37.7k
    PK11_FreeSlotList(loginList);
2357
2358
37.7k
    return list;
2359
37.7k
}
2360
2361
/*
2362
 * NOTE: This routine is working from a private List generated by
2363
 * PK11_GetAllTokens. That is why it does not need to lock.
2364
 */
2365
PK11SlotList *
2366
PK11_GetPrivateKeyTokens(CK_MECHANISM_TYPE type, PRBool needRW, void *wincx)
2367
0
{
2368
0
    PK11SlotList *list = PK11_GetAllTokens(type, needRW, PR_TRUE, wincx);
2369
0
    PK11SlotListElement *le, *next;
2370
0
    SECStatus rv;
2371
2372
0
    if (list == NULL)
2373
0
        return list;
2374
2375
0
    for (le = list->head; le; le = next) {
2376
0
        next = le->next; /* save the pointer here in case we have to
2377
                          * free the element later */
2378
0
        rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
2379
0
        if (rv != SECSuccess) {
2380
0
            PK11_DeleteSlotFromList(list, le);
2381
0
            continue;
2382
0
        }
2383
0
    }
2384
0
    return list;
2385
0
}
2386
2387
/*
2388
 * returns true if the slot doesn't conform to the requested attributes
2389
 */
2390
PRBool
2391
pk11_filterSlot(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism,
2392
                CK_FLAGS mechanismInfoFlags, unsigned int keySize)
2393
237k
{
2394
237k
    CK_MECHANISM_INFO mechanism_info;
2395
237k
    CK_RV crv = CKR_OK;
2396
2397
    /* handle the only case where we don't actually fetch the mechanisms
2398
     * on the fly */
2399
237k
    if ((keySize == 0) && (mechanism == CKM_RSA_PKCS) && (slot->hasRSAInfo)) {
2400
1.35k
        mechanism_info.flags = slot->RSAInfoFlags;
2401
235k
    } else {
2402
235k
        if (!slot->isThreadSafe)
2403
0
            PK11_EnterSlotMonitor(slot);
2404
235k
        crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, mechanism,
2405
235k
                                                    &mechanism_info);
2406
235k
        if (!slot->isThreadSafe)
2407
0
            PK11_ExitSlotMonitor(slot);
2408
        /* if we were getting the RSA flags, save them */
2409
235k
        if ((crv == CKR_OK) && (mechanism == CKM_RSA_PKCS) && (!slot->hasRSAInfo)) {
2410
5
            slot->RSAInfoFlags = mechanism_info.flags;
2411
5
            slot->hasRSAInfo = PR_TRUE;
2412
5
        }
2413
235k
    }
2414
    /* couldn't get the mechanism info */
2415
237k
    if (crv != CKR_OK) {
2416
0
        return PR_TRUE;
2417
0
    }
2418
237k
    if (keySize && ((mechanism_info.ulMinKeySize > keySize) || (mechanism_info.ulMaxKeySize < keySize))) {
2419
        /* Token can do mechanism, but not at the key size we
2420
         * want */
2421
4
        return PR_TRUE;
2422
4
    }
2423
237k
    if (mechanismInfoFlags && ((mechanism_info.flags & mechanismInfoFlags) !=
2424
237k
                               mechanismInfoFlags)) {
2425
0
        return PR_TRUE;
2426
0
    }
2427
237k
    return PR_FALSE;
2428
237k
}
2429
2430
/*
2431
 * Find the best slot which supports the given set of mechanisms and key sizes.
2432
 * In normal cases this should grab the first slot on the list with no fuss.
2433
 * The size array is presumed to match one for one with the mechanism type
2434
 * array, which allows you to specify the required key size for each
2435
 * mechanism in the list. Whether key size is in bits or bytes is mechanism
2436
 * dependent. Typically asymetric keys are in bits and symetric keys are in
2437
 * bytes.
2438
 */
2439
PK11SlotInfo *
2440
PK11_GetBestSlotMultipleWithAttributes(CK_MECHANISM_TYPE *type,
2441
                                       CK_FLAGS *mechanismInfoFlags, unsigned int *keySize,
2442
                                       unsigned int mech_count, void *wincx)
2443
1.34M
{
2444
1.34M
    PK11SlotList *list = NULL;
2445
1.34M
    PK11SlotListElement *le;
2446
1.34M
    PK11SlotInfo *slot = NULL;
2447
1.34M
    PRBool freeit = PR_FALSE;
2448
1.34M
    PRBool listNeedLogin = PR_FALSE;
2449
1.34M
    unsigned int i;
2450
1.34M
    SECStatus rv;
2451
2452
1.34M
    list = PK11_GetSlotList(type[0]);
2453
2454
1.34M
    if ((list == NULL) || (list->head == NULL)) {
2455
        /* We need to look up all the tokens for the mechanism */
2456
35.5k
        list = PK11_GetAllTokens(type[0], PR_FALSE, PR_TRUE, wincx);
2457
35.5k
        freeit = PR_TRUE;
2458
35.5k
    }
2459
2460
    /* no one can do it! */
2461
1.34M
    if (list == NULL) {
2462
0
        PORT_SetError(SEC_ERROR_NO_TOKEN);
2463
0
        return NULL;
2464
0
    }
2465
2466
1.34M
    PORT_SetError(0);
2467
2468
1.34M
    listNeedLogin = PR_FALSE;
2469
2.41M
    for (i = 0; i < mech_count; i++) {
2470
1.34M
        if ((type[i] != CKM_FAKE_RANDOM) &&
2471
1.06M
            (type[i] != CKM_SHA_1) &&
2472
789k
            (type[i] != CKM_SHA224) &&
2473
579k
            (type[i] != CKM_SHA256) &&
2474
439k
            (type[i] != CKM_SHA384) &&
2475
384k
            (type[i] != CKM_SHA512) &&
2476
321k
            (type[i] != CKM_MD5) &&
2477
269k
            (type[i] != CKM_MD2)) {
2478
269k
            listNeedLogin = PR_TRUE;
2479
269k
            break;
2480
269k
        }
2481
1.34M
    }
2482
2483
1.34M
    for (le = PK11_GetFirstSafe(list); le;
2484
1.34M
         le = PK11_GetNextSafe(list, le, PR_TRUE)) {
2485
1.34M
        if (PK11_IsPresent(le->slot)) {
2486
1.34M
            PRBool doExit = PR_FALSE;
2487
2.71M
            for (i = 0; i < mech_count; i++) {
2488
1.37M
                if (!PK11_DoesMechanism(le->slot, type[i])) {
2489
3.09k
                    doExit = PR_TRUE;
2490
3.09k
                    break;
2491
3.09k
                }
2492
1.37M
                if ((mechanismInfoFlags && mechanismInfoFlags[i]) ||
2493
1.34M
                    (keySize && keySize[i])) {
2494
29.5k
                    if (pk11_filterSlot(le->slot, type[i],
2495
29.5k
                                        mechanismInfoFlags ? mechanismInfoFlags[i] : 0,
2496
29.5k
                                        keySize ? keySize[i] : 0)) {
2497
4
                        doExit = PR_TRUE;
2498
4
                        break;
2499
4
                    }
2500
29.5k
                }
2501
1.37M
            }
2502
2503
1.34M
            if (doExit)
2504
3.09k
                continue;
2505
2506
1.34M
            if (listNeedLogin && le->slot->needLogin) {
2507
0
                rv = PK11_Authenticate(le->slot, PR_TRUE, wincx);
2508
0
                if (rv != SECSuccess)
2509
0
                    continue;
2510
0
            }
2511
1.34M
            slot = le->slot;
2512
1.34M
            PK11_ReferenceSlot(slot);
2513
1.34M
            PK11_FreeSlotListElement(list, le);
2514
1.34M
            if (freeit) {
2515
35.1k
                PK11_FreeSlotList(list);
2516
35.1k
            }
2517
1.34M
            return slot;
2518
1.34M
        }
2519
1.34M
    }
2520
3.11k
    if (freeit) {
2521
382
        PK11_FreeSlotList(list);
2522
382
    }
2523
3.11k
    if (PORT_GetError() == 0) {
2524
3.11k
        PORT_SetError(SEC_ERROR_NO_TOKEN);
2525
3.11k
    }
2526
3.11k
    return NULL;
2527
1.34M
}
2528
2529
PK11SlotInfo *
2530
PK11_GetBestSlotMultiple(CK_MECHANISM_TYPE *type,
2531
                         unsigned int mech_count, void *wincx)
2532
17.9k
{
2533
17.9k
    return PK11_GetBestSlotMultipleWithAttributes(type, NULL, NULL,
2534
17.9k
                                                  mech_count, wincx);
2535
17.9k
}
2536
2537
/* original get best slot now calls the multiple version with only one type */
2538
PK11SlotInfo *
2539
PK11_GetBestSlot(CK_MECHANISM_TYPE type, void *wincx)
2540
1.29M
{
2541
1.29M
    return PK11_GetBestSlotMultipleWithAttributes(&type, NULL, NULL, 1, wincx);
2542
1.29M
}
2543
2544
PK11SlotInfo *
2545
PK11_GetBestSlotWithAttributes(CK_MECHANISM_TYPE type, CK_FLAGS mechanismFlags,
2546
                               unsigned int keySize, void *wincx)
2547
29.5k
{
2548
29.5k
    return PK11_GetBestSlotMultipleWithAttributes(&type, &mechanismFlags,
2549
29.5k
                                                  &keySize, 1, wincx);
2550
29.5k
}
2551
2552
int
2553
PK11_GetBestKeyLength(PK11SlotInfo *slot, CK_MECHANISM_TYPE mechanism)
2554
5.91k
{
2555
5.91k
    CK_MECHANISM_INFO mechanism_info;
2556
5.91k
    CK_RV crv;
2557
2558
5.91k
    if (!slot->isThreadSafe)
2559
0
        PK11_EnterSlotMonitor(slot);
2560
5.91k
    crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
2561
5.91k
                                                mechanism, &mechanism_info);
2562
5.91k
    if (!slot->isThreadSafe)
2563
0
        PK11_ExitSlotMonitor(slot);
2564
5.91k
    if (crv != CKR_OK)
2565
0
        return 0;
2566
2567
5.91k
    if (mechanism_info.ulMinKeySize == mechanism_info.ulMaxKeySize)
2568
5.91k
        return 0;
2569
0
    return mechanism_info.ulMaxKeySize;
2570
5.91k
}
2571
2572
/*
2573
 * This function uses the existing PKCS #11 module to find the
2574
 * longest supported key length in the preferred token for a mechanism.
2575
 * This varies from the above function in that 1) it returns the key length
2576
 * even for fixed key algorithms, and 2) it looks through the tokens
2577
 * generally rather than for a specific token. This is used in liu of
2578
 * a PK11_GetKeyLength function in pk11mech.c since we can actually read
2579
 * supported key lengths from PKCS #11.
2580
 *
2581
 * For symmetric key operations the length is returned in bytes.
2582
 */
2583
int
2584
PK11_GetMaxKeyLength(CK_MECHANISM_TYPE mechanism)
2585
3.45k
{
2586
3.45k
    CK_MECHANISM_INFO mechanism_info;
2587
3.45k
    PK11SlotList *list = NULL;
2588
3.45k
    PK11SlotListElement *le;
2589
3.45k
    PRBool freeit = PR_FALSE;
2590
3.45k
    int keyLength = 0;
2591
2592
3.45k
    list = PK11_GetSlotList(mechanism);
2593
2594
3.45k
    if ((list == NULL) || (list->head == NULL)) {
2595
        /* We need to look up all the tokens for the mechanism */
2596
1.97k
        list = PK11_GetAllTokens(mechanism, PR_FALSE, PR_FALSE, NULL);
2597
1.97k
        freeit = PR_TRUE;
2598
1.97k
    }
2599
2600
    /* no tokens recognize this mechanism */
2601
3.45k
    if (list == NULL) {
2602
0
        PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
2603
0
        return 0;
2604
0
    }
2605
2606
4.28k
    for (le = PK11_GetFirstSafe(list); le;
2607
3.45k
         le = PK11_GetNextSafe(list, le, PR_TRUE)) {
2608
3.03k
        PK11SlotInfo *slot = le->slot;
2609
3.03k
        CK_RV crv;
2610
3.03k
        if (PK11_IsPresent(slot)) {
2611
3.03k
            if (!slot->isThreadSafe)
2612
0
                PK11_EnterSlotMonitor(slot);
2613
3.03k
            crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID,
2614
3.03k
                                                        mechanism, &mechanism_info);
2615
3.03k
            if (!slot->isThreadSafe)
2616
0
                PK11_ExitSlotMonitor(slot);
2617
3.03k
            if ((crv == CKR_OK) && (mechanism_info.ulMaxKeySize != 0) && (mechanism_info.ulMaxKeySize != 0xffffffff)) {
2618
2.20k
                keyLength = mechanism_info.ulMaxKeySize;
2619
2.20k
                break;
2620
2.20k
            }
2621
3.03k
        }
2622
3.03k
    }
2623
2624
    /* fallback to pk11_GetPredefinedKeyLength for fixed key size algorithms */
2625
3.45k
    if (keyLength == 0) {
2626
1.25k
        CK_KEY_TYPE keyType;
2627
1.25k
        keyType = PK11_GetKeyType(mechanism, 0);
2628
1.25k
        keyLength = pk11_GetPredefinedKeyLength(keyType);
2629
1.25k
    }
2630
2631
3.45k
    if (le)
2632
2.20k
        PK11_FreeSlotListElement(list, le);
2633
3.45k
    if (freeit)
2634
1.97k
        PK11_FreeSlotList(list);
2635
3.45k
    return keyLength;
2636
3.45k
}
2637
2638
SECStatus
2639
PK11_SeedRandom(PK11SlotInfo *slot, unsigned char *data, int len)
2640
0
{
2641
0
    CK_RV crv;
2642
2643
0
    PK11_EnterSlotMonitor(slot);
2644
0
    crv = PK11_GETTAB(slot)->C_SeedRandom(slot->session, data, (CK_ULONG)len);
2645
0
    PK11_ExitSlotMonitor(slot);
2646
0
    if (crv != CKR_OK) {
2647
0
        PORT_SetError(PK11_MapError(crv));
2648
0
        return SECFailure;
2649
0
    }
2650
0
    return SECSuccess;
2651
0
}
2652
2653
SECStatus
2654
PK11_GenerateRandomOnSlot(PK11SlotInfo *slot, unsigned char *data, int len)
2655
276k
{
2656
276k
    CK_RV crv;
2657
2658
276k
    if (!slot->isInternal)
2659
0
        PK11_EnterSlotMonitor(slot);
2660
276k
    crv = PK11_GETTAB(slot)->C_GenerateRandom(slot->session, data,
2661
276k
                                              (CK_ULONG)len);
2662
276k
    if (!slot->isInternal)
2663
0
        PK11_ExitSlotMonitor(slot);
2664
276k
    if (crv != CKR_OK) {
2665
0
        PORT_SetError(PK11_MapError(crv));
2666
0
        return SECFailure;
2667
0
    }
2668
276k
    return SECSuccess;
2669
276k
}
2670
2671
/* Attempts to update the Best Slot for "FAKE RANDOM" generation.
2672
** If that's not the internal slot, then it also attempts to update the
2673
** internal slot.
2674
** The return value indicates if the INTERNAL slot was updated OK.
2675
*/
2676
SECStatus
2677
PK11_RandomUpdate(void *data, size_t bytes)
2678
0
{
2679
0
    PK11SlotInfo *slot;
2680
0
    PRBool bestIsInternal;
2681
0
    SECStatus status;
2682
2683
0
    slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
2684
0
    if (slot == NULL) {
2685
0
        slot = PK11_GetInternalSlot();
2686
0
        if (!slot)
2687
0
            return SECFailure;
2688
0
    }
2689
2690
0
    bestIsInternal = PK11_IsInternal(slot);
2691
0
    status = PK11_SeedRandom(slot, data, bytes);
2692
0
    PK11_FreeSlot(slot);
2693
2694
0
    if (!bestIsInternal) {
2695
        /* do internal slot, too. */
2696
0
        slot = PK11_GetInternalSlot();
2697
0
        PORT_Assert(slot);
2698
0
        if (!slot) {
2699
0
            return SECFailure;
2700
0
        }
2701
0
        status = PK11_SeedRandom(slot, data, bytes);
2702
0
        PK11_FreeSlot(slot);
2703
0
    }
2704
0
    return status;
2705
0
}
2706
2707
SECStatus
2708
PK11_GenerateRandom(unsigned char *data, int len)
2709
276k
{
2710
276k
    PK11SlotInfo *slot;
2711
276k
    SECStatus rv;
2712
2713
276k
    slot = PK11_GetBestSlot(CKM_FAKE_RANDOM, NULL);
2714
276k
    if (slot == NULL)
2715
0
        return SECFailure;
2716
2717
276k
    rv = PK11_GenerateRandomOnSlot(slot, data, len);
2718
276k
    PK11_FreeSlot(slot);
2719
276k
    return rv;
2720
276k
}
2721
2722
/*
2723
 * Reset the token to it's initial state. For the internal module, this will
2724
 * Purge your keydb, and reset your cert db certs to USER_INIT.
2725
 */
2726
SECStatus
2727
PK11_ResetToken(PK11SlotInfo *slot, char *sso_pwd)
2728
0
{
2729
0
    unsigned char tokenName[32];
2730
0
    size_t tokenNameLen;
2731
0
    CK_RV crv;
2732
2733
    /* reconstruct the token name */
2734
0
    tokenNameLen = PORT_Strlen(slot->token_name);
2735
0
    if (tokenNameLen > sizeof(tokenName)) {
2736
0
        tokenNameLen = sizeof(tokenName);
2737
0
    }
2738
2739
0
    PORT_Memcpy(tokenName, slot->token_name, tokenNameLen);
2740
0
    if (tokenNameLen < sizeof(tokenName)) {
2741
0
        PORT_Memset(&tokenName[tokenNameLen], ' ',
2742
0
                    sizeof(tokenName) - tokenNameLen);
2743
0
    }
2744
2745
    /* initialize the token */
2746
0
    PK11_EnterSlotMonitor(slot);
2747
2748
    /* first shutdown the token. Existing sessions will get closed here */
2749
0
    PK11_GETTAB(slot)
2750
0
        ->C_CloseAllSessions(slot->slotID);
2751
0
    slot->session = CK_INVALID_HANDLE;
2752
2753
    /* now re-init the token */
2754
0
    crv = PK11_GETTAB(slot)->C_InitToken(slot->slotID,
2755
0
                                         (unsigned char *)sso_pwd, sso_pwd ? PORT_Strlen(sso_pwd) : 0, tokenName);
2756
2757
    /* finally bring the token back up */
2758
0
    PK11_InitToken(slot, PR_TRUE);
2759
0
    PK11_ExitSlotMonitor(slot);
2760
0
    if (crv != CKR_OK) {
2761
0
        PORT_SetError(PK11_MapError(crv));
2762
0
        return SECFailure;
2763
0
    }
2764
0
    NSSToken *token = PK11Slot_GetNSSToken(slot);
2765
0
    if (token) {
2766
0
        nssTrustDomain_UpdateCachedTokenCerts(token->trustDomain, token);
2767
0
        (void)nssToken_Destroy(token);
2768
0
    }
2769
0
    return SECSuccess;
2770
0
}
2771
2772
void
2773
PK11Slot_SetNSSToken(PK11SlotInfo *sl, NSSToken *nsst)
2774
60
{
2775
60
    NSSToken *old;
2776
60
    if (nsst) {
2777
32
        nsst = nssToken_AddRef(nsst);
2778
32
    }
2779
2780
60
    PZ_Lock(sl->nssTokenLock);
2781
60
    old = sl->nssToken;
2782
60
    sl->nssToken = nsst;
2783
60
    PZ_Unlock(sl->nssTokenLock);
2784
2785
60
    if (old) {
2786
28
        (void)nssToken_Destroy(old);
2787
28
    }
2788
60
}
2789
2790
NSSToken *
2791
PK11Slot_GetNSSToken(PK11SlotInfo *sl)
2792
607k
{
2793
607k
    NSSToken *rv = NULL;
2794
2795
607k
    PZ_Lock(sl->nssTokenLock);
2796
607k
    if (sl->nssToken) {
2797
606k
        rv = nssToken_AddRef(sl->nssToken);
2798
606k
    }
2799
607k
    PZ_Unlock(sl->nssTokenLock);
2800
2801
607k
    return rv;
2802
607k
}
2803
2804
PRBool
2805
pk11slot_GetFIPSStatus(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
2806
                       CK_OBJECT_HANDLE object, CK_ULONG operationType)
2807
0
{
2808
0
    SECMODModule *mod = slot->module;
2809
0
    CK_RV crv;
2810
0
    CK_ULONG fipsState = CKS_NSS_FIPS_NOT_OK;
2811
2812
0
    if (PK11_CheckPKCS11Version(slot, 3, 2, PR_TRUE) >= 0) {
2813
0
        CK_FLAGS validationFlags = 0;
2814
2815
        /* module isn't validated */
2816
0
        if (slot->validationFIPSFlags == 0) {
2817
0
            return PR_FALSE;
2818
0
        }
2819
0
        switch (operationType) {
2820
            /* in pkcs #11, these are equivalent */
2821
0
            case CKT_NSS_SESSION_LAST_CHECK:
2822
0
            case CKT_NSS_SESSION_CHECK:
2823
0
                crv = PK11_GETTAB(slot)->C_GetSessionValidationFlags(session,
2824
0
                                                                     CKS_LAST_VALIDATION_OK, &validationFlags);
2825
0
                if (crv != CKR_OK) {
2826
0
                    return PR_FALSE;
2827
0
                }
2828
0
                break;
2829
0
            case CKT_NSS_OBJECT_CHECK:
2830
0
                validationFlags = PK11_ReadULongAttribute(slot, object,
2831
0
                                                          CKA_OBJECT_VALIDATION_FLAGS);
2832
0
                if (validationFlags == CK_UNAVAILABLE_INFORMATION) {
2833
0
                    return PR_FALSE;
2834
0
                }
2835
0
                break;
2836
0
            default:
2837
0
                return PR_FALSE;
2838
0
        }
2839
0
        return (PRBool)(validationFlags & slot->validationFIPSFlags) != 0;
2840
0
    }
2841
    /* handle the NSS vendor specific indicators, for older modules */
2842
    /* handle the obvious conditions:
2843
     * 1) the module doesn't have a fipsIndicator - fips state must be false */
2844
0
    if (mod->fipsIndicator == NULL) {
2845
0
        return PR_FALSE;
2846
0
    }
2847
    /* 2) the session doesn't exist - fips state must be false */
2848
0
    if (session == CK_INVALID_HANDLE) {
2849
0
        return PR_FALSE;
2850
0
    }
2851
2852
    /* go fetch the state */
2853
0
    crv = mod->fipsIndicator(session, object, operationType, &fipsState);
2854
0
    if (crv != CKR_OK) {
2855
0
        return PR_FALSE;
2856
0
    }
2857
0
    return (fipsState == CKS_NSS_FIPS_OK) ? PR_TRUE : PR_FALSE;
2858
0
}
2859
2860
PRBool
2861
PK11_SlotGetLastFIPSStatus(PK11SlotInfo *slot)
2862
0
{
2863
0
    return pk11slot_GetFIPSStatus(slot, slot->session, CK_INVALID_HANDLE,
2864
0
                                  CKT_NSS_SESSION_LAST_CHECK);
2865
0
}
2866
2867
/*
2868
 * wait for a token to change it's state. The application passes in the expected
2869
 * new state in event.
2870
 */
2871
PK11TokenStatus
2872
PK11_WaitForTokenEvent(PK11SlotInfo *slot, PK11TokenEvent event,
2873
                       PRIntervalTime timeout, PRIntervalTime latency, int series)
2874
0
{
2875
0
    PRIntervalTime first_time = 0;
2876
0
    PRBool first_time_set = PR_FALSE;
2877
0
    PRBool waitForRemoval;
2878
2879
0
    if (slot->isPerm) {
2880
0
        return PK11TokenNotRemovable;
2881
0
    }
2882
0
    if (latency == 0) {
2883
0
        latency = PR_SecondsToInterval(5);
2884
0
    }
2885
0
    waitForRemoval = (PRBool)(event == PK11TokenRemovedOrChangedEvent);
2886
2887
0
    if (series == 0) {
2888
0
        series = PK11_GetSlotSeries(slot);
2889
0
    }
2890
0
    while (PK11_IsPresent(slot) == waitForRemoval) {
2891
0
        PRIntervalTime interval;
2892
2893
0
        if (waitForRemoval && series != PK11_GetSlotSeries(slot)) {
2894
0
            return PK11TokenChanged;
2895
0
        }
2896
0
        if (timeout == PR_INTERVAL_NO_WAIT) {
2897
0
            return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
2898
0
        }
2899
0
        if (timeout != PR_INTERVAL_NO_TIMEOUT) {
2900
0
            interval = PR_IntervalNow();
2901
0
            if (!first_time_set) {
2902
0
                first_time = interval;
2903
0
                first_time_set = PR_TRUE;
2904
0
            }
2905
0
            if ((interval - first_time) > timeout) {
2906
0
                return waitForRemoval ? PK11TokenPresent : PK11TokenRemoved;
2907
0
            }
2908
0
        }
2909
0
        PR_Sleep(latency);
2910
0
    }
2911
0
    return waitForRemoval ? PK11TokenRemoved : PK11TokenPresent;
2912
0
}