~ubuntu-branches/ubuntu/feisty/firefox/feisty-security

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/nss/nssinit.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack, Alexander Sack
  • Date: 2008-06-23 15:08:12 UTC
  • mfrom: (1.1.24 upstream)
  • Revision ID: james.westby@ubuntu.com-20080623150812-sxdwhn3dz9pmapvf
Tags: 2.0.0.15+0nobinonly-0ubuntu0.7.4
[ Alexander Sack ]
* New security/stability upstream release (v2.0.0.15)
  - see USN-619-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * NSS utility functions
 
3
 *
 
4
 * ***** BEGIN LICENSE BLOCK *****
 
5
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
6
 *
 
7
 * The contents of this file are subject to the Mozilla Public License Version
 
8
 * 1.1 (the "License"); you may not use this file except in compliance with
 
9
 * the License. You may obtain a copy of the License at
 
10
 * http://www.mozilla.org/MPL/
 
11
 *
 
12
 * Software distributed under the License is distributed on an "AS IS" basis,
 
13
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
14
 * for the specific language governing rights and limitations under the
 
15
 * License.
 
16
 *
 
17
 * The Original Code is the Netscape security libraries.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Netscape Communications Corporation.
 
21
 * Portions created by the Initial Developer are Copyright (C) 1994-2000
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
28
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the MPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the MPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
/* $Id: nssinit.c,v 1.69.2.6 2006/09/21 20:09:48 julien.pierre.bugs%sun.com Exp $ */
 
40
 
 
41
#include <ctype.h>
 
42
#include "seccomon.h"
 
43
#include "prinit.h"
 
44
#include "prprf.h"
 
45
#include "prmem.h"
 
46
#include "cert.h"
 
47
#include "key.h"
 
48
#include "ssl.h"
 
49
#include "sslproto.h"
 
50
#include "secmod.h"
 
51
#include "secoid.h"
 
52
#include "nss.h"
 
53
#include "pk11func.h"
 
54
#include "secerr.h"
 
55
#include "nssbase.h"
 
56
 
 
57
#include "pki3hack.h"
 
58
#include "certi.h"
 
59
#include "secmodi.h"
 
60
#include "ocspi.h"
 
61
 
 
62
/*
 
63
 * On Windows nss3.dll needs to export the symbol 'mktemp' to be
 
64
 * fully backward compatible with the nss3.dll in NSS 3.2.x and
 
65
 * 3.3.x.  This symbol was unintentionally exported and its
 
66
 * definition (in DBM) was moved from nss3.dll to softokn3.dll
 
67
 * in NSS 3.4.  See bug 142575.
 
68
 */
 
69
#ifdef WIN32_NSS3_DLL_COMPAT
 
70
#include <io.h>
 
71
 
 
72
/* exported as 'mktemp' */
 
73
char *
 
74
nss_mktemp(char *path)
 
75
{
 
76
    return _mktemp(path);
 
77
}
 
78
#endif
 
79
 
 
80
#define NSS_MAX_FLAG_SIZE  sizeof("readOnly")+sizeof("noCertDB")+ \
 
81
        sizeof("noModDB")+sizeof("forceOpen")+sizeof("passwordRequired")+ \
 
82
        sizeof ("optimizeSpace")
 
83
#define NSS_DEFAULT_MOD_NAME "NSS Internal Module"
 
84
 
 
85
static char *
 
86
nss_makeFlags(PRBool readOnly, PRBool noCertDB, 
 
87
                                PRBool noModDB, PRBool forceOpen, 
 
88
                                PRBool passwordRequired, PRBool optimizeSpace) 
 
89
{
 
90
    char *flags = (char *)PORT_Alloc(NSS_MAX_FLAG_SIZE);
 
91
    PRBool first = PR_TRUE;
 
92
 
 
93
    PORT_Memset(flags,0,NSS_MAX_FLAG_SIZE);
 
94
    if (readOnly) {
 
95
        PORT_Strcat(flags,"readOnly");
 
96
        first = PR_FALSE;
 
97
    }
 
98
    if (noCertDB) {
 
99
        if (!first) PORT_Strcat(flags,",");
 
100
        PORT_Strcat(flags,"noCertDB");
 
101
        first = PR_FALSE;
 
102
    }
 
103
    if (noModDB) {
 
104
        if (!first) PORT_Strcat(flags,",");
 
105
        PORT_Strcat(flags,"noModDB");
 
106
        first = PR_FALSE;
 
107
    }
 
108
    if (forceOpen) {
 
109
        if (!first) PORT_Strcat(flags,",");
 
110
        PORT_Strcat(flags,"forceOpen");
 
111
        first = PR_FALSE;
 
112
    }
 
113
    if (passwordRequired) {
 
114
        if (!first) PORT_Strcat(flags,",");
 
115
        PORT_Strcat(flags,"passwordRequired");
 
116
        first = PR_FALSE;
 
117
    }
 
118
    if (optimizeSpace) {
 
119
        if (!first) PORT_Strcat(flags,",");
 
120
        PORT_Strcat(flags,"optimizeSpace");
 
121
        first = PR_FALSE;
 
122
    }
 
123
    return flags;
 
124
}
 
