Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/pk11wrap/pk11util.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
 * Initialize the PCKS 11 subsystem
6
 */
7
#include "seccomon.h"
8
#include "secmod.h"
9
#include "nssilock.h"
10
#include "secmodi.h"
11
#include "secmodti.h"
12
#include "pk11func.h"
13
#include "pki3hack.h"
14
#include "secerr.h"
15
#include "dev.h"
16
#include "dev3hack.h"
17
#include "utilpars.h"
18
#include "pkcs11uri.h"
19
20
/* these are for displaying error messages */
21
22
static SECMODModuleList *modules = NULL;
23
static SECMODModuleList *modulesDB = NULL;
24
static SECMODModuleList *modulesUnload = NULL;
25
static SECMODModule *internalModule = NULL;
26
static SECMODModule *defaultDBModule = NULL;
27
static SECMODModule *pendingModule = NULL;
28
static SECMODListLock *moduleLock = NULL;
29
30
int secmod_PrivateModuleCount = 0;
31
32
extern const PK11DefaultArrayEntry PK11_DefaultArray[];
33
extern const int num_pk11_default_mechanisms;
34
35
void
36
SECMOD_Init()
37
4
{
38
    /* don't initialize twice */
39
4
    if (moduleLock)
40
2
        return;
41
42
2
    moduleLock = SECMOD_NewListLock();
43
2
    PK11_InitSlotLists();
44
2
}
45
46
SECStatus
47
SECMOD_Shutdown()
48
0
{
49
    /* destroy the lock */
50
0
    if (moduleLock) {
51
0
        SECMOD_DestroyListLock(moduleLock);
52
0
        moduleLock = NULL;
53
0
    }
54
    /* free the internal module */
55
0
    if (internalModule) {
56
0
        SECMOD_DestroyModule(internalModule);
57
0
        internalModule = NULL;
58
0
    }
59
60
    /* free the default database module */
61
0
    if (defaultDBModule) {
62
0
        SECMOD_DestroyModule(defaultDBModule);
63
0
        defaultDBModule = NULL;
64
0
    }
65
66
    /* destroy the list */
67
0
    if (modules) {
68
0
        SECMOD_DestroyModuleList(modules);
69
0
        modules = NULL;
70
0
    }
71
72
0
    if (modulesDB) {
73
0
        SECMOD_DestroyModuleList(modulesDB);
74
0
        modulesDB = NULL;
75
0
    }
76
77
0
    if (modulesUnload) {
78
0
        SECMOD_DestroyModuleList(modulesUnload);
79
0
        modulesUnload = NULL;
80
0
    }
81
82
    /* make all the slots and the lists go away */
83
0
    PK11_DestroySlotLists();
84
85
0
    nss_DumpModuleLog();
86
87
0
#ifdef DEBUG
88
0
    if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) {
89
0
        PORT_Assert(secmod_PrivateModuleCount == 0);
90
0
    }
91
0
#endif
92
0
    if (secmod_PrivateModuleCount) {
93
0
        PORT_SetError(SEC_ERROR_BUSY);
94
0
        return SECFailure;
95
0
    }
96
0
    return SECSuccess;
97
0
}
98
99
PRBool
100
SECMOD_GetSystemFIPSEnabled(void)
101
4
{
102
4
    return NSS_GetSystemFIPSEnabled();
103
4
}
104
105
/*
106
 * retrieve the internal module
107
 */
108
SECMODModule *
109
SECMOD_GetInternalModule(void)
110
645
{
111
645
    return internalModule;
112
645
}
113
114
SECStatus
115
secmod_AddModuleToList(SECMODModuleList **moduleList, SECMODModule *newModule)
116
4
{
117
4
    SECMODModuleList *mlp, *newListElement, *last = NULL;
118
119
4
    newListElement = SECMOD_NewModuleListElement();
120
4
    if (newListElement == NULL) {
121
0
        return SECFailure;
122
0
    }
123
124
4
    newListElement->module = SECMOD_ReferenceModule(newModule);
125
126
4
    SECMOD_GetWriteLock(moduleLock);
127
    /* Added it to the end (This is very inefficient, but Adding a module
128
     * on the fly should happen maybe 2-3 times through the life this program
129
     * on a given computer, and this list should be *SHORT*. */
130
4
    for (mlp = *moduleList; mlp != NULL; mlp = mlp->next) {
131
0
        last = mlp;
132
0
    }
133
134
4
    if (last == NULL) {
135
4
        *moduleList = newListElement;
136
4
    } else {
137
0
        SECMOD_AddList(last, newListElement, NULL);
138
0
    }
139
4
    SECMOD_ReleaseWriteLock(moduleLock);
140
4
    return SECSuccess;
141
4
}
142
143
SECStatus
144
SECMOD_AddModuleToList(SECMODModule *newModule)
145
2
{
146
2
    if (newModule->internal && !internalModule) {
147
2
        internalModule = SECMOD_ReferenceModule(newModule);
148
2
    }
149
2
    return secmod_AddModuleToList(&modules, newModule);
150
2
}
151
152
SECStatus
153
SECMOD_AddModuleToDBOnlyList(SECMODModule *newModule)
154
2
{
155
2
    if (defaultDBModule && SECMOD_GetDefaultModDBFlag(newModule)) {
156
0
        SECMOD_DestroyModule(defaultDBModule);
157
0
        defaultDBModule = SECMOD_ReferenceModule(newModule);
158
2
    } else if (defaultDBModule == NULL) {
159
2
        defaultDBModule = SECMOD_ReferenceModule(newModule);
160
2
    }
161
2
    return secmod_AddModuleToList(&modulesDB, newModule);
162
2
}
163
164
SECStatus
165
SECMOD_AddModuleToUnloadList(SECMODModule *newModule)
166
0
{
167
0
    return secmod_AddModuleToList(&modulesUnload, newModule);
168
0
}
169
170
/*
171
 * get the list of PKCS11 modules that are available.
172
 */
173
SECMODModuleList *
174
SECMOD_GetDefaultModuleList()
175
49
{
176
49
    return modules;
177
49
}
178
SECMODModuleList *
179
SECMOD_GetDeadModuleList()
180
0
{
181
0
    return modulesUnload;
182
0
}
183
SECMODModuleList *
184
SECMOD_GetDBModuleList()
185
0
{
186
0
    return modulesDB;
187
0
}
188
189
/*
190
 * This lock protects the global module lists.
191
 * it also protects changes to the slot array (module->slots[]) and slot count
192
 * (module->slotCount) in each module. It is a read/write lock with multiple
193
 * readers or one writer. Writes are uncommon.
194
 * Because of legacy considerations protection of the slot array and count is
195
 * only necessary in applications if the application calls
196
 * SECMOD_UpdateSlotList() or SECMOD_WaitForAnyTokenEvent(), though all new
197
 * applications are encouraged to acquire this lock when reading the
198
 * slot array information directly.
199
 */
200
SECMODListLock *
201
SECMOD_GetDefaultModuleListLock()
202
49
{
203
49
    return moduleLock;
204
49
}
205
206
/*
207
 * find a module by name, and add a reference to it.
208
 * return that module.
209
 */
210
SECMODModule *
211
SECMOD_FindModule(const char *name)
212
0
{
213
0
    SECMODModuleList *mlp;
214
0
    SECMODModule *module = NULL;
215
216
0
    if (!moduleLock) {
217
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
218
0
        return module;
219
0
    }
220
0
    SECMOD_GetReadLock(moduleLock);
221
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
222
0
        if (PORT_Strcmp(name, mlp->module->commonName) == 0) {
223
0
            module = mlp->module;
224
0
            SECMOD_ReferenceModule(module);
225
0
            break;
226
0
        }
227
0
    }
228
0
    if (module) {
229
0
        goto found;
230
0
    }
231
0
    for (mlp = modulesUnload; mlp != NULL; mlp = mlp->next) {
232
0
        if (PORT_Strcmp(name, mlp->module->commonName) == 0) {
233
0
            module = mlp->module;
234
0
            SECMOD_ReferenceModule(module);
235
0
            break;
236
0
        }
237
0
    }
238
239
0
found:
240
0
    SECMOD_ReleaseReadLock(moduleLock);
241
242
0
    return module;
243
0
}
244
245
/*
246
 * find a module by ID, and add a reference to it.
247
 * return that module.
248
 */
249
SECMODModule *
250
SECMOD_FindModuleByID(SECMODModuleID id)
251
0
{
252
0
    SECMODModuleList *mlp;
253
0
    SECMODModule *module = NULL;
254
255
0
    if (!moduleLock) {
256
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
257
0
        return module;
258
0
    }
259
0
    SECMOD_GetReadLock(moduleLock);
260
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
261
0
        if (id == mlp->module->moduleID) {
262
0
            module = mlp->module;
263
0
            SECMOD_ReferenceModule(module);
264
0
            break;
265
0
        }
266
0
    }
