Coverage Report

Created: 2018-09-25 14:53

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