125
 
 
126
/*
 
127
 * statics to remember the PKCS11_ConfigurePKCS11()
 
128
 * info.
 
129
 */
 
130
static char * pk11_config_strings = NULL;
 
131
static char * pk11_config_name = NULL;
 
132
static PRBool pk11_password_required = PR_FALSE;
 
133
 
 
134
/*
 
135
 * this is a legacy configuration function which used to be part of
 
136
 * the PKCS #11 internal token.
 
137
 */
 
138
void
 
139
PK11_ConfigurePKCS11(const char *man, const char *libdes, const char *tokdes,
 
140
        const char *ptokdes, const char *slotdes, const char *pslotdes, 
 
141
        const char *fslotdes, const char *fpslotdes, int minPwd, int pwRequired)
 
142
{
 
143
   char *strings = NULL;
 
144
   char *newStrings;
 
145
 
 
146
   /* make sure the internationalization was done correctly... */
 
147
   strings = PR_smprintf("");
 
148
   if (strings == NULL) return;
 
149
 
 
150
    if (man) {
 
151
        newStrings = PR_smprintf("%s manufacturerID='%s'",strings,man);
 
152
        PR_smprintf_free(strings);
 
153
        strings = newStrings;
 
154
    }
 
155
   if (strings == NULL) return;
 
156
 
 
157
    if (libdes) {
 
158
        newStrings = PR_smprintf("%s libraryDescription='%s'",strings,libdes);
 
159
        PR_smprintf_free(strings);
 
160
        strings = newStrings;
 
161
        if (pk11_config_name != NULL) {
 
162
            PORT_Free(pk11_config_name);
 
163
        }
 
164
        pk11_config_name = PORT_Strdup(libdes);
 
165
    }
 
166
   if (strings == NULL) return;
 
167
 
 
168
    if (tokdes) {
 
169
        newStrings = PR_smprintf("%s cryptoTokenDescription='%s'",strings,
 
170
                                                                tokdes);
 
171
        PR_smprintf_free(strings);
 
172
        strings = newStrings;
 
173
    }
 
174
   if (strings == NULL) return;
 
175
 
 
176
    if (ptokdes) {
 
177
        newStrings = PR_smprintf("%s dbTokenDescription='%s'",strings,ptokdes);
 
178
        PR_smprintf_free(strings);
 
179
        strings = newStrings;
 
180
    }
 
181
   if (strings == NULL) return;
 
182
 
 
183
    if (slotdes) {
 
184
        newStrings = PR_smprintf("%s cryptoSlotDescription='%s'",strings,
 
185
                                                                slotdes);
 
186
        PR_smprintf_free(strings);
 
187
        strings = newStrings;
 
188
    }
 
189
   if (strings == NULL) return;
 
190
 
 
191
    if (pslotdes) {
 
192
        newStrings = PR_smprintf("%s dbSlotDescription='%s'",strings,pslotdes);
 
193
        PR_smprintf_free(strings);
 
194
        strings = newStrings;
 
195
    }
 
196
   if (strings == NULL) return;
 
197
 
 
198
    if (fslotdes) {
 
199
        newStrings = PR_smprintf("%s FIPSSlotDescription='%s'",
 
200
                                                        strings,fslotdes);
 
201
        PR_smprintf_free(strings);
 
202
        strings = newStrings;
 
203
    }
 
204
   if (strings == NULL) return;
 
205
 
 
206
    if (fpslotdes) {
 
207
        newStrings = PR_smprintf("%s FIPSTokenDescription='%s'",
 
208
                                                        strings,fpslotdes);
 
209
        PR_smprintf_free(strings);
 
210
        strings = newStrings;
 
211
    }
 
212
   if (strings == NULL) return;
 
213
 
 
214
    newStrings = PR_smprintf("%s minPS=%d", strings, minPwd);
 
215
    PR_smprintf_free(strings);
 
216
    strings = newStrings;
 
217
   if (strings == NULL) return;
 
218
 
 
219
    if (pk11_config_strings != NULL) {
 
220
        PR_smprintf_free(pk11_config_strings);
 
221
    }
 
222
    pk11_config_strings = strings;
 
223
    pk11_password_required = pwRequired;
 
224
 
 
225
    return;
 
226
}
 
227
 
 
228
static char *
 
229
nss_addEscape(const char *string, char quote)
 