267
0
    SECMOD_ReleaseReadLock(moduleLock);
268
0
    if (module == NULL) {
269
0
        PORT_SetError(SEC_ERROR_NO_MODULE);
270
0
    }
271
0
    return module;
272
0
}
273
274
/*
275
 * find the function pointer.
276
 */
277
SECMODModule *
278
secmod_FindModuleByFuncPtr(void *funcPtr)
279
0
{
280
0
    SECMODModuleList *mlp;
281
0
    SECMODModule *module = NULL;
282
283
0
    SECMOD_GetReadLock(moduleLock);
284
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
285
        /* paranoia, shouldn't ever happen */
286
0
        if (!mlp->module) {
287
0
            continue;
288
0
        }
289
0
        if (funcPtr == mlp->module->functionList) {
290
0
            module = mlp->module;
291
0
            SECMOD_ReferenceModule(module);
292
0
            break;
293
0
        }
294
0
    }
295
0
    SECMOD_ReleaseReadLock(moduleLock);
296
0
    if (module == NULL) {
297
0
        PORT_SetError(SEC_ERROR_NO_MODULE);
298
0
    }
299
0
    return module;
300
0
}
301
302
/*
303
 * Find the Slot based on ID and the module.
304
 */
305
PK11SlotInfo *
306
SECMOD_FindSlotByID(SECMODModule *module, CK_SLOT_ID slotID)
307
0
{
308
0
    int i;
309
0
    PK11SlotInfo *slot = NULL;
310
311
0
    if (!moduleLock) {
312
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
313
0
        return slot;
314
0
    }
315
0
    SECMOD_GetReadLock(moduleLock);
316
0
    for (i = 0; i < module->slotCount; i++) {
317
0
        PK11SlotInfo *cSlot = module->slots[i];
318
319
0
        if (cSlot->slotID == slotID) {
320
0
            slot = PK11_ReferenceSlot(cSlot);
321
0
            break;
322
0
        }
323
0
    }
324
0
    SECMOD_ReleaseReadLock(moduleLock);
325
326
0
    if (slot == NULL) {
327
0
        PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
328
0
    }
329
0
    return slot;
330
0
}
331
332
/*
333
 * lookup the Slot module based on it's module ID and slot ID.
334
 */
335
PK11SlotInfo *
336
SECMOD_LookupSlot(SECMODModuleID moduleID, CK_SLOT_ID slotID)
337
0
{
338
0
    SECMODModule *module;
339
0
    PK11SlotInfo *slot;
340
341
0
    module = SECMOD_FindModuleByID(moduleID);
342
0
    if (module == NULL)
343
0
        return NULL;
344
345
0
    slot = SECMOD_FindSlotByID(module, slotID);
346
0
    SECMOD_DestroyModule(module);
347
0
    return slot;
348
0
}
349
350
/*
351
 * find a module by name or module pointer and delete it off the module list.
352
 * optionally remove it from secmod.db.
353
 */
354
SECStatus
355
SECMOD_DeleteModuleEx(const char *name, SECMODModule *mod,
356
                      int *type, PRBool permdb)
357
0
{
358
0
    SECMODModuleList *mlp;
359
0
    SECMODModuleList **mlpp;
360
0
    SECStatus rv = SECFailure;
361
362
0
    if (!moduleLock) {
363
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
364
0
        return rv;
365
0
    }
366
367
0
    *type = SECMOD_EXTERNAL;
368
369
0
    SECMOD_GetWriteLock(moduleLock);
370
0
    for (mlpp = &modules, mlp = modules;
371
0
         mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
372
0
        if ((name && (PORT_Strcmp(name, mlp->module->commonName) == 0)) ||
373
0
            mod == mlp->module) {
374
            /* don't delete the internal module */
375
0
            if (!mlp->module->internal) {
376
0
                SECMOD_RemoveList(mlpp, mlp);
377
                /* delete it after we release the lock */
378
0
                rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
379
0
            } else if (mlp->module->isFIPS) {
380
0
                *type = SECMOD_FIPS;
381
0
            } else {
382
0
                *type = SECMOD_INTERNAL;
383
0
            }
384
0
            break;
385
0
        }
386
0
    }
387
0
    if (mlp) {
388
0
        goto found;
389
0
    }
390
    /* not on the internal list, check the unload list */
391
0
    for (mlpp = &modulesUnload, mlp = modulesUnload;
392
0
         mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
393
0
        if ((name && (PORT_Strcmp(name, mlp->module->commonName) == 0)) ||
394
0
            mod == mlp->module) {
395
            /* don't delete the internal module */
396
0
            if (!mlp->module->internal) {
397
0
                SECMOD_RemoveList(mlpp, mlp);
398
0
                rv = SECSuccess;
399
0
            } else if (mlp->module->isFIPS) {
400
0
                *type = SECMOD_FIPS;
401
0
            } else {
402
0
                *type = SECMOD_INTERNAL;
403
0
            }
404
0
            break;
405
0
        }
406
0
    }
407
0
found:
408
0
    SECMOD_ReleaseWriteLock(moduleLock);
409
410
0
    if (rv == SECSuccess) {
411
0
        if (permdb) {
412
0
            SECMOD_DeletePermDB(mlp->module);
413
0
        }
414
0
        SECMOD_DestroyModuleListElement(mlp);
415
0
    }
416
0
    return rv;
417
0
}
418
419
/*
420
 * find a module by name and delete it off the module list
421
 */
422
SECStatus
423
SECMOD_DeleteModule(const char *name, int *type)
424
0
{
425
0
    return SECMOD_DeleteModuleEx(name, NULL, type, PR_TRUE);
426
0
}
427
428
/*
429
 * find a module by name and delete it off the module list
430
 */
431
SECStatus
432
SECMOD_DeleteInternalModule(const char *name)
433
0
{
434
0
#ifndef NSS_FIPS_DISABLED
435
0
    SECMODModuleList *mlp;
436
0
    SECMODModuleList **mlpp;
437
0
#endif
438
0
    SECStatus rv = SECFailure;
439
440
0
    if (SECMOD_GetSystemFIPSEnabled() || pendingModule) {
441
0
        PORT_SetError(SEC_ERROR_MODULE_STUCK);
442
0
        return rv;
443
0
    }
444
0
    if (!moduleLock) {
445
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
446
0
        return rv;
447
0
    }
448
449
#ifdef NSS_FIPS_DISABLED
450
    PORT_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR);
451
    return rv;
452
#else
453
0
    SECMOD_GetWriteLock(moduleLock);
454
0
    for (mlpp = &modules, mlp = modules;
455
0
         mlp != NULL; mlpp = &mlp->next, mlp = *mlpp) {
456
0
        if (PORT_Strcmp(name, mlp->module->commonName) == 0) {
457
            /* don't delete the internal module */
458
0
            if (mlp->module->internal) {
459
0
                SECMOD_RemoveList(mlpp, mlp);
460
0
                rv = STAN_RemoveModuleFromDefaultTrustDomain(mlp->module);
461
0
            }
462
0
            break;
463
0
        }
464
0
    }
465
0
    SECMOD_ReleaseWriteLock(moduleLock);
466
467
0
    if (rv == SECSuccess) {
468
0
        SECMODModule *newModule, *oldModule;
469
470
0
        if (mlp->module->isFIPS) {
471
0
            newModule = SECMOD_CreateModule(NULL, SECMOD_INT_NAME,
472
0
                                            NULL, SECMOD_INT_FLAGS);
473
0
        } else {
474
0
            newModule = SECMOD_CreateModule(NULL, SECMOD_FIPS_NAME,
475
0
                                            NULL, SECMOD_FIPS_FLAGS);
476
0
        }
477
0
        if (newModule) {
478
0
            PK11SlotInfo *slot;
479
0
            newModule->libraryParams =
480
0
                PORT_ArenaStrdup(newModule->arena, mlp->module->libraryParams);
481
            /* if an explicit internal key slot has been set, reset it */
482
0
            slot = pk11_SwapInternalKeySlot(NULL);
483
0
            if (slot) {
484
0
                secmod_SetInternalKeySlotFlag(newModule, PR_TRUE);
485
0
            }
486
0
            rv = SECMOD_AddModule(newModule);
487
0
            if (rv != SECSuccess) {
488
                /* load failed, restore the internal key slot */
489
0
                pk11_SetInternalKeySlot(slot);
490
0
                SECMOD_DestroyModule(newModule);
491
0
                newModule = NULL;
492
0
            }
493
            /* free the old explicit internal key slot, we now have a new one */
494
0
            if (slot) {
495
0
                PK11_FreeSlot(slot);
496
0
            }
497
0
        }
498
0
        if (newModule == NULL) {
499
0
            SECMODModuleList *last = NULL, *mlp2;
500
            /* we're in pretty deep trouble if this happens...Security
501
             * not going to work well... try to put the old module back on
502
             * the list */
503
0
            SECMOD_GetWriteLock(moduleLock);
504
0
            for (mlp2 = modules; mlp2 != NULL; mlp2 = mlp->next) {
505
0
                last = mlp2;
506
0
            }
507
508
0
            if (last == NULL) {
509
0
                modules = mlp;
510
0
            } else {
511
0
                SECMOD_AddList(last, mlp, NULL);
512
0
            }
513
0
            SECMOD_ReleaseWriteLock(moduleLock);
514
0
            return SECFailure;
515
0
        }
516
0
        pendingModule = oldModule = internalModule;
517
0
        internalModule = NULL;
518
0
        SECMOD_DestroyModule(oldModule);
519
0
        SECMOD_DeletePermDB(mlp->module);
520
0
        SECMOD_DestroyModuleListElement(mlp);
521
0
        internalModule = newModule; /* adopt the module */
522
0
    }
