Coverage Report

Created: 2025-09-17 07:05

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