230
{
 
231
    char *newString = 0;
 
232
    int escapes = 0, size = 0;
 
233
    const char *src;
 
234
    char *dest;
 
235
 
 
236
    for (src=string; *src ; src++) {
 
237
        if ((*src == quote) || (*src == '\\')) escapes++;
 
238
        size++;
 
239
    }
 
240
 
 
241
    newString = PORT_ZAlloc(escapes+size+1); 
 
242
    if (newString == NULL) {
 
243
        return NULL;
 
244
    }
 
245
 
 
246
    for (src=string, dest=newString; *src; src++,dest++) {
 
247
        if ((*src == '\\') || (*src == quote)) {
 
248
            *dest++ = '\\';
 
249
        }
 
250
        *dest = *src;
 
251
    }
 
252
 
 
253
    return newString;
 
254
}
 
255
 
 
256
static char *
 
257
nss_doubleEscape(const char *string)
 
258
{
 
259
    char *round1 = NULL;
 
260
    char *retValue = NULL;
 
261
    if (string == NULL) {
 
262
        goto done;
 
263
    }
 
264
    round1 = nss_addEscape(string,'\'');
 
265
    if (round1) {
 
266
        retValue = nss_addEscape(round1,'"');
 
267
        PORT_Free(round1);
 
268
    }
 
269
 
 
270
done:
 
271
    if (retValue == NULL) {
 
272
        retValue = PORT_Strdup("");
 
273
    }
 
274
    return retValue;
 
275
}
 
276
 
 
277
 
 
278
#ifndef XP_MAC
 
279
/*
 
280
 * The following code is an attempt to automagically find the external root
 
281
 * module. NOTE: This code should be checked out on the MAC! There must be
 
282
 * some cross platform support out there to help out with this?
 
283
 * Note: Keep the #if-defined chunks in order. HPUX must select before UNIX.
 
284
 */
 
285
 
 
286
static const char *dllname =
 
287
#if defined(XP_WIN32) || defined(XP_OS2)
 
288
        "nssckbi.dll";
 
289
#elif defined(HPUX) && !defined(__ia64)  /* HP-UX PA-RISC */
 
290
        "libnssckbi.sl";
 
291
#elif defined(DARWIN)
 
292
        "libnssckbi.dylib";
 
293
#elif defined(XP_UNIX) || defined(XP_BEOS)
 
294
        "libnssckbi.so";
 
295
#elif defined(XP_MAC)
 
296
        "NSS Builtin Root Certs";
 
297
#else
 
298
        #error "Uh! Oh! I don't know about this platform."
 
299
#endif
 
300
 
 
301
/* Should we have platform ifdefs here??? */
 
302
#define FILE_SEP '/'
 
303
 
 
304
static void nss_FindExternalRootPaths(const char *dbpath, 
 
305
                                      const char* secmodprefix,
 
306
                              char** retoldpath, char** retnewpath)
 
307
{
 
308
    char *path, *oldpath = NULL, *lastsep;
 
309
    int len, path_len, secmod_len, dll_len;
 
310
 
 
311
    path_len = PORT_Strlen(dbpath);
 
312
    secmod_len = secmodprefix ? PORT_Strlen(secmodprefix) : 0;
 
313
    dll_len = PORT_Strlen(dllname);
 
314
    len = path_len + secmod_len + dll_len + 2; /* FILE_SEP + NULL */
 
315
 
 
316
    path = PORT_Alloc(len);
 
317
    if (path == NULL) return;
 
318
 
 
319
    /* back up to the top of the directory */
 
320
    PORT_Memcpy(path,dbpath,path_len);
 
321
    if (path[path_len-1] != FILE_SEP) {
 
322
        path[path_len++] = FILE_SEP;
 
323
    }
 
324
    PORT_Strcpy(&path[path_len],dllname);
 
325
    if (secmod_len > 0) {
 
326
        lastsep = PORT_Strrchr(secmodprefix, FILE_SEP);
 
327
        if (lastsep) {
 
328
            int secmoddir_len = lastsep-secmodprefix+1; /* FILE_SEP */
 
329
            oldpath = PORT_Alloc(len);
 
330
            if (oldpath == NULL) {
 
331
                PORT_Free(path);
 
332
                return;
 
333
            }
 
334
            PORT_Memcpy(oldpath,path,path_len);
 
335
            PORT_Memcpy(&oldpath[path_len],secmodprefix,secmoddir_len);
 
336
            PORT_Strcpy(&oldpath[path_len+secmoddir_len],dllname);
 
337
        }
 
338
    }
 
339
    *retoldpath = oldpath;
 
340
    *retnewpath = path;
 
341
    return;
 
342
}
 
343
 
 
344
static void nss_FreeExternalRootPaths(char* oldpath, char* path)
 