523
0
    return rv;
524
0
#endif
525
0
}
526
527
SECStatus
528
SECMOD_AddModule(SECMODModule *newModule)
529
0
{
530
0
    SECStatus rv;
531
0
    SECMODModule *oldModule;
532
533
    /* Test if a module w/ the same name already exists */
534
    /* and return SECWouldBlock if so. */
535
    /* We should probably add a new return value such as */
536
    /* SECDublicateModule, but to minimize ripples, I'll */
537
    /* give SECWouldBlock a new meaning */
538
0
    if ((oldModule = SECMOD_FindModule(newModule->commonName)) != NULL) {
539
0
        SECMOD_DestroyModule(oldModule);
540
0
        return SECWouldBlock;
541
        /* module already exists. */
542
0
    }
543
544
0
    rv = secmod_LoadPKCS11Module(newModule, NULL);
545
0
    if (rv != SECSuccess) {
546
0
        return rv;
547
0
    }
548
549
0
    if (newModule->parent == NULL) {
550
0
        newModule->parent = SECMOD_ReferenceModule(defaultDBModule);
551
0
    }
552
553
0
    SECMOD_AddPermDB(newModule);
554
0
    SECMOD_AddModuleToList(newModule);
555
556
0
    rv = STAN_AddModuleToDefaultTrustDomain(newModule);
557
558
0
    return rv;
559
0
}
560
561
PK11SlotInfo *
562
SECMOD_FindSlot(SECMODModule *module, const char *name)
563
0
{
564
0
    int i;
565
0
    char *string;
566
0
    PK11SlotInfo *retSlot = NULL;
567
568
0
    if (!moduleLock) {
569
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
570
0
        return retSlot;
571
0
    }
572
0
    SECMOD_GetReadLock(moduleLock);
573
0
    for (i = 0; i < module->slotCount; i++) {
574
0
        PK11SlotInfo *slot = module->slots[i];
575
576
0
        if (PK11_IsPresent(slot)) {
577
0
            string = PK11_GetTokenName(slot);
578
0
        } else {
579
0
            string = PK11_GetSlotName(slot);
580
0
        }
581
0
        if (PORT_Strcmp(name, string) == 0) {
582
0
            retSlot = PK11_ReferenceSlot(slot);
583
0
            break;
584
0
        }
585
0
    }
586
0
    SECMOD_ReleaseReadLock(moduleLock);
587
588
0
    if (retSlot == NULL) {
589
0
        PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
590
0
    }
591
0
    return retSlot;
592
0
}
593
594
SECStatus
595
PK11_GetModInfo(SECMODModule *mod, CK_INFO *info)
596
0
{
597
0
    CK_RV crv;
598
599
0
    if (mod->functionList == NULL)
600
0
        return SECFailure;
601
0
    crv = PK11_GETTAB(mod)->C_GetInfo(info);
602
0
    if (crv != CKR_OK) {
603
0
        PORT_SetError(PK11_MapError(crv));
604
0
    }
605
0
    return (crv == CKR_OK) ? SECSuccess : SECFailure;
606
0
}
607
608
char *
609
PK11_GetModuleURI(SECMODModule *mod)
610
0
{
611
0
    CK_INFO info;
612
0
    PK11URI *uri;
613
0
    char *ret = NULL;
614
0
    PK11URIAttribute attrs[3];
615
0
    size_t nattrs = 0;
616
0
    char libraryManufacturer[32 + 1], libraryDescription[32 + 1], libraryVersion[8];
617
618
0
    if (PK11_GetModInfo(mod, &info) == SECFailure) {
619
0
        return NULL;
620
0
    }
621
622
0
    PK11_MakeString(NULL, libraryManufacturer, (char *)info.manufacturerID,
623
0
                    sizeof(info.manufacturerID));
624
0
    if (*libraryManufacturer != '\0') {
625
0
        attrs[nattrs].name = PK11URI_PATTR_LIBRARY_MANUFACTURER;
626
0
        attrs[nattrs].value = libraryManufacturer;
627
0
        nattrs++;
628
0
    }
629
630
0
    PK11_MakeString(NULL, libraryDescription, (char *)info.libraryDescription,
631
0
                    sizeof(info.libraryDescription));
632
0
    if (*libraryDescription != '\0') {
633
0
        attrs[nattrs].name = PK11URI_PATTR_LIBRARY_DESCRIPTION;
634
0
        attrs[nattrs].value = libraryDescription;
635
0
        nattrs++;
636
0
    }
637
638
0
    PR_snprintf(libraryVersion, sizeof(libraryVersion), "%d.%d",
639
0
                info.libraryVersion.major, info.libraryVersion.minor);
640
0
    attrs[nattrs].name = PK11URI_PATTR_LIBRARY_VERSION;
641
0
    attrs[nattrs].value = libraryVersion;
642
0
    nattrs++;
643
644
0
    uri = PK11URI_CreateURI(attrs, nattrs, NULL, 0);
645
0
    if (uri == NULL) {
646
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
647
0
        return NULL;
648
0
    }
649
650
0
    ret = PK11URI_FormatURI(NULL, uri);
651
0
    PK11URI_DestroyURI(uri);
652
0
    if (ret == NULL) {
653
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
654
0
        return NULL;
655
0
    }
656
657
0
    return ret;
658
0
}
659
660
/* Determine if we have the FIP's module loaded as the default
661
 * module to trigger other bogus FIPS requirements in PKCS #12 and
662
 * SSL
663
 */
664
PRBool
665
PK11_IsFIPS(void)
666
0
{
667
0
    SECMODModule *mod = SECMOD_GetInternalModule();
668
669
0
    if (mod && mod->internal) {
670
0
        return mod->isFIPS;
671
0
    }
672
673
0
    return PR_FALSE;
674
0
}
675
676
/* combines NewModule() & AddModule */
677
/* give a string for the module name & the full-path for the dll, */
678
/* installs the PKCS11 module & update registry */
679
SECStatus
680
SECMOD_AddNewModuleEx(const char *moduleName, const char *dllPath,
681
                      unsigned long defaultMechanismFlags,
682
                      unsigned long cipherEnableFlags,
683
                      char *modparms, char *nssparms)
684
0
{
685
0
    SECMODModule *module;
686
0
    SECStatus result = SECFailure;
687
0
    int s, i;
688
0
    PK11SlotInfo *slot;
689
690
0
    PR_SetErrorText(0, NULL);
691
0
    if (!moduleLock) {
692
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
693
0
        return result;
694
0
    }
695
696
0
    module = SECMOD_CreateModule(dllPath, moduleName, modparms, nssparms);
697
698
0
    if (module == NULL) {
699
0
        return result;
700
0
    }
701
702
0
    if (module->dllName != NULL) {
703
0
        if (module->dllName[0] != 0) {
704
0
            result = SECMOD_AddModule(module);
705
0
            if (result == SECSuccess) {
706
                /* turn on SSL cipher enable flags */
707
0
                module->ssl[0] = cipherEnableFlags;
708
709
0
                SECMOD_GetReadLock(moduleLock);
710
                /* check each slot to turn on appropriate mechanisms */
711
0
                for (s = 0; s < module->slotCount; s++) {
712
0
                    slot = (module->slots)[s];
713
                    /* for each possible mechanism */
714
0
                    for (i = 0; i < num_pk11_default_mechanisms; i++) {
715
                        /* we are told to turn it on by default ? */
716
0
                        PRBool add =
717
0
                            (PK11_DefaultArray[i].flag & defaultMechanismFlags) ? PR_TRUE : PR_FALSE;
718
0
                        result = PK11_UpdateSlotAttribute(slot,
719
0
                                                          &(PK11_DefaultArray[i]), add);
720
0
                        if (result != SECSuccess) {
721
0
                            SECMOD_ReleaseReadLock(moduleLock);
722
0
                            SECMOD_DestroyModule(module);
723
0
                            return result;
724
0
                        }
725
0
                    } /* for each mechanism */
726
                    /* disable each slot if the defaultFlags say so */
727
0
                    if (defaultMechanismFlags & PK11_DISABLE_FLAG) {
728
0
                        PK11_UserDisableSlot(slot);
729
0
                    }
730
0
                } /* for each slot of this module */
731
0
                SECMOD_ReleaseReadLock(moduleLock);
732
733
                /* delete and re-add module in order to save changes
734
                 * to the module */
735
0
                result = SECMOD_UpdateModule(module);
736
0
            }
737
0
        }
738
0
    }
739
0
    SECMOD_DestroyModule(module);
740
0
    return result;
741
0
}
742
743
SECStatus
744
SECMOD_AddNewModule(const char *moduleName, const char *dllPath,
745
                    unsigned long defaultMechanismFlags,
746
                    unsigned long cipherEnableFlags)
