Coverage Report

Created: 2025-08-18 06:36

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