345
{
 
346
    if (path) {
 
347
        PORT_Free(path);
 
348
    }
 
349
    if (oldpath) {
 
350
        PORT_Free(oldpath);
 
351
    }
 
352
}
 
353
 
 
354
static void
 
355
nss_FindExternalRoot(const char *dbpath, const char* secmodprefix)
 
356
{
 
357
        char *path = NULL;
 
358
        char *oldpath = NULL;
 
359
        PRBool hasrootcerts = PR_FALSE;
 
360
 
 
361
        /*
 
362
         * 'oldpath' is the external root path in NSS 3.3.x or older.
 
363
         * For backward compatibility we try to load the root certs
 
364
         * module with the old path first.
 
365
         */
 
366
        nss_FindExternalRootPaths(dbpath, secmodprefix, &oldpath, &path);
 
367
        if (oldpath) {
 
368
            (void) SECMOD_AddNewModule("Root Certs",oldpath, 0, 0);
 
369
            hasrootcerts = SECMOD_HasRootCerts();
 
370
        }
 
371
        if (path && !hasrootcerts) {
 
372
            (void) SECMOD_AddNewModule("Root Certs",path, 0, 0);
 
373
        }
 
374
        nss_FreeExternalRootPaths(oldpath, path);
 
375
        return;
 
376
}
 
377
#endif
 
378
 
 
379
/*
 
380
 * OK there are now lots of options here, lets go through them all:
 
381
 *
 
382
 * configdir - base directory where all the cert, key, and module datbases live.
 
383
 * certPrefix - prefix added to the beginning of the cert database example: "
 
384
 *                      "https-server1-"
 
385
 * keyPrefix - prefix added to the beginning of the key database example: "
 
386
 *                      "https-server1-"
 
387
 * secmodName - name of the security module database (usually "secmod.db").
 
388
 * readOnly - Boolean: true if the databases are to be openned read only.
 
389
 * nocertdb - Don't open the cert DB and key DB's, just initialize the 
 
390
 *                      Volatile certdb.
 
391
 * nomoddb - Don't open the security module DB, just initialize the 
 
392
 *                      PKCS #11 module.
 
393
 * forceOpen - Continue to force initializations even if the databases cannot
 
394
 *                      be opened.
 
395
 */
 
396
 
 
397
static PRBool nss_IsInitted = PR_FALSE;
 
398
 
 
399
extern SECStatus secoid_Init(void);
 
400
static SECStatus nss_InitShutdownList(void);
 
401
 
 
402
#ifdef DEBUG
 
403
static CERTCertificate dummyCert;
 
404
#endif
 
405
 
 
406
static SECStatus
 
407
nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix,
 
408
                 const char *secmodName, PRBool readOnly, PRBool noCertDB, 
 
409
                        PRBool noModDB, PRBool forceOpen, PRBool noRootInit,
 
410
                        PRBool optimizeSpace, PRBool noSingleThreadedModules,
 
411
                        PRBool allowAlreadyInitializedModules,
 
412
                        PRBool dontFinalizeModules)
 