747
0
{
748
0
    return SECMOD_AddNewModuleEx(moduleName, dllPath, defaultMechanismFlags,
749
0
                                 cipherEnableFlags,
750
0
                                 NULL, NULL); /* don't pass module or nss params */
751
0
}
752
753
SECStatus
754
SECMOD_UpdateModule(SECMODModule *module)
755
0
{
756
0
    SECStatus result;
757
758
0
    result = SECMOD_DeletePermDB(module);
759
760
0
    if (result == SECSuccess) {
761
0
        result = SECMOD_AddPermDB(module);
762
0
    }
763
0
    return result;
764
0
}
765
766
/* Public & Internal(Security Library)  representation of
767
 * encryption mechanism flags conversion */
768
769
/* Currently, the only difference is that internal representation
770
 * puts RANDOM_FLAG at bit 31 (Most-significant bit), but
771
 * public representation puts this bit at bit 28
772
 */
773
unsigned long
774
SECMOD_PubMechFlagstoInternal(unsigned long publicFlags)
775
0
{
776
0
    unsigned long internalFlags = publicFlags;
777
778
0
    if (publicFlags & PUBLIC_MECH_RANDOM_FLAG) {
779
0
        internalFlags &= ~PUBLIC_MECH_RANDOM_FLAG;
780
0
        internalFlags |= SECMOD_RANDOM_FLAG;
781
0
    }
782
0
    return internalFlags;
783
0
}
784
785
unsigned long
786
SECMOD_InternaltoPubMechFlags(unsigned long internalFlags)
787
0
{
788
0
    unsigned long publicFlags = internalFlags;
789
790
0
    if (internalFlags & SECMOD_RANDOM_FLAG) {
791
0
        publicFlags &= ~SECMOD_RANDOM_FLAG;
792
0
        publicFlags |= PUBLIC_MECH_RANDOM_FLAG;
793
0
    }
794
0
    return publicFlags;
795
0
}
796
797
/* Public & Internal(Security Library)  representation of */
798
/* cipher flags conversion */
799
/* Note: currently they are just stubs */
800
unsigned long
801
SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags)
802
0
{
803
0
    return publicFlags;
804
0
}
805
806
unsigned long
807
SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags)
808
0
{
809
0
    return internalFlags;
810
0
}
811
812
/* Funtion reports true if module of modType is installed/configured */
813
PRBool
814
SECMOD_IsModulePresent(unsigned long int pubCipherEnableFlags)
815
0
{
816
0
    PRBool result = PR_FALSE;
817
0
    SECMODModuleList *mods;
818
819
0
    if (!moduleLock) {
820
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
821
0
        return result;
822
0
    }
823
0
    SECMOD_GetReadLock(moduleLock);
824
0
    mods = SECMOD_GetDefaultModuleList();
825
0
    for (; mods != NULL; mods = mods->next) {
826
0
        if (mods->module->ssl[0] &
827
0
            SECMOD_PubCipherFlagstoInternal(pubCipherEnableFlags)) {
828
0
            result = PR_TRUE;
829
0
        }
830
0
    }
831
832
0
    SECMOD_ReleaseReadLock(moduleLock);
833
0
    return result;
834
0
}
835
836
/* create a new ModuleListElement */
837
SECMODModuleList *
838
SECMOD_NewModuleListElement(void)
839
4
{
840
4
    SECMODModuleList *newModList;
841
842
4
    newModList = (SECMODModuleList *)PORT_Alloc(sizeof(SECMODModuleList));
843
4
    if (newModList) {
844
4
        newModList->next = NULL;
845
4
        newModList->module = NULL;
846
4
    }
847
4
    return newModList;
848
4
}
849
850
/*
851
 * make a new reference to a module so It doesn't go away on us
852
 */
853
SECMODModule *
854
SECMOD_ReferenceModule(SECMODModule *module)
855
10
{
856
10
    PZ_Lock(module->refLock);
857
10
    PORT_Assert(module->refCount > 0);
858
859
10
    module->refCount++;
860
10
    PZ_Unlock(module->refLock);
861
10
    return module;
862
10
}
863
864
/* destroy an existing module */
865
void
866
SECMOD_DestroyModule(SECMODModule *module)
867
4
{
868
4
    PRBool willfree = PR_FALSE;
869
4
    int slotCount;
870
4
    int i;
871
872
4
    PZ_Lock(module->refLock);
873
4
    if (module->refCount-- == 1) {
874
0
        willfree = PR_TRUE;
875
0
    }
876
4
    PORT_Assert(willfree || (module->refCount > 0));
877
4
    PZ_Unlock(module->refLock);
878
879
4
    if (!willfree) {
880
4
        return;
881
4
    }
882
883
0
    if (module->parent != NULL) {
884
0
        SECMODModule *parent = module->parent;
885
        /* paranoia, don't loop forever if the modules are looped */
886
0
        module->parent = NULL;
887
0
        SECMOD_DestroyModule(parent);
888
0
    }
889
890
    /* slots can't really disappear until our module starts freeing them,
891
     * so this check is safe */
892
0
    slotCount = module->slotCount;
893
0
    if (slotCount == 0) {
894
0
        SECMOD_SlotDestroyModule(module, PR_FALSE);
895
0
        return;
896
0
    }
897
898
    /* now free all out slots, when they are done, they will cause the
899
     * module to disappear altogether */
900
0
    for (i = 0; i < slotCount; i++) {
901
0
        if (!module->slots[i]->disabled) {
902
0
            PK11_ClearSlotList(module->slots[i]);
903
0
        }
904
0
        PK11_FreeSlot(module->slots[i]);
905
0
    }
906
    /* WARNING: once the last slot has been freed is it possible (even likely)
907
     * that module is no more... touching it now is a good way to go south */
908
0
}
909
910
/* we can only get here if we've destroyed the module, or some one has
911
 * erroneously freed a slot that wasn't referenced. */
912
void
913
SECMOD_SlotDestroyModule(SECMODModule *module, PRBool fromSlot)
914
0
{
915
0
    PRBool willfree = PR_FALSE;
916
0
    if (fromSlot) {
917
0
        PORT_Assert(module->refCount == 0);
918
0
        PZ_Lock(module->refLock);
919
0
        if (module->slotCount-- == 1) {
920
0
            willfree = PR_TRUE;
921
0
        }
922
0
        PORT_Assert(willfree || (module->slotCount > 0));
923
0
        PZ_Unlock(module->refLock);
924
0
        if (!willfree)
925
0
            return;
926
0
    }
927
928
0
    if (module == pendingModule) {
929
0
        pendingModule = NULL;
930
0
    }
931
932
0
    if (module->loaded) {
933
0
        SECMOD_UnloadModule(module);
934
0
    }
935
0
    PZ_DestroyLock(module->refLock);
936
0
    PORT_FreeArena(module->arena, PR_FALSE);
937
0
    secmod_PrivateModuleCount--;
938
0
}
939
940
/* destroy a list element
941
 * this destroys a single element, and returns the next element
942
 * on the chain. It makes it easy to implement for loops to delete
943
 * the chain. It also make deleting a single element easy */
944
SECMODModuleList *
945
SECMOD_DestroyModuleListElement(SECMODModuleList *element)
946
0
{
947
0
    SECMODModuleList *next = element->next;
948
949
0
    if (element->module) {
950
0
        SECMOD_DestroyModule(element->module);
951
0
        element->module = NULL;
952
0
    }
953
0
    PORT_Free(element);
954
0
    return next;
955
0
}
956
957
/*
958
 * Destroy an entire module list
959
 */