413
{
 
414
    char *moduleSpec = NULL;
 
415
    char *flags = NULL;
 
416
    SECStatus rv = SECFailure;
 
417
    char *lconfigdir = NULL;
 
418
    char *lcertPrefix = NULL;
 
419
    char *lkeyPrefix = NULL;
 
420
    char *lsecmodName = NULL;
 
421
 
 
422
    if (nss_IsInitted) {
 
423
        return SECSuccess;
 
424
    }
 
425
 
 
426
    /* New option bits must not change the size of CERTCertificate. */
 
427
    PORT_Assert(sizeof(dummyCert.options) == sizeof(void *));
 
428
 
 
429
    if (SECSuccess != InitCRLCache()) {
 
430
        return SECFailure;
 
431
    }
 
432
    
 
433
    if (SECSuccess != InitOCSPGlobal()) {
 
434
        return SECFailure;
 
435
    }
 
436
 
 
437
    flags = nss_makeFlags(readOnly,noCertDB,noModDB,forceOpen,
 
438
                                        pk11_password_required, optimizeSpace);
 
439
    if (flags == NULL) return rv;
 
440
 
 
441
    /*
 
442
     * configdir is double nested, and Windows uses the same character
 
443
     * for file seps as we use for escapes! (sigh).
 
444
     */
 
445
    lconfigdir = nss_doubleEscape(configdir);
 
446
    if (lconfigdir == NULL) {
 
447
        goto loser;
 
448
    }
 
449
    lcertPrefix = nss_doubleEscape(certPrefix);
 
450
    if (lcertPrefix == NULL) {
 
451
        goto loser;
 
452
    }
 
453
    lkeyPrefix = nss_doubleEscape(keyPrefix);
 
454
    if (lkeyPrefix == NULL) {
 
455
        goto loser;
 
456
    }
 
457
    lsecmodName = nss_doubleEscape(secmodName);
 
458
    if (lsecmodName == NULL) {
 
459
        goto loser;
 
460
    }
 
461
    if (noSingleThreadedModules || allowAlreadyInitializedModules ||
 
462
        dontFinalizeModules) {
 
463
        pk11_setGlobalOptions(noSingleThreadedModules,
 
464
                              allowAlreadyInitializedModules,
 
465
                              dontFinalizeModules);
 
466
    }
 
467
 
 
468
    moduleSpec = PR_smprintf("name=\"%s\" parameters=\"configdir='%s' certPrefix='%s' keyPrefix='%s' secmod='%s' flags=%s %s\" NSS=\"flags=internal,moduleDB,moduleDBOnly,critical\"",
 
469
                pk11_config_name ? pk11_config_name : NSS_DEFAULT_MOD_NAME,
 
470
                lconfigdir,lcertPrefix,lkeyPrefix,lsecmodName,flags,
 
471
                pk11_config_strings ? pk11_config_strings : "");
 
472
 
 
473
loser:
 
474
    PORT_Free(flags);
 
475
    if (lconfigdir) PORT_Free(lconfigdir);
 
476
    if (lcertPrefix) PORT_Free(lcertPrefix);
 
477
    if (lkeyPrefix) PORT_Free(lkeyPrefix);
 
478
    if (lsecmodName) PORT_Free(lsecmodName);
 
479
 
 
480
    if (moduleSpec) {
 
481
        SECMODModule *module = SECMOD_LoadModule(moduleSpec,NULL,PR_TRUE);
 
482
        PR_smprintf_free(moduleSpec);
 
483
        if (module) {
 
484
            if (module->loaded) rv=SECSuccess;
 
485
            SECMOD_DestroyModule(module);
 
486
        }
 
487
    }
 
488
 
 
489
    if (rv == SECSuccess) {
 
490
        if (secoid_Init() != SECSuccess) {
 
491
            return SECFailure;
 
492
        }
 
493
        if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) {
 
494
            return SECFailure;
 
495
        }
 
496
        if (nss_InitShutdownList() != SECSuccess) {
 
497
            return SECFailure;
 
498
        }
 
499
        CERT_SetDefaultCertDB((CERTCertDBHandle *)
 
500
                                STAN_GetDefaultTrustDomain());
 
501
#ifndef XP_MAC
 
502
        /* only servers need this. We currently do not have a mac server */
 
503
        if ((!noModDB) && (!noCertDB) && (!noRootInit)) {
 
504
            if (!SECMOD_HasRootCerts()) {
 
505
                nss_FindExternalRoot(configdir, secmodName);
 
506
            }
 
507
        }
 
508
#endif
 
509
        pk11sdr_Init();
 
510
        cert_CreateSubjectKeyIDHashTable();
 
511
        nss_IsInitted = PR_TRUE;
 
512
    }
 
513
    return rv;
 
514
}
 
515
 
 
516
 
 
517
SECStatus
 
518
NSS_Init(const char *configdir)
 
519
{
 
520
    return nss_Init(configdir, "", "", SECMOD_DB, PR_TRUE, 
 
521
                PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
 
522
}
 
523
 
 
524
SECStatus
 
525
NSS_InitReadWrite(const char *configdir)
 
526
{
 
527
    return nss_Init(configdir, "", "", SECMOD_DB, PR_FALSE, 
 
528
                PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE, PR_TRUE, PR_FALSE, PR_FALSE, PR_FALSE);
 
529
}
 
530
 
 
531
/*
 
532
 * OK there are now lots of options here, lets go through them all:
 
533
 *
 
534
 * configdir - base directory where all the cert, key, and module datbases live.
 
535
 * certPrefix - prefix added to the beginning of the cert database example: "
 
536
 *                      "https-server1-"
 
537
 * keyPrefix - prefix added to the beginning of the key database example: "
 
538
 *                      "https-server1-"
 
539
 * secmodName - name of the security module database (usually "secmod.db").
 
540
 * flags - change the open options of NSS_Initialize as follows:
 
541
 *      NSS_INIT_READONLY - Open the databases read only.
 
542
 *      NSS_INIT_NOCERTDB - Don't open the cert DB and key DB's, just 
 
543
 *                      initialize the volatile certdb.
 
544
 *      NSS_INIT_NOMODDB  - Don't open the security module DB, just 
 
545
 *                      initialize the  PKCS #11 module.
 
546
 *      NSS_INIT_FORCEOPEN - Continue to force initializations even if the 
 
547
 *                      databases cannot be opened.
 
548
 *      NSS_INIT_PK11THREADSAFE - only load PKCS#11 modules that are
 
549
 *                      thread-safe, ie. that support locking - either OS
 
550
 *                      locking or NSS-provided locks . If a PKCS#11
 
551
 *                      module isn't thread-safe, don't serialize its
 
552
 *                      calls; just don't load it instead. This is necessary
 
553
 *                      if another piece of code is using the same PKCS#11
 
554
 *                      modules that NSS is accessing without going through
 
555
 *                      NSS, for example the Java SunPKCS11 provider.
 
556
 *      NSS_INIT_PK11RELOAD - ignore the CKR_CRYPTOKI_ALREADY_INITIALIZED
 
557
 *                      error when loading PKCS#11 modules. This is necessary
 
558
 *                      if another piece of code is using the same PKCS#11
 
559
 *                      modules that NSS is accessing without going through
 
560
 *                      NSS, for example Java SunPKCS11 provider.
 
561
 *      NSS_INIT_NOPK11FINALIZE - never call C_Finalize on any
 
562
 *                      PKCS#11 module. This may be necessary in order to
 
563
 *                      ensure continuous operation and proper shutdown
 
564
 *                      sequence if another piece of code is using the same
 
565
 *                      PKCS#11 modules that NSS is accessing without going
 
566
 *                      through NSS, for example Java SunPKCS11 provider.
 
567
 *                      The following limitation applies when this is set :
 
568
 *                      SECMOD_WaitForAnyTokenEvent will not use
 
569
 *                      C_WaitForSlotEvent, in order to prevent the need for
 
570
 *                      C_Finalize. This call will be emulated instead.
 
571
 *      NSS_INIT_RESERVED - Currently has no effect, but may be used in the
 
572
 *                      future to trigger better cooperation between PKCS#11
 
573
 *                      modules used by both NSS and the Java SunPKCS11
 
574
 *                      provider. This should occur after a new flag is defined
 
575
 *                      for C_Initialize by the PKCS#11 working group.
 
576
 *      NSS_INIT_COOPERATE - Sets 4 recommended options for applications that
 
577
 *                      use both NSS and the Java SunPKCS11 provider. 
 
578
 */
 
579
SECStatus
 
580
NSS_Initialize(const char *configdir, const char *certPrefix, 
 
581
        const char *keyPrefix, const char *secmodName, PRUint32 flags)
 
582
{
 
583
    return nss_Init(configdir, certPrefix, keyPrefix, secmodName, 
 
584
        ((flags & NSS_INIT_READONLY) == NSS_INIT_READONLY),
 
585
        ((flags & NSS_INIT_NOCERTDB) == NSS_INIT_NOCERTDB),
 
586
        ((flags & NSS_INIT_NOMODDB) == NSS_INIT_NOMODDB),
 
587
        ((flags & NSS_INIT_FORCEOPEN) == NSS_INIT_FORCEOPEN),
 
588
        ((flags & NSS_INIT_NOROOTINIT) == NSS_INIT_NOROOTINIT),
 
589
        ((flags & NSS_INIT_OPTIMIZESPACE) == NSS_INIT_OPTIMIZESPACE),
 
590
        ((flags & NSS_INIT_PK11THREADSAFE) == NSS_INIT_PK11THREADSAFE),
 
591
        ((flags & NSS_INIT_PK11RELOAD) == NSS_INIT_PK11RELOAD),
 
592
        ((flags & NSS_INIT_NOPK11FINALIZE) == NSS_INIT_NOPK11FINALIZE));
 
593
}
 
594
 
 
595
/*
 
596
 * initialize NSS without a creating cert db's, key db's, or secmod db's.
 
597
 */
 
598
SECStatus
 
599
NSS_NoDB_Init(const char * configdir)
 
600
{
 
601
      return nss_Init("","","","",
 
602
                        PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,PR_TRUE,
 
603
                        PR_FALSE,PR_FALSE,PR_FALSE);
 
604
}
 
605
 
 
606
 
 
607
#define NSS_SHUTDOWN_STEP 10
 
608
 
 
609
struct NSSShutdownFuncPair {
 
610
    NSS_ShutdownFunc    func;
 
611
    void                *appData;
 
612
};
 
613
 
 
614
static struct NSSShutdownListStr {
 
615
    PZLock              *lock;
 
616
    int                 maxFuncs;
 
617
    int                 numFuncs;
 
618
    struct NSSShutdownFuncPair  *funcs;
 
619
} nssShutdownList = { 0 };
 
620
 
 
621
/*
 
622
 * find and existing shutdown function
 
623
 */
 
624
static int 
 
625
nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData)
 