960
void
961
SECMOD_DestroyModuleList(SECMODModuleList *list)
962
0
{
963
0
    SECMODModuleList *lp;
964
965
0
    for (lp = list; lp != NULL; lp = SECMOD_DestroyModuleListElement(lp))
966
0
        ;
967
0
}
968
969
PRBool
970
SECMOD_CanDeleteInternalModule(void)
971
0
{
972
#ifdef NSS_FIPS_DISABLED
973
    return PR_FALSE;
974
#else
975
0
    return (PRBool)((pendingModule == NULL) && !SECMOD_GetSystemFIPSEnabled());
976
0
#endif
977
0
}
978
979
/*
980
 * check to see if the module has added new slots. PKCS 11 v2.20 allows for
981
 * modules to add new slots, but never remove them. Slots cannot be added
982
 * between a call to C_GetSlotLlist(Flag, NULL, &count) and the subsequent
983
 * C_GetSlotList(flag, &data, &count) so that the array doesn't accidently
984
 * grow on the caller. It is permissible for the slots to increase between
985
 * successive calls with NULL to get the size.
986
 *
987
 * Caller must not hold a module list read lock.
988
 */
989
SECStatus
990
SECMOD_UpdateSlotList(SECMODModule *mod)
991
0
{
992
0
    CK_RV crv;
993
0
    CK_ULONG count;
994
0
    CK_ULONG i, oldCount;
995
0
    PRBool freeRef = PR_FALSE;
996
0
    void *mark = NULL;
997
0
    CK_ULONG *slotIDs = NULL;
998
0
    PK11SlotInfo **newSlots = NULL;
999
0
    PK11SlotInfo **oldSlots = NULL;
1000
1001
0
    if (!moduleLock) {
1002
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1003
0
        return SECFailure;
1004
0
    }
1005
1006
    /* C_GetSlotList is not a session function, make sure
1007
     * calls are serialized */
1008
0
    PZ_Lock(mod->refLock);
1009
0
    freeRef = PR_TRUE;
1010
    /* see if the number of slots have changed */
1011
0
    crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, NULL, &count);
1012
0
    if (crv != CKR_OK) {
1013
0
        PORT_SetError(PK11_MapError(crv));
1014
0
        goto loser;
1015
0
    }
1016
    /* nothing new, blow out early, we want this function to be quick
1017
     * and cheap in the normal case  */
1018
0
    if (count == mod->slotCount) {
1019
0
        PZ_Unlock(mod->refLock);
1020
0
        return SECSuccess;
1021
0
    }
1022
0
    if (count < (CK_ULONG)mod->slotCount) {
1023
        /* shouldn't happen with a properly functioning PKCS #11 module */
1024
0
        PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
1025
0
        goto loser;
1026
0
    }
1027
1028
    /* get the new slot list */
1029
0
    slotIDs = PORT_NewArray(CK_SLOT_ID, count);
1030
0
    if (slotIDs == NULL) {
1031
0
        goto loser;
1032
0
    }
1033
1034
0
    crv = PK11_GETTAB(mod)->C_GetSlotList(PR_FALSE, slotIDs, &count);
1035
0
    if (crv != CKR_OK) {
1036
0
        PORT_SetError(PK11_MapError(crv));
1037
0
        goto loser;
1038
0
    }
1039
0
    freeRef = PR_FALSE;
1040
0
    PZ_Unlock(mod->refLock);
1041
0
    mark = PORT_ArenaMark(mod->arena);
1042
0
    if (mark == NULL) {
1043
0
        goto loser;
1044
0
    }
1045
0
    newSlots = PORT_ArenaZNewArray(mod->arena, PK11SlotInfo *, count);
1046
1047
    /* walk down the new slot ID list returned from the module. We keep
1048
     * the old slots which match a returned ID, and we initialize the new
1049
     * slots. */
1050
0
    for (i = 0; i < count; i++) {
1051
0
        PK11SlotInfo *slot = SECMOD_FindSlotByID(mod, slotIDs[i]);
1052
1053
0
        if (!slot) {
1054
            /* we have a new slot create a new slot data structure */
1055
0
            slot = PK11_NewSlotInfo(mod);
1056
0
            if (!slot) {
1057
0
                goto loser;
1058
0
            }
1059
0
            PK11_InitSlot(mod, slotIDs[i], slot);
1060
0
            STAN_InitTokenForSlotInfo(NULL, slot);
1061
0
        }
1062
0
        newSlots[i] = slot;
1063
0
    }
1064
0
    STAN_ResetTokenInterator(NULL);
1065
0
    PORT_Free(slotIDs);
1066
0
    slotIDs = NULL;
1067
0
    PORT_ArenaUnmark(mod->arena, mark);
1068
1069
    /* until this point we're still using the old slot list. Now we update
1070
     * module slot list. We update the slots (array) first then the count,
1071
     * since we've already guarrenteed that count has increased (just in case
1072
     * someone is looking at the slots field of  module without holding the
1073
     * moduleLock */
1074
0
    SECMOD_GetWriteLock(moduleLock);
1075
0
    oldCount = mod->slotCount;
1076
0
    oldSlots = mod->slots;
1077
0
    mod->slots = newSlots; /* typical arena 'leak'... old mod->slots is
1078
                            * allocated out of the module arena and won't
1079
                            * be freed until the module is freed */
1080
0
    mod->slotCount = count;
1081
0
    SECMOD_ReleaseWriteLock(moduleLock);
1082
    /* free our old references before forgetting about oldSlot*/
1083
0
    for (i = 0; i < oldCount; i++) {
1084
0
        PK11_FreeSlot(oldSlots[i]);
1085
0
    }
1086
0
    return SECSuccess;
1087
1088
0
loser:
1089
0
    if (freeRef) {
1090
0
        PZ_Unlock(mod->refLock);
1091
0
    }
1092
0
    if (slotIDs) {
1093
0
        PORT_Free(slotIDs);
1094
0
    }
1095
    /* free all the slots we allocated. newSlots are part of the
1096
     * mod arena. NOTE: the newSlots array contain both new and old
1097
     * slots, but we kept a reference to the old slots when we built the new
1098
     * array, so we need to free all the slots in newSlots array. */
1099
0
    if (newSlots) {
1100
0
        for (i = 0; i < count; i++) {
1101
0
            if (newSlots[i] == NULL) {
1102
0
                break; /* hit the last one */
1103
0
            }
1104
0
            PK11_FreeSlot(newSlots[i]);
1105
0
        }
1106
0
    }
1107
    /* must come after freeing newSlots */
1108
0
    if (mark) {
1109
0
        PORT_ArenaRelease(mod->arena, mark);
1110
0
    }
1111
0
    return SECFailure;
1112
0
}
1113
1114
/*
1115
 * this handles modules that do not support C_WaitForSlotEvent().
1116
 * The internal flags are stored. Note that C_WaitForSlotEvent() does not
1117
 * have a timeout, so we don't have one for handleWaitForSlotEvent() either.
1118
 */
1119
PK11SlotInfo *
1120
secmod_HandleWaitForSlotEvent(SECMODModule *mod, unsigned long flags,
1121
                              PRIntervalTime latency)