626
{
 
627
    int count, i;
 
628
    count = nssShutdownList.numFuncs;
 
629
    /* expect the list to be short, just do a linear search */
 
630
    for (i=0; i < count; i++) {
 
631
        if ((nssShutdownList.funcs[i].func == sFunc) &&
 
632
            (nssShutdownList.funcs[i].appData == appData)){
 
633
            return i;
 
634
        }
 
635
    }
 
636
    return -1;
 
637
}
 
638
    
 
639
/*
 
640
 * register a callback to be called when NSS shuts down
 
641
 */
 
642
SECStatus
 
643
NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
 
644
{
 
645
    int i;
 
646
 
 
647
    if (!nss_IsInitted) {
 
648
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 
649
        return SECFailure;
 
650
    }
 
651
    if (sFunc == NULL) {
 
652
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
 
653
        return SECFailure;
 
654
    }
 
655
 
 
656
    PORT_Assert(nssShutdownList.lock);
 
657
    PZ_Lock(nssShutdownList.lock);
 
658
 
 
659
    /* make sure we don't have a duplicate */
 
660
    i = nss_GetShutdownEntry(sFunc, appData);
 
661
    if (i > 0) {
 
662
        PZ_Unlock(nssShutdownList.lock);
 
663
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 
664
        return SECFailure;
 
665
    }
 
666
    /* find an empty slot */
 
667
    i = nss_GetShutdownEntry(NULL, NULL);
 
668
    if (i > 0) {
 
669
        nssShutdownList.funcs[i].func = sFunc;
 
670
        nssShutdownList.funcs[i].appData = appData;
 
671
        PZ_Unlock(nssShutdownList.lock);
 
672
        return SECFailure;
 
673
    }
 
674
    if (nssShutdownList.maxFuncs == nssShutdownList.numFuncs) {
 
675
        struct NSSShutdownFuncPair *funcs = 
 
676
                (struct NSSShutdownFuncPair *)PORT_Realloc
 
677
                (nssShutdownList.funcs, 
 
678
                (nssShutdownList.maxFuncs + NSS_SHUTDOWN_STEP) 
 
679
                *sizeof(struct NSSShutdownFuncPair));
 
680
        if (!funcs) {
 
681
            return SECFailure;
 
682
        }
 
683
        nssShutdownList.funcs = funcs;
 
684
        nssShutdownList.maxFuncs += NSS_SHUTDOWN_STEP;
 
685
    }
 
686
    nssShutdownList.funcs[nssShutdownList.numFuncs].func = sFunc;
 
687
    nssShutdownList.funcs[nssShutdownList.numFuncs].appData = appData;
 
688
    nssShutdownList.numFuncs++;
 
689
    PZ_Unlock(nssShutdownList.lock);
 
690
    return SECSuccess;
 
691
}
 
692
 
 
693
/*
 
694
 * unregister a callback so it won't get called on shutdown.
 
695
 */
 
696
SECStatus
 
697
NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData)
 
698
{
 
699
    int i;
 
700
    if (!nss_IsInitted) {
 
701
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 
702
        return SECFailure;
 
703
    }
 
704
 
 
705
    PORT_Assert(nssShutdownList.lock);
 
706
    PZ_Lock(nssShutdownList.lock);
 
707
    i = nss_GetShutdownEntry(sFunc, appData);
 
708
    if (i > 0) {
 
709
        nssShutdownList.funcs[i].func = NULL;
 
710
        nssShutdownList.funcs[i].appData = NULL;
 
711
    }
 
712
    PZ_Unlock(nssShutdownList.lock);
 
713
 
 
714
    if (i < 0) {
 
715
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 
716
        return SECFailure;
 
717
    }
 
718
    return SECSuccess;
 
719
}
 
720
 
 
721
/*
 
722
 * bring up and shutdown the shutdown list
 
723
 */
 
724
static SECStatus
 
725
nss_InitShutdownList(void)
 
726
{
 
727
    nssShutdownList.lock = PZ_NewLock(nssILockOther);
 
728
    if (nssShutdownList.lock == NULL) {
 
729
        return SECFailure;
 
730
    }
 
731
    nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair, 
 
732
                                           NSS_SHUTDOWN_STEP);
 
733
    if (nssShutdownList.funcs == NULL) {
 
734
        PZ_DestroyLock(nssShutdownList.lock);
 
735
        nssShutdownList.lock = NULL;
 
736
        return SECFailure;
 
737
    }
 
738
    nssShutdownList.maxFuncs = NSS_SHUTDOWN_STEP;
 
739
    nssShutdownList.numFuncs = 0;
 
740
 
 
741
    return SECSuccess;
 
742
}
 
743
 
 
744
static SECStatus
 
745
nss_ShutdownShutdownList(void)
 