1122
0
{
1123
0
    PRBool removableSlotsFound = PR_FALSE;
1124
0
    int i;
1125
0
    int error = SEC_ERROR_NO_EVENT;
1126
1127
0
    if (!moduleLock) {
1128
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1129
0
        return NULL;
1130
0
    }
1131
0
    PZ_Lock(mod->refLock);
1132
0
    if (mod->evControlMask & SECMOD_END_WAIT) {
1133
0
        mod->evControlMask &= ~SECMOD_END_WAIT;
1134
0
        PZ_Unlock(mod->refLock);
1135
0
        PORT_SetError(SEC_ERROR_NO_EVENT);
1136
0
        return NULL;
1137
0
    }
1138
0
    mod->evControlMask |= SECMOD_WAIT_SIMULATED_EVENT;
1139
0
    while (mod->evControlMask & SECMOD_WAIT_SIMULATED_EVENT) {
1140
0
        PZ_Unlock(mod->refLock);
1141
        /* now is a good time to see if new slots have been added */
1142
0
        SECMOD_UpdateSlotList(mod);
1143
1144
        /* loop through all the slots on a module */
1145
0
        SECMOD_GetReadLock(moduleLock);
1146
0
        for (i = 0; i < mod->slotCount; i++) {
1147
0
            PK11SlotInfo *slot = mod->slots[i];
1148
0
            PRUint16 series;
1149
0
            PRBool present;
1150
1151
            /* perm modules do not change */
1152
0
            if (slot->isPerm) {
1153
0
                continue;
1154
0
            }
1155
0
            removableSlotsFound = PR_TRUE;
1156
            /* simulate the PKCS #11 module flags. are the flags different
1157
             * from the last time we called? */
1158
0
            series = slot->series;
1159
0
            present = PK11_IsPresent(slot);
1160
0
            if ((slot->flagSeries != series) || (slot->flagState != present)) {
1161
0
                slot->flagState = present;
1162
0
                slot->flagSeries = series;
1163
0
                SECMOD_ReleaseReadLock(moduleLock);
1164
0
                PZ_Lock(mod->refLock);
1165
0
                mod->evControlMask &= ~SECMOD_END_WAIT;
1166
0
                PZ_Unlock(mod->refLock);
1167
0
                return PK11_ReferenceSlot(slot);
1168
0
            }
1169
0
        }
1170
0
        SECMOD_ReleaseReadLock(moduleLock);
1171
        /* if everything was perm modules, don't lock up forever */
1172
0
        if ((mod->slotCount != 0) && !removableSlotsFound) {
1173
0
            error = SEC_ERROR_NO_SLOT_SELECTED;
1174
0
            PZ_Lock(mod->refLock);
1175
0
            break;
1176
0
        }
1177
0
        if (flags & CKF_DONT_BLOCK) {
1178
0
            PZ_Lock(mod->refLock);
1179
0
            break;
1180
0
        }
1181
0
        PR_Sleep(latency);
1182
0
        PZ_Lock(mod->refLock);
1183
0
    }
1184
0
    mod->evControlMask &= ~SECMOD_END_WAIT;
1185
0
    PZ_Unlock(mod->refLock);
1186
0
    PORT_SetError(error);
1187
0
    return NULL;
1188
0
}
1189
1190
/*
1191
 * this function waits for a token event on any slot of a given module
1192
 * This function should not be called from more than one thread of the
1193
 * same process (though other threads can make other library calls
1194
 * on this module while this call is blocked).
1195
 */
1196
PK11SlotInfo *
1197
SECMOD_WaitForAnyTokenEvent(SECMODModule *mod, unsigned long flags,
1198
                            PRIntervalTime latency)
1199
0
{
1200
0
    CK_SLOT_ID id;
1201
0
    CK_RV crv;
1202
0
    PK11SlotInfo *slot;
1203
1204
0
    if (!pk11_getFinalizeModulesOption() ||
1205
0
        ((mod->cryptokiVersion.major == 2) &&
1206
0
         (mod->cryptokiVersion.minor < 1))) {
1207
        /* if we are sharing the module with other software in our
1208
         * address space, we can't reliably use C_WaitForSlotEvent(),
1209
         * and if the module is version 2.0, C_WaitForSlotEvent() doesn't
1210
         * exist */
1211
0
        return secmod_HandleWaitForSlotEvent(mod, flags, latency);
1212
0
    }
1213
    /* first the the PKCS #11 call */
1214
0
    PZ_Lock(mod->refLock);
1215
0
    if (mod->evControlMask & SECMOD_END_WAIT) {
1216
0
        goto end_wait;
1217
0
    }
1218
0
    mod->evControlMask |= SECMOD_WAIT_PKCS11_EVENT;
1219
0
    PZ_Unlock(mod->refLock);
1220
0
    crv = PK11_GETTAB(mod)->C_WaitForSlotEvent(flags, &id, NULL);
1221
0
    PZ_Lock(mod->refLock);
1222
0
    mod->evControlMask &= ~SECMOD_WAIT_PKCS11_EVENT;
1223
    /* if we are in end wait, short circuit now, don't even risk
1224
     * going into secmod_HandleWaitForSlotEvent */
1225
0
    if (mod->evControlMask & SECMOD_END_WAIT) {
1226
0
        goto end_wait;
1227
0
    }
1228
0
    PZ_Unlock(mod->refLock);
1229
0
    if (crv == CKR_FUNCTION_NOT_SUPPORTED) {
1230
        /* module doesn't support that call, simulate it */
1231
0
        return secmod_HandleWaitForSlotEvent(mod, flags, latency);
1232
0
    }
1233
0
    if (crv != CKR_OK) {
1234
        /* we can get this error if finalize was called while we were
1235
         * still running. This is the only way to force a C_WaitForSlotEvent()
1236
         * to return in PKCS #11. In this case, just return that there
1237
         * was no event. */
1238
0
        if (crv == CKR_CRYPTOKI_NOT_INITIALIZED) {
1239
0
            PORT_SetError(SEC_ERROR_NO_EVENT);
1240
0
        } else {
1241
0
            PORT_SetError(PK11_MapError(crv));
1242
0
        }
1243
0
        return NULL;
1244
0
    }
1245
0
    slot = SECMOD_FindSlotByID(mod, id);
1246
0
    if (slot == NULL) {
1247
        /* possibly a new slot that was added? */
1248
0
        SECMOD_UpdateSlotList(mod);
1249
0
        slot = SECMOD_FindSlotByID(mod, id);
1250
0
    }
1251
    /* if we are in the delay period for the "isPresent" call, reset
1252
     * the delay since we know things have probably changed... */
1253
0
    if (slot) {
1254
0
        NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1255
0
        if (nssToken) {
1256
0
            if (nssToken->slot) {
1257
0
                nssSlot_ResetDelay(nssToken->slot);
1258
0
            }
1259
0
            (void)nssToken_Destroy(nssToken);
1260
0
        }
1261
0
    }
1262
0
    return slot;
1263
1264
/* must be called with the lock on. */
1265
0
end_wait:
1266
0
    mod->evControlMask &= ~SECMOD_END_WAIT;
1267
0
    PZ_Unlock(mod->refLock);
1268
0
    PORT_SetError(SEC_ERROR_NO_EVENT);
1269
0
    return NULL;
1270
0
}
1271
1272
/*
1273
 * This function "wakes up" WaitForAnyTokenEvent. It's a pretty drastic
1274
 * function, possibly bringing down the pkcs #11 module in question. This
1275
 * should be OK because 1) it does reinitialize, and 2) it should only be
1276
 * called when we are on our way to tear the whole system down anyway.
1277
 */
1278
SECStatus
1279
SECMOD_CancelWait(SECMODModule *mod)
1280
0
{
1281
0
    unsigned long controlMask;
1282
0
    SECStatus rv = SECSuccess;
1283
0
    CK_RV crv;
1284
1285
0
    PZ_Lock(mod->refLock);
1286
0
    mod->evControlMask |= SECMOD_END_WAIT;
1287
0
    controlMask = mod->evControlMask;
1288
0
    if (controlMask & SECMOD_WAIT_PKCS11_EVENT) {
1289
0
        if (!pk11_getFinalizeModulesOption()) {
1290
            /* can't get here unless pk11_getFinalizeModulesOption is set */
1291
0
            PORT_Assert(0);
1292
0
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1293
0
            rv = SECFailure;
1294
0
            goto loser;
1295
0
        }
1296
        /* NOTE: this call will drop all transient keys, in progress
1297
         * operations, and any authentication. This is the only documented
1298
         * way to get WaitForSlotEvent to return. Also note: for non-thread
1299
         * safe tokens, we need to hold the module lock, this is not yet at
1300
         * system shutdown/startup time, so we need to protect these calls */
1301
0
        crv = PK11_GETTAB(mod)->C_Finalize(NULL);
1302
        /* ok, we slammed the module down, now we need to reinit it in case
1303
         * we intend to use it again */
1304
0
        if (CKR_OK == crv) {
1305
0
            PRBool alreadyLoaded;
1306
0
            secmod_ModuleInit(mod, NULL, &alreadyLoaded);
1307
0
        } else {
1308
            /* Finalized failed for some reason,  notify the application
1309
             * so maybe it has a prayer of recovering... */
1310
0
            PORT_SetError(PK11_MapError(crv));
1311
0
            rv = SECFailure;
1312
0
        }
1313
0
    } else if (controlMask & SECMOD_WAIT_SIMULATED_EVENT) {
1314
0
        mod->evControlMask &= ~SECMOD_WAIT_SIMULATED_EVENT;
1315
        /* Simulated events will eventually timeout
1316
         * and wake up in the loop */
1317
0
    }
1318
0
loser:
1319
0
    PZ_Unlock(mod->refLock);
1320
0
    return rv;
1321
0
}
1322
1323
/*
1324
 * check to see if the module has removable slots that we may need to
1325
 * watch for.
1326
 */