746
{
 
747
    SECStatus rv = SECSuccess;
 
748
    int i;
 
749
 
 
750
    /* call all the registerd functions first */
 
751
    for (i=0; i < nssShutdownList.numFuncs; i++) {
 
752
        struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i];
 
753
        if (funcPair->func) {
 
754
            if ((*funcPair->func)(funcPair->appData,NULL) != SECSuccess) {
 
755
                rv = SECFailure;
 
756
            }
 
757
        }
 
758
    }
 
759
 
 
760
    nssShutdownList.numFuncs = 0;
 
761
    nssShutdownList.maxFuncs = 0;
 
762
    PORT_Free(nssShutdownList.funcs);
 
763
    nssShutdownList.funcs = NULL;
 
764
    if (nssShutdownList.lock) {
 
765
        PZ_DestroyLock(nssShutdownList.lock);
 
766
    }
 
767
    nssShutdownList.lock = NULL;
 
768
    return rv;
 
769
}
 
770
 
 
771
 
 
772
extern const NSSError NSS_ERROR_BUSY;
 
773
 
 
774
SECStatus
 
775
NSS_Shutdown(void)
 
776
{
 
777
    SECStatus shutdownRV = SECSuccess;
 
778
    SECStatus rv;
 
779
    PRStatus status;
 
780
 
 
781
    if (!nss_IsInitted) {
 
782
        PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
 
783
        return SECFailure;
 
784
    }
 
785
 
 
786
    rv = nss_ShutdownShutdownList();
 
787
    if (rv != SECSuccess) {
 
788
        shutdownRV = SECFailure;
 
789
    }
 
790
    ShutdownCRLCache();
 
791
    SECOID_Shutdown();
 
792
    status = STAN_Shutdown();
 
793
    cert_DestroySubjectKeyIDHashTable();
 
794
    rv = SECMOD_Shutdown();
 
795
    if (rv != SECSuccess) {
 
796
        shutdownRV = SECFailure;
 
797
    }
 
798
    pk11sdr_Shutdown();
 
799
    if (status == PR_FAILURE) {
 
800
        if (NSS_GetError() == NSS_ERROR_BUSY) {
 
801
            PORT_SetError(SEC_ERROR_BUSY);
 
802
        }
 
803
        shutdownRV = SECFailure;
 
804
    }
 
805
    nss_IsInitted = PR_FALSE;
 
806
    return shutdownRV;
 
807
}
 
808
 
 
809
PRBool
 
810
NSS_IsInitialized(void)
 
811
{
 
812
    return nss_IsInitted;
 
813
}
 
814
 
 
815
 
 
816
extern const char __nss_base_rcsid[];
 
817
extern const char __nss_base_sccsid[];
 
818
 
 
819
PRBool
 
820
NSS_VersionCheck(const char *importedVersion)
 
821
{
 
822
    /*
 
823
     * This is the secret handshake algorithm.
 
824
     *
 
825
     * This release has a simple version compatibility
 
826
     * check algorithm.  This release is not backward
 
827
     * compatible with previous major releases.  It is
 
828
     * not compatible with future major, minor, or
 
829
     * patch releases.
 
830
     */
 
831
    int vmajor = 0, vminor = 0, vpatch = 0;
 
832
    const char *ptr = importedVersion;
 
833
    volatile char c; /* force a reference that won't get optimized away */
 
834
 
 
835
    c = __nss_base_rcsid[0] + __nss_base_sccsid[0]; 
 
836
 
 
837
    while (isdigit(*ptr)) {
 
838
        vmajor = 10 * vmajor + *ptr - '0';
 
839
        ptr++;
 
840
    }
 
841
    if (*ptr == '.') {
 
842
        ptr++;
 
843
        while (isdigit(*ptr)) {
 
844
            vminor = 10 * vminor + *ptr - '0';
 
845
            ptr++;
 
846
        }
 
847
        if (*ptr == '.') {
 
848
            ptr++;
 
849
            while (isdigit(*ptr)) {
 
850
                vpatch = 10 * vpatch + *ptr - '0';
 
851
                ptr++;
 
852
            }
 
853
        }
 
854
    }
 
855
 
 
856
    if (vmajor != NSS_VMAJOR) {
 
857
        return PR_FALSE;
 
858
    }
 
859
    if (vmajor == NSS_VMAJOR && vminor > NSS_VMINOR) {
 
860
        return PR_FALSE;
 
861
    }
 
862
    if (vmajor == NSS_VMAJOR && vminor == NSS_VMINOR && vpatch > NSS_VPATCH) {
 
863
        return PR_FALSE;
 
864
    }
 
865
    /* Check dependent libraries */
 
866
    if (PR_VersionCheck(PR_VERSION) == PR_FALSE) {
 
867
        return PR_FALSE;
 
868
    }
 
869
    return PR_TRUE;
 
870
}
 
871
 
 
872