1327
PRBool
1328
SECMOD_HasRemovableSlots(SECMODModule *mod)
1329
0
{
1330
0
    PRBool ret = PR_FALSE;
1331
0
    if (!moduleLock) {
1332
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1333
0
        return ret;
1334
0
    }
1335
0
    SECMOD_GetReadLock(moduleLock);
1336
0
    ret = SECMOD_LockedModuleHasRemovableSlots(mod);
1337
0
    SECMOD_ReleaseReadLock(moduleLock);
1338
0
    return ret;
1339
0
}
1340
1341
PRBool
1342
SECMOD_LockedModuleHasRemovableSlots(SECMODModule *mod)
1343
0
{
1344
0
    int i;
1345
0
    PRBool ret;
1346
0
    if (mod->slotCount == 0) {
1347
0
        return PR_TRUE;
1348
0
    }
1349
1350
0
    ret = PR_FALSE;
1351
0
    for (i = 0; i < mod->slotCount; i++) {
1352
0
        PK11SlotInfo *slot = mod->slots[i];
1353
        /* perm modules are not inserted or removed */
1354
0
        if (slot->isPerm) {
1355
0
            continue;
1356
0
        }
1357
0
        ret = PR_TRUE;
1358
0
        break;
1359
0
    }
1360
0
    return ret;
1361
0
}
1362
1363
/*
1364
 * helper function to actually create and destroy user defined slots
1365
 */
1366
static SECStatus
1367
secmod_UserDBOp(PK11SlotInfo *slot, CK_OBJECT_CLASS objClass,
1368
                const char *sendSpec)
1369
0
{
1370
0
    CK_OBJECT_HANDLE dummy;
1371
0
    CK_ATTRIBUTE template[2];
1372
0
    CK_ATTRIBUTE *attrs = template;
1373
0
    CK_RV crv;
1374
1375
0
    PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass));
1376
0
    attrs++;
1377
0
    PK11_SETATTRS(attrs, CKA_NSS_MODULE_SPEC, (unsigned char *)sendSpec,
1378
0
                  strlen(sendSpec) + 1);
1379
0
    attrs++;
1380
1381
0
    PORT_Assert(attrs - template <= 2);
1382
1383
0
    PK11_EnterSlotMonitor(slot);
1384
0
    crv = PK11_CreateNewObject(slot, slot->session,
1385
0
                               template, attrs - template, PR_FALSE, &dummy);
1386
0
    PK11_ExitSlotMonitor(slot);
1387
1388
0
    if (crv != CKR_OK) {
1389
0
        PORT_SetError(PK11_MapError(crv));
1390
0
        return SECFailure;
1391
0
    }
1392
0
    return SECMOD_UpdateSlotList(slot->module);
1393
0
}
1394
1395
/*
1396
 * return true if the selected slot ID is not present or doesn't exist
1397
 */
1398
static PRBool
1399
secmod_SlotIsEmpty(SECMODModule *mod, CK_SLOT_ID slotID)
1400
0
{
1401
0
    PK11SlotInfo *slot = SECMOD_LookupSlot(mod->moduleID, slotID);
1402
0
    if (slot) {
1403
0
        PRBool present = PK11_IsPresent(slot);
1404
0
        PK11_FreeSlot(slot);
1405
0
        if (present) {
1406
0
            return PR_FALSE;
1407
0
        }
1408
0
    }
1409
    /* it doesn't exist or isn't present, it's available */
1410
0
    return PR_TRUE;
1411
0
}
1412
1413
/*
1414
 * Find an unused slot id in module.
1415
 */
1416
static CK_SLOT_ID
1417
secmod_FindFreeSlot(SECMODModule *mod)
1418
0
{
1419
0
    CK_SLOT_ID i, minSlotID, maxSlotID;
1420
1421
    /* look for a free slot id on the internal module */
1422
0
    if (mod->internal && mod->isFIPS) {
1423
0
        minSlotID = SFTK_MIN_FIPS_USER_SLOT_ID;
1424
0
        maxSlotID = SFTK_MAX_FIPS_USER_SLOT_ID;
1425
0
    } else {
1426
0
        minSlotID = SFTK_MIN_USER_SLOT_ID;
1427
0
        maxSlotID = SFTK_MAX_USER_SLOT_ID;
1428
0
    }
1429
0
    for (i = minSlotID; i < maxSlotID; i++) {
1430
0
        if (secmod_SlotIsEmpty(mod, i)) {
1431
0
            return i;
1432
0
        }
1433
0
    }
1434
0
    PORT_SetError(SEC_ERROR_NO_SLOT_SELECTED);
1435
0
    return (CK_SLOT_ID)-1;
1436
0
}
1437
1438
/*
1439
 * Attempt to open a new slot.
1440
 *
1441
 * This works the same os OpenUserDB except it can be called against
1442
 * any module that understands the softoken protocol for opening new
1443
 * slots, not just the softoken itself. If the selected module does not
1444
 * understand the protocol, C_CreateObject will fail with
1445
 * CKR_INVALID_ATTRIBUTE, and SECMOD_OpenNewSlot will return NULL and set
1446
 * SEC_ERROR_BAD_DATA.
1447
 *
1448
 * NewSlots can be closed with SECMOD_CloseUserDB();
1449
 *
1450
 * Modulespec is module dependent.
1451
 */
1452
PK11SlotInfo *
1453
SECMOD_OpenNewSlot(SECMODModule *mod, const char *moduleSpec)
1454
0
{
1455
0
    CK_SLOT_ID slotID = 0;
1456
0
    PK11SlotInfo *slot;
1457
0
    char *escSpec;
1458
0
    char *sendSpec;
1459
0
    SECStatus rv;
1460
1461
0
    slotID = secmod_FindFreeSlot(mod);
1462
0
    if (slotID == (CK_SLOT_ID)-1) {
1463
0
        return NULL;
1464
0
    }
1465
1466
0
    if (mod->slotCount == 0) {
1467
0
        return NULL;
1468
0
    }
1469
1470
    /* just grab the first slot in the module, any present slot should work */
1471
0
    slot = PK11_ReferenceSlot(mod->slots[0]);
1472
0
    if (slot == NULL) {
1473
0
        return NULL;
1474
0
    }
1475
1476
    /* we've found the slot, now build the moduleSpec */
1477
0
    escSpec = NSSUTIL_DoubleEscape(moduleSpec, '>', ']');
1478
0
    if (escSpec == NULL) {
1479
0
        PK11_FreeSlot(slot);
1480
0
        return NULL;
1481
0
    }
1482
0
    sendSpec = PR_smprintf("tokens=[0x%x=<%s>]", slotID, escSpec);
1483
0
    PORT_Free(escSpec);
1484
1485
0
    if (sendSpec == NULL) {
1486
        /* PR_smprintf does not set SEC_ERROR_NO_MEMORY on failure. */
1487
0
        PK11_FreeSlot(slot);
1488
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
1489
0
        return NULL;
1490
0
    }
1491
0
    rv = secmod_UserDBOp(slot, CKO_NSS_NEWSLOT, sendSpec);
1492
0
    PR_smprintf_free(sendSpec);
1493
0
    PK11_FreeSlot(slot);
1494
0
    if (rv != SECSuccess) {
1495
0
        return NULL;
1496
0
    }
1497
1498
0
    slot = SECMOD_FindSlotByID(mod, slotID);
1499
0
    if (slot) {
1500
        /* if we are in the delay period for the "isPresent" call, reset
1501
         * the delay since we know things have probably changed... */
1502
0
        NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1503
0
        if (nssToken) {
1504
0
            if (nssToken->slot) {
1505
0
                nssSlot_ResetDelay(nssToken->slot);
1506
0
            }
1507
0
            (void)nssToken_Destroy(nssToken);
1508
0
        }
1509
        /* force the slot info structures to properly reset */
1510
0
        (void)PK11_IsPresent(slot);
1511
0
    }
1512
0
    return slot;
1513
0
}
1514
1515
/*
1516
 * given a module spec, find the slot in the module for it.
1517
 */
1518
PK11SlotInfo *
1519
secmod_FindSlotFromModuleSpec(const char *moduleSpec, SECMODModule *module)
1520
0
{
1521
0
    CK_SLOT_ID slot_id = secmod_GetSlotIDFromModuleSpec(moduleSpec, module);
1522
0
    if (slot_id == -1) {
1523
0
        return NULL;
1524
0
    }
1525
1526
0
    return SECMOD_FindSlotByID(module, slot_id);
1527
0
}
1528
1529
/*
1530
 * Open a new database using the softoken. The caller is responsible for making
1531
 * sure the module spec is correct and usable. The caller should ask for one
1532
 * new database per call if the caller wants to get meaningful information
1533
 * about the new database.
1534
 *
1535
 * moduleSpec is the same data that you would pass to softoken at
1536
 * initialization time under the 'tokens' options. For example, if you were
1537
 * to specify tokens=<0x4=[configdir='./mybackup' tokenDescription='Backup']>
1538
 * You would specify "configdir='./mybackup' tokenDescription='Backup'" as your
1539
 * module spec here. The slot ID will be calculated for you by
1540
 * SECMOD_OpenUserDB().
1541
 *
1542
 * Typical parameters here are configdir, tokenDescription and flags.
1543
 *
1544
 * a Full list is below:
1545
 *
1546
 *
1547
 *  configDir - The location of the databases for this token. If configDir is
1548
 *         not specified, and noCertDB and noKeyDB is not specified, the load
1549
 *         will fail.
1550
 *   certPrefix - Cert prefix for this token.
1551
 *   keyPrefix - Prefix for the key database for this token. (if not specified,
1552
 *         certPrefix will be used).
1553
 *   tokenDescription - The label value for this token returned in the
1554
 *         CK_TOKEN_INFO structure with an internationalize string (UTF8).
1555
 *         This value will be truncated at 32 bytes (no NULL, partial UTF8
1556
 *         characters dropped). You should specify a user friendly name here
1557
 *         as this is the value the token will be referred to in most
1558
 *         application UI's. You should make sure tokenDescription is unique.
1559
 *   slotDescription - The slotDescription value for this token returned
1560
 *         in the CK_SLOT_INFO structure with an internationalize string
1561
 *         (UTF8). This value will be truncated at 64 bytes (no NULL, partial
1562
 *         UTF8 characters dropped). This name will not change after the
1563
 *         database is closed. It should have some number to make this unique.
1564
 *   minPWLen - minimum password length for this token.
1565
 *   flags - comma separated list of flag values, parsed case-insensitive.
1566
 *         Valid flags are:
1567
 *              readOnly - Databases should be opened read only.
1568
 *              noCertDB - Don't try to open a certificate database.
1569
 *              noKeyDB - Don't try to open a key database.
1570
 *              forceOpen - Don't fail to initialize the token if the
1571
 *                databases could not be opened.
1572
 *              passwordRequired - zero length passwords are not acceptable
1573
 *                (valid only if there is a keyDB).
1574
 *              optimizeSpace - allocate smaller hash tables and lock tables.
1575
 *                When this flag is not specified, Softoken will allocate
1576
 *                large tables to prevent lock contention.
1577
 */
1578
PK11SlotInfo *
1579
SECMOD_OpenUserDB(const char *moduleSpec)
1580
0
{
1581
0
    SECMODModule *mod;
1582
0
    SECMODConfigList *conflist = NULL;
1583
0
    int count = 0;
1584
1585
0
    if (moduleSpec == NULL) {
1586
0
        return NULL;
1587
0
    }
1588
1589
    /* NOTE: unlike most PK11 function, this does not return a reference
1590
     * to the module */
1591
0
    mod = SECMOD_GetInternalModule();
1592
0
    if (!mod) {
1593
        /* shouldn't happen */
1594
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1595
0
        return NULL;
1596
0
    }
1597
1598
    /* make sure we don't open the same database twice. We only understand
1599
     * the moduleSpec for internal databases well enough to do this, so only
1600
     * do this in OpenUserDB */
1601
0
    conflist = secmod_GetConfigList(mod->isFIPS, mod->libraryParams, &count);
1602
0
    if (conflist) {
1603
0
        PK11SlotInfo *slot = NULL;
1604
0
        if (secmod_MatchConfigList(moduleSpec, conflist, count)) {
1605
0
            slot = secmod_FindSlotFromModuleSpec(moduleSpec, mod);
1606
0
        }
1607
0
        secmod_FreeConfigList(conflist, count);
1608
0
        if (slot) {
1609
0
            return slot;
1610
0
        }
1611
0
    }
1612
0
    return SECMOD_OpenNewSlot(mod, moduleSpec);
1613
0
}
1614
1615
/*
1616
 * close an already opened user database. NOTE: the database must be
1617
 * in the internal token, and must be one created with SECMOD_OpenUserDB().
1618
 * Once the database is closed, the slot will remain as an empty slot
1619
 * until it's used again with SECMOD_OpenUserDB() or SECMOD_OpenNewSlot().
1620
 */
1621
SECStatus
1622
SECMOD_CloseUserDB(PK11SlotInfo *slot)
1623
0
{
1624
0
    SECStatus rv;
1625
0
    char *sendSpec;
1626
1627
0
    sendSpec = PR_smprintf("tokens=[0x%x=<>]", slot->slotID);
1628
0
    if (sendSpec == NULL) {
1629
        /* PR_smprintf does not set no memory error */
1630
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
1631
0
        return SECFailure;
1632
0
    }
1633
0
    rv = secmod_UserDBOp(slot, CKO_NSS_DELSLOT, sendSpec);
1634
0
    PR_smprintf_free(sendSpec);
1635
    /* if we are in the delay period for the "isPresent" call, reset
1636
     * the delay since we know things have probably changed... */
1637
0
    NSSToken *nssToken = PK11Slot_GetNSSToken(slot);
1638
0
    if (nssToken) {
1639
0
        if (nssToken->slot) {
1640
0
            nssSlot_ResetDelay(nssToken->slot);
1641
0
        }
1642
0
        (void)nssToken_Destroy(nssToken);
1643
        /* force the slot info structures to properly reset */
1644
0
        (void)PK11_IsPresent(slot);
1645
0
    }
1646
0
    return rv;
1647
0
}
1648
1649
/*
1650
 * Restart PKCS #11 modules after a fork(). See secmod.h for more information.
1651
 */
1652
SECStatus
1653
SECMOD_RestartModules(PRBool force)
1654
0
{
1655
0
    SECMODModuleList *mlp;
1656
0
    SECStatus rrv = SECSuccess;
1657
0
    int lastError = 0;
1658
1659
0
    if (!moduleLock) {
1660
0
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
1661
0
        return SECFailure;
1662
0
    }
1663
1664
    /* Only need to restart the PKCS #11 modules that were initialized */
1665
0
    SECMOD_GetReadLock(moduleLock);
1666
0
    for (mlp = modules; mlp != NULL; mlp = mlp->next) {
1667
0
        SECMODModule *mod = mlp->module;
1668
0
        CK_ULONG count;
1669
0
        SECStatus rv;
1670
0
        int i;
1671
1672
        /* If the module needs to be reset, do so */
1673
0
        if (force || (PK11_GETTAB(mod)->C_GetSlotList(CK_FALSE, NULL, &count) != CKR_OK)) {
1674
0
            PRBool alreadyLoaded;
1675
            /* first call Finalize. This is not required by PKCS #11, but some
1676
             * older modules require it, and it doesn't hurt (compliant modules
1677
             * will return CKR_NOT_INITIALIZED */
1678
0
            (void)PK11_GETTAB(mod)->C_Finalize(NULL);
1679
            /* now initialize the module, this function reinitializes
1680
             * a module in place, preserving existing slots (even if they
1681
             * no longer exist) */
1682
0
            rv = secmod_ModuleInit(mod, NULL, &alreadyLoaded);
1683
0
            if (rv != SECSuccess) {
1684
                /* save the last error code */
1685
0
                lastError = PORT_GetError();
1686
0
                rrv = rv;
1687
                /* couldn't reinit the module, disable all its slots */
1688
0
                for (i = 0; i < mod->slotCount; i++) {
1689
0
                    mod->slots[i]->disabled = PR_TRUE;
1690
0
                    mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1691
0
                }
1692
0
                continue;
1693
0
            }
1694
0
            for (i = 0; i < mod->slotCount; i++) {
1695
                /* get new token sessions, bump the series up so that
1696
                 * we refresh other old sessions. This will tell much of
1697
                 * NSS to flush cached handles it may hold as well */
1698
0
                rv = PK11_InitToken(mod->slots[i], PR_TRUE);
1699
                /* PK11_InitToken could fail if the slot isn't present.
1700
                 * If it is present, though, something is wrong and we should
1701
                 * disable the slot and let the caller know. */
1702
0
                if (rv != SECSuccess && PK11_IsPresent(mod->slots[i])) {
1703
                    /* save the last error code */
1704
0
                    lastError = PORT_GetError();
1705
0
                    rrv = rv;
1706
                    /* disable the token */
1707
0
                    mod->slots[i]->disabled = PR_TRUE;
1708
0
                    mod->slots[i]->reason = PK11_DIS_COULD_NOT_INIT_TOKEN;
1709
0
                }
1710
0
            }
1711
0
        }
1712
0
    }
1713
0
    SECMOD_ReleaseReadLock(moduleLock);
1714
1715
    /*
1716
     * on multiple failures, we are only returning the lastError. The caller
1717
     * can determine which slots are bad by calling PK11_IsDisabled().
1718
     */
1719
0
    if (rrv != SECSuccess) {
1720
        /* restore the last error code */
1721
0
        PORT_SetError(lastError);
1722
0
    }
1723
1724
0
    return rrv;
1725
0
}