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  * The following handles the loading, unloading and management of
6  * various PCKS #11 modules
7  */
8 
9 #include <ctype.h>
10 #include <assert.h>
11 #include "pkcs11.h"
12 #include "seccomon.h"
13 #include "secmod.h"
14 #include "secmodi.h"
15 #include "secmodti.h"
16 #include "pki3hack.h"
17 #include "secerr.h"
18 #include "nss.h"
19 #include "utilpars.h"
20 #include "pk11pub.h"
21 
22 /* create a new module */
23 static SECMODModule *
secmod_NewModule(void)24 secmod_NewModule(void)
25 {
26     SECMODModule *newMod;
27     PLArenaPool *arena;
28 
29     /* create an arena in which dllName and commonName can be
30      * allocated.
31      */
32     arena = PORT_NewArena(512);
33     if (arena == NULL) {
34         return NULL;
35     }
36 
37     newMod = (SECMODModule *)PORT_ArenaAlloc(arena, sizeof(SECMODModule));
38     if (newMod == NULL) {
39         PORT_FreeArena(arena, PR_FALSE);
40         return NULL;
41     }
42 
43     /*
44      * initialize of the fields of the module
45      */
46     newMod->arena = arena;
47     newMod->internal = PR_FALSE;
48     newMod->loaded = PR_FALSE;
49     newMod->isFIPS = PR_FALSE;
50     newMod->dllName = NULL;
51     newMod->commonName = NULL;
52     newMod->library = NULL;
53     newMod->functionList = NULL;
54     newMod->slotCount = 0;
55     newMod->slots = NULL;
56     newMod->slotInfo = NULL;
57     newMod->slotInfoCount = 0;
58     newMod->refCount = 1;
59     newMod->ssl[0] = 0;
60     newMod->ssl[1] = 0;
61     newMod->libraryParams = NULL;
62     newMod->moduleDBFunc = NULL;
63     newMod->parent = NULL;
64     newMod->isCritical = PR_FALSE;
65     newMod->isModuleDB = PR_FALSE;
66     newMod->moduleDBOnly = PR_FALSE;
67     newMod->trustOrder = 0;
68     newMod->cipherOrder = 0;
69     newMod->evControlMask = 0;
70     newMod->refLock = PZ_NewLock(nssILockRefLock);
71     if (newMod->refLock == NULL) {
72         PORT_FreeArena(arena, PR_FALSE);
73         return NULL;
74     }
75     return newMod;
76 }
77 
78 /* private flags for isModuleDB (field in SECMODModule). */
79 /* The meaing of these flags is as follows:
80  *
81  * SECMOD_FLAG_MODULE_DB_IS_MODULE_DB - This is a module that accesses the
82  *   database of other modules to load. Module DBs are loadable modules that
83  *   tells NSS which PKCS #11 modules to load and when. These module DBs are
84  *   chainable. That is, one module DB can load another one. NSS system init
85  *   design takes advantage of this feature. In system NSS, a fixed system
86  *   module DB loads the system defined libraries, then chains out to the
87  *   traditional module DBs to load any system or user configured modules
88  *   (like smart cards). This bit is the same as the already existing meaning
89  *   of  isModuleDB = PR_TRUE. None of the other module db flags should be set
90  *   if this flag isn't on.
91  *
92  * SECMOD_FLAG_MODULE_DB_SKIP_FIRST - This flag tells NSS to skip the first
93  *   PKCS #11 module presented by a module DB. This allows the OS to load a
94  *   softoken from the system module, then ask the existing module DB code to
95  *   load the other PKCS #11 modules in that module DB (skipping it's request
96  *   to load softoken). This gives the system init finer control over the
97  *   configuration of that softoken module.
98  *
99  * SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB - This flag allows system init to mark a
100  *   different module DB as the 'default' module DB (the one in which
101  *   'Add module' changes will go). Without this flag NSS takes the first
102  *   module as the default Module DB, but in system NSS, that first module
103  *   is the system module, which is likely read only (at least to the user).
104  *   This  allows system NSS to delegate those changes to the user's module DB,
105  *   preserving the user's ability to load new PKCS #11 modules (which only
106  *   affect him), from existing applications like Firefox.
107  */
108 #define SECMOD_FLAG_MODULE_DB_IS_MODULE_DB 0x01 /* must be set if any of the \
109                                                  *other flags are set */
110 #define SECMOD_FLAG_MODULE_DB_SKIP_FIRST 0x02
111 #define SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB 0x04
112 #define SECMOD_FLAG_MODULE_DB_POLICY_ONLY 0x08
113 
114 /* private flags for internal (field in SECMODModule). */
115 /* The meaing of these flags is as follows:
116  *
117  * SECMOD_FLAG_INTERNAL_IS_INTERNAL - This is a marks the the module is
118  *   the internal module (that is, softoken). This bit is the same as the
119  *   already existing meaning of internal = PR_TRUE. None of the other
120  *   internal flags should be set if this flag isn't on.
121  *
122  * SECMOD_FLAG_MODULE_INTERNAL_KEY_SLOT - This flag allows system init to mark
123  *   a  different slot returned byt PK11_GetInternalKeySlot(). The 'primary'
124  *   slot defined by this module will be the new internal key slot.
125  */
126 #define SECMOD_FLAG_INTERNAL_IS_INTERNAL 0x01 /* must be set if any of \
127                                                *the other flags are set */
128 #define SECMOD_FLAG_INTERNAL_KEY_SLOT 0x02
129 
130 /*
131  * for 3.4 we continue to use the old SECMODModule structure
132  */
133 SECMODModule *
SECMOD_CreateModule(const char * library,const char * moduleName,const char * parameters,const char * nss)134 SECMOD_CreateModule(const char *library, const char *moduleName,
135                     const char *parameters, const char *nss)
136 {
137     return SECMOD_CreateModuleEx(library, moduleName, parameters, nss, NULL);
138 }
139 
140 /*
141  * NSS config options format:
142  *
143  * The specified ciphers will be allowed by policy, but an application
144  * may allow more by policy explicitly:
145  * config="allow=curve1:curve2:hash1:hash2:rsa-1024..."
146  *
147  * Only the specified hashes and curves will be allowed:
148  * config="disallow=all allow=sha1:sha256:secp256r1:secp384r1"
149  *
150  * Only the specified hashes and curves will be allowed, and
151  *  RSA keys of 2048 or more will be accepted, and DH key exchange
152  *  with 1024-bit primes or more:
153  * config="disallow=all allow=sha1:sha256:secp256r1:secp384r1:min-rsa=2048:min-dh=1024"
154  *
155  * A policy that enables the AES ciphersuites and the SECP256/384 curves:
156  * config="allow=aes128-cbc:aes128-gcm:TLS1.0:TLS1.2:TLS1.1:HMAC-SHA1:SHA1:SHA256:SHA384:RSA:ECDHE-RSA:SECP256R1:SECP384R1"
157  *
158  * Disallow values are parsed first, then allow values, independent of the
159  * order they appear.
160  *
161  * flags: turn on the following flags:
162  *    policy-lock: turn off the ability for applications to change policy with
163  *                 the call NSS_SetAlgorithmPolicy or the other system policy
164  *                 calls (SSL_SetPolicy, etc.)
165  *    ssl-lock:    turn off the ability to change the ssl defaults.
166  *
167  * The following only apply to ssl cipher suites (future smime)
168  *
169  * enable: turn on ciphersuites by default.
170  * disable: turn off ciphersuites by default without disallowing them by policy.
171  *
172  *
173  */
174 
175 typedef struct {
176     const char *name;
177     unsigned name_size;
178     SECOidTag oid;
179     PRUint32 val;
180 } oidValDef;
181 
182 typedef struct {
183     const char *name;
184     unsigned name_size;
185     PRInt32 option;
186 } optionFreeDef;
187 
188 typedef struct {
189     const char *name;
190     unsigned name_size;
191     PRUint32 flag;
192 } policyFlagDef;
193 
194 /*
195  *  This table should be merged with the SECOID table.
196  */
197 #define CIPHER_NAME(x) x, (sizeof(x) - 1)
198 static const oidValDef curveOptList[] = {
199     /* Curves */
200     { CIPHER_NAME("PRIME192V1"), SEC_OID_ANSIX962_EC_PRIME192V1,
201       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
202     { CIPHER_NAME("PRIME192V2"), SEC_OID_ANSIX962_EC_PRIME192V2,
203       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
204     { CIPHER_NAME("PRIME192V3"), SEC_OID_ANSIX962_EC_PRIME192V3,
205       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
206     { CIPHER_NAME("PRIME239V1"), SEC_OID_ANSIX962_EC_PRIME239V1,
207       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
208     { CIPHER_NAME("PRIME239V2"), SEC_OID_ANSIX962_EC_PRIME239V2,
209       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
210     { CIPHER_NAME("PRIME239V3"), SEC_OID_ANSIX962_EC_PRIME239V3,
211       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
212     { CIPHER_NAME("PRIME256V1"), SEC_OID_ANSIX962_EC_PRIME256V1,
213       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
214     { CIPHER_NAME("SECP112R1"), SEC_OID_SECG_EC_SECP112R1,
215       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
216     { CIPHER_NAME("SECP112R2"), SEC_OID_SECG_EC_SECP112R2,
217       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
218     { CIPHER_NAME("SECP128R1"), SEC_OID_SECG_EC_SECP128R1,
219       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
220     { CIPHER_NAME("SECP128R2"), SEC_OID_SECG_EC_SECP128R2,
221       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
222     { CIPHER_NAME("SECP160K1"), SEC_OID_SECG_EC_SECP160K1,
223       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
224     { CIPHER_NAME("SECP160R1"), SEC_OID_SECG_EC_SECP160R1,
225       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
226     { CIPHER_NAME("SECP160R2"), SEC_OID_SECG_EC_SECP160R2,
227       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
228     { CIPHER_NAME("SECP192K1"), SEC_OID_SECG_EC_SECP192K1,
229       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
230     { CIPHER_NAME("SECP192R1"), SEC_OID_ANSIX962_EC_PRIME192V1,
231       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
232     { CIPHER_NAME("SECP224K1"), SEC_OID_SECG_EC_SECP224K1,
233       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
234     { CIPHER_NAME("SECP256K1"), SEC_OID_SECG_EC_SECP256K1,
235       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
236     { CIPHER_NAME("SECP256R1"), SEC_OID_ANSIX962_EC_PRIME256V1,
237       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
238     { CIPHER_NAME("SECP384R1"), SEC_OID_SECG_EC_SECP384R1,
239       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
240     { CIPHER_NAME("SECP521R1"), SEC_OID_SECG_EC_SECP521R1,
241       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
242     { CIPHER_NAME("CURVE25519"), SEC_OID_CURVE25519,
243       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
244     /* ANSI X9.62 named elliptic curves (characteristic two field) */
245     { CIPHER_NAME("C2PNB163V1"), SEC_OID_ANSIX962_EC_C2PNB163V1,
246       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
247     { CIPHER_NAME("C2PNB163V2"), SEC_OID_ANSIX962_EC_C2PNB163V2,
248       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
249     { CIPHER_NAME("C2PNB163V3"), SEC_OID_ANSIX962_EC_C2PNB163V3,
250       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
251     { CIPHER_NAME("C2PNB176V1"), SEC_OID_ANSIX962_EC_C2PNB176V1,
252       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
253     { CIPHER_NAME("C2TNB191V1"), SEC_OID_ANSIX962_EC_C2TNB191V1,
254       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
255     { CIPHER_NAME("C2TNB191V2"), SEC_OID_ANSIX962_EC_C2TNB191V2,
256       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
257     { CIPHER_NAME("C2TNB191V3"), SEC_OID_ANSIX962_EC_C2TNB191V3,
258       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
259     { CIPHER_NAME("C2ONB191V4"), SEC_OID_ANSIX962_EC_C2ONB191V4,
260       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
261     { CIPHER_NAME("C2ONB191V5"), SEC_OID_ANSIX962_EC_C2ONB191V5,
262       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
263     { CIPHER_NAME("C2PNB208W1"), SEC_OID_ANSIX962_EC_C2PNB208W1,
264       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
265     { CIPHER_NAME("C2TNB239V1"), SEC_OID_ANSIX962_EC_C2TNB239V1,
266       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
267     { CIPHER_NAME("C2TNB239V2"), SEC_OID_ANSIX962_EC_C2TNB239V2,
268       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
269     { CIPHER_NAME("C2TNB239V3"), SEC_OID_ANSIX962_EC_C2TNB239V3,
270       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
271     { CIPHER_NAME("C2ONB239V4"), SEC_OID_ANSIX962_EC_C2ONB239V4,
272       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
273     { CIPHER_NAME("C2ONB239V5"), SEC_OID_ANSIX962_EC_C2ONB239V5,
274       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
275     { CIPHER_NAME("C2PNB272W1"), SEC_OID_ANSIX962_EC_C2PNB272W1,
276       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
277     { CIPHER_NAME("C2PNB304W1"), SEC_OID_ANSIX962_EC_C2PNB304W1,
278       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
279     { CIPHER_NAME("C2TNB359V1"), SEC_OID_ANSIX962_EC_C2TNB359V1,
280       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
281     { CIPHER_NAME("C2PNB368W1"), SEC_OID_ANSIX962_EC_C2PNB368W1,
282       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
283     { CIPHER_NAME("C2TNB431R1"), SEC_OID_ANSIX962_EC_C2TNB431R1,
284       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
285     /* SECG named elliptic curves (characteristic two field) */
286     { CIPHER_NAME("SECT113R1"), SEC_OID_SECG_EC_SECT113R1,
287       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
288     { CIPHER_NAME("SECT131R1"), SEC_OID_SECG_EC_SECT113R2,
289       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
290     { CIPHER_NAME("SECT131R1"), SEC_OID_SECG_EC_SECT131R1,
291       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
292     { CIPHER_NAME("SECT131R2"), SEC_OID_SECG_EC_SECT131R2,
293       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
294     { CIPHER_NAME("SECT163K1"), SEC_OID_SECG_EC_SECT163K1,
295       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
296     { CIPHER_NAME("SECT163R1"), SEC_OID_SECG_EC_SECT163R1,
297       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
298     { CIPHER_NAME("SECT163R2"), SEC_OID_SECG_EC_SECT163R2,
299       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
300     { CIPHER_NAME("SECT193R1"), SEC_OID_SECG_EC_SECT193R1,
301       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
302     { CIPHER_NAME("SECT193R2"), SEC_OID_SECG_EC_SECT193R2,
303       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
304     { CIPHER_NAME("SECT233K1"), SEC_OID_SECG_EC_SECT233K1,
305       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
306     { CIPHER_NAME("SECT233R1"), SEC_OID_SECG_EC_SECT233R1,
307       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
308     { CIPHER_NAME("SECT239K1"), SEC_OID_SECG_EC_SECT239K1,
309       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
310     { CIPHER_NAME("SECT283K1"), SEC_OID_SECG_EC_SECT283K1,
311       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
312     { CIPHER_NAME("SECT283R1"), SEC_OID_SECG_EC_SECT283R1,
313       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
314     { CIPHER_NAME("SECT409K1"), SEC_OID_SECG_EC_SECT409K1,
315       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
316     { CIPHER_NAME("SECT409R1"), SEC_OID_SECG_EC_SECT409R1,
317       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
318     { CIPHER_NAME("SECT571K1"), SEC_OID_SECG_EC_SECT571K1,
319       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
320     { CIPHER_NAME("SECT571R1"), SEC_OID_SECG_EC_SECT571R1,
321       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_CERT_SIGNATURE },
322 };
323 
324 static const oidValDef hashOptList[] = {
325     /* Hashes */
326     { CIPHER_NAME("MD2"), SEC_OID_MD2,
327       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
328     { CIPHER_NAME("MD4"), SEC_OID_MD4,
329       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
330     { CIPHER_NAME("MD5"), SEC_OID_MD5,
331       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
332     { CIPHER_NAME("SHA1"), SEC_OID_SHA1,
333       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
334     { CIPHER_NAME("SHA224"), SEC_OID_SHA224,
335       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
336     { CIPHER_NAME("SHA256"), SEC_OID_SHA256,
337       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
338     { CIPHER_NAME("SHA384"), SEC_OID_SHA384,
339       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
340     { CIPHER_NAME("SHA512"), SEC_OID_SHA512,
341       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE }
342 };
343 
344 static const oidValDef macOptList[] = {
345     /* MACs */
346     { CIPHER_NAME("HMAC-SHA1"), SEC_OID_HMAC_SHA1, NSS_USE_ALG_IN_SSL },
347     { CIPHER_NAME("HMAC-SHA224"), SEC_OID_HMAC_SHA224, NSS_USE_ALG_IN_SSL },
348     { CIPHER_NAME("HMAC-SHA256"), SEC_OID_HMAC_SHA256, NSS_USE_ALG_IN_SSL },
349     { CIPHER_NAME("HMAC-SHA384"), SEC_OID_HMAC_SHA384, NSS_USE_ALG_IN_SSL },
350     { CIPHER_NAME("HMAC-SHA512"), SEC_OID_HMAC_SHA512, NSS_USE_ALG_IN_SSL },
351     { CIPHER_NAME("HMAC-MD5"), SEC_OID_HMAC_MD5, NSS_USE_ALG_IN_SSL },
352 };
353 
354 static const oidValDef cipherOptList[] = {
355     /* Ciphers */
356     { CIPHER_NAME("AES128-CBC"), SEC_OID_AES_128_CBC, NSS_USE_ALG_IN_SSL },
357     { CIPHER_NAME("AES192-CBC"), SEC_OID_AES_192_CBC, NSS_USE_ALG_IN_SSL },
358     { CIPHER_NAME("AES256-CBC"), SEC_OID_AES_256_CBC, NSS_USE_ALG_IN_SSL },
359     { CIPHER_NAME("AES128-GCM"), SEC_OID_AES_128_GCM, NSS_USE_ALG_IN_SSL },
360     { CIPHER_NAME("AES192-GCM"), SEC_OID_AES_192_GCM, NSS_USE_ALG_IN_SSL },
361     { CIPHER_NAME("AES256-GCM"), SEC_OID_AES_256_GCM, NSS_USE_ALG_IN_SSL },
362     { CIPHER_NAME("CAMELLIA128-CBC"), SEC_OID_CAMELLIA_128_CBC, NSS_USE_ALG_IN_SSL },
363     { CIPHER_NAME("CAMELLIA192-CBC"), SEC_OID_CAMELLIA_192_CBC, NSS_USE_ALG_IN_SSL },
364     { CIPHER_NAME("CAMELLIA256-CBC"), SEC_OID_CAMELLIA_256_CBC, NSS_USE_ALG_IN_SSL },
365     { CIPHER_NAME("CHACHA20-POLY1305"), SEC_OID_CHACHA20_POLY1305, NSS_USE_ALG_IN_SSL },
366     { CIPHER_NAME("SEED-CBC"), SEC_OID_SEED_CBC, NSS_USE_ALG_IN_SSL },
367     { CIPHER_NAME("DES-EDE3-CBC"), SEC_OID_DES_EDE3_CBC, NSS_USE_ALG_IN_SSL },
368     { CIPHER_NAME("DES-40-CBC"), SEC_OID_DES_40_CBC, NSS_USE_ALG_IN_SSL },
369     { CIPHER_NAME("DES-CBC"), SEC_OID_DES_CBC, NSS_USE_ALG_IN_SSL },
370     { CIPHER_NAME("NULL-CIPHER"), SEC_OID_NULL_CIPHER, NSS_USE_ALG_IN_SSL },
371     { CIPHER_NAME("RC2"), SEC_OID_RC2_CBC, NSS_USE_ALG_IN_SSL },
372     { CIPHER_NAME("RC4"), SEC_OID_RC4, NSS_USE_ALG_IN_SSL },
373     { CIPHER_NAME("IDEA"), SEC_OID_IDEA_CBC, NSS_USE_ALG_IN_SSL },
374 };
375 
376 static const oidValDef kxOptList[] = {
377     /* Key exchange */
378     { CIPHER_NAME("RSA"), SEC_OID_TLS_RSA, NSS_USE_ALG_IN_SSL_KX },
379     { CIPHER_NAME("RSA-EXPORT"), SEC_OID_TLS_RSA_EXPORT, NSS_USE_ALG_IN_SSL_KX },
380     { CIPHER_NAME("DHE-RSA"), SEC_OID_TLS_DHE_RSA, NSS_USE_ALG_IN_SSL_KX },
381     { CIPHER_NAME("DHE-DSS"), SEC_OID_TLS_DHE_DSS, NSS_USE_ALG_IN_SSL_KX },
382     { CIPHER_NAME("DH-RSA"), SEC_OID_TLS_DH_RSA, NSS_USE_ALG_IN_SSL_KX },
383     { CIPHER_NAME("DH-DSS"), SEC_OID_TLS_DH_DSS, NSS_USE_ALG_IN_SSL_KX },
384     { CIPHER_NAME("ECDHE-ECDSA"), SEC_OID_TLS_ECDHE_ECDSA, NSS_USE_ALG_IN_SSL_KX },
385     { CIPHER_NAME("ECDHE-RSA"), SEC_OID_TLS_ECDHE_RSA, NSS_USE_ALG_IN_SSL_KX },
386     { CIPHER_NAME("ECDH-ECDSA"), SEC_OID_TLS_ECDH_ECDSA, NSS_USE_ALG_IN_SSL_KX },
387     { CIPHER_NAME("ECDH-RSA"), SEC_OID_TLS_ECDH_RSA, NSS_USE_ALG_IN_SSL_KX },
388 };
389 
390 static const oidValDef signOptList[] = {
391     /* Signatures */
392     { CIPHER_NAME("DSA"), SEC_OID_ANSIX9_DSA_SIGNATURE,
393       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
394     { CIPHER_NAME("RSA-PKCS"), SEC_OID_PKCS1_RSA_ENCRYPTION,
395       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
396     { CIPHER_NAME("RSA-PSS"), SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
397       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
398     { CIPHER_NAME("ECDSA"), SEC_OID_ANSIX962_EC_PUBLIC_KEY,
399       NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_SIGNATURE },
400 };
401 
402 typedef struct {
403     const oidValDef *list;
404     PRUint32 entries;
405     const char *description;
406     PRBool allowEmpty;
407 } algListsDef;
408 
409 static const algListsDef algOptLists[] = {
410     { curveOptList, PR_ARRAY_SIZE(curveOptList), "ECC", PR_FALSE },
411     { hashOptList, PR_ARRAY_SIZE(hashOptList), "HASH", PR_FALSE },
412     { macOptList, PR_ARRAY_SIZE(macOptList), "MAC", PR_FALSE },
413     { cipherOptList, PR_ARRAY_SIZE(cipherOptList), "CIPHER", PR_FALSE },
414     { kxOptList, PR_ARRAY_SIZE(kxOptList), "OTHER-KX", PR_FALSE },
415     { signOptList, PR_ARRAY_SIZE(signOptList), "OTHER-SIGN", PR_FALSE },
416 };
417 
418 static const optionFreeDef sslOptList[] = {
419     /* Versions */
420     { CIPHER_NAME("SSL2.0"), 0x002 },
421     { CIPHER_NAME("SSL3.0"), 0x300 },
422     { CIPHER_NAME("SSL3.1"), 0x301 },
423     { CIPHER_NAME("TLS1.0"), 0x301 },
424     { CIPHER_NAME("TLS1.1"), 0x302 },
425     { CIPHER_NAME("TLS1.2"), 0x303 },
426     { CIPHER_NAME("TLS1.3"), 0x304 },
427     { CIPHER_NAME("DTLS1.0"), 0x302 },
428     { CIPHER_NAME("DTLS1.1"), 0x302 },
429     { CIPHER_NAME("DTLS1.2"), 0x303 },
430     { CIPHER_NAME("DTLS1.3"), 0x304 },
431 };
432 
433 static const optionFreeDef freeOptList[] = {
434 
435     /* Restrictions for asymetric keys */
436     { CIPHER_NAME("RSA-MIN"), NSS_RSA_MIN_KEY_SIZE },
437     { CIPHER_NAME("DH-MIN"), NSS_DH_MIN_KEY_SIZE },
438     { CIPHER_NAME("DSA-MIN"), NSS_DSA_MIN_KEY_SIZE },
439     /* constraints on SSL Protocols */
440     { CIPHER_NAME("TLS-VERSION-MIN"), NSS_TLS_VERSION_MIN_POLICY },
441     { CIPHER_NAME("TLS-VERSION-MAX"), NSS_TLS_VERSION_MAX_POLICY },
442     /* constraints on DTLS Protocols */
443     { CIPHER_NAME("DTLS-VERSION-MIN"), NSS_DTLS_VERSION_MIN_POLICY },
444     { CIPHER_NAME("DTLS-VERSION-MAX"), NSS_DTLS_VERSION_MAX_POLICY }
445 };
446 
447 static const policyFlagDef policyFlagList[] = {
448     { CIPHER_NAME("SSL"), NSS_USE_ALG_IN_SSL },
449     { CIPHER_NAME("SSL-KEY-EXCHANGE"), NSS_USE_ALG_IN_SSL_KX },
450     /* add other key exhanges in the future */
451     { CIPHER_NAME("KEY-EXCHANGE"), NSS_USE_ALG_IN_SSL_KX },
452     { CIPHER_NAME("CERT-SIGNATURE"), NSS_USE_ALG_IN_CERT_SIGNATURE },
453     { CIPHER_NAME("CMS-SIGNATURE"), NSS_USE_ALG_IN_CMS_SIGNATURE },
454     { CIPHER_NAME("ALL-SIGNATURE"), NSS_USE_ALG_IN_SIGNATURE },
455     /* sign turns off all signatures, but doesn't change the
456      * allowance for specific sigantures... for example:
457      * disallow=sha256/all allow=sha256/signature doesn't allow
458      * cert-sigantures, where disallow=sha256/all allow=sha256/all-signature
459      * does.
460      * however, disallow=sha356/signature and disallow=sha256/all-siganture are
461      * equivalent in effect */
462     { CIPHER_NAME("SIGNATURE"), NSS_USE_ALG_IN_ANY_SIGNATURE },
463     /* enable/disable everything */
464     { CIPHER_NAME("ALL"), NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SSL_KX |
465                               NSS_USE_ALG_IN_SIGNATURE },
466     { CIPHER_NAME("NONE"), 0 }
467 };
468 
469 /*
470  *  Get the next cipher on the list. point to the next one in 'next'.
471  *  return the length;
472  */
473 static const char *
secmod_ArgGetSubValue(const char * cipher,char sep1,char sep2,int * len,const char ** next)474 secmod_ArgGetSubValue(const char *cipher, char sep1, char sep2,
475                       int *len, const char **next)
476 {
477     const char *start = cipher;
478 
479     if (start == NULL) {
480         *len = 0;
481         *next = NULL;
482         return start;
483     }
484 
485     for (; *cipher && *cipher != sep2; cipher++) {
486         if (*cipher == sep1) {
487             *next = cipher + 1;
488             *len = cipher - start;
489             return start;
490         }
491     }
492     *next = NULL;
493     *len = cipher - start;
494     return start;
495 }
496 
497 static PRUint32
secmod_parsePolicyValue(const char * policyFlags,int policyLength,PRBool printPolicyFeedback)498 secmod_parsePolicyValue(const char *policyFlags, int policyLength,
499                         PRBool printPolicyFeedback)
500 {
501     const char *flag, *currentString;
502     PRUint32 flags = 0;
503     int i;
504 
505     for (currentString = policyFlags; currentString &&
506                                       currentString < policyFlags + policyLength;) {
507         int length;
508         PRBool unknown = PR_TRUE;
509         flag = secmod_ArgGetSubValue(currentString, ',', ':', &length,
510                                      &currentString);
511         if (length == 0) {
512             continue;
513         }
514         for (i = 0; i < PR_ARRAY_SIZE(policyFlagList); i++) {
515             const policyFlagDef *policy = &policyFlagList[i];
516             unsigned name_size = policy->name_size;
517             if ((policy->name_size == length) &&
518                 PORT_Strncasecmp(policy->name, flag, name_size) == 0) {
519                 flags |= policy->flag;
520                 unknown = PR_FALSE;
521                 break;
522             }
523         }
524         if (unknown && printPolicyFeedback) {
525             PR_SetEnv("NSS_POLICY_FAIL=1");
526             fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
527                     policyLength, policyFlags, length, flag);
528         }
529     }
530     return flags;
531 }
532 
533 /* allow symbolic names for values. The only ones currently defines or
534  * SSL protocol versions. */
535 static SECStatus
secmod_getPolicyOptValue(const char * policyValue,int policyValueLength,PRInt32 * result)536 secmod_getPolicyOptValue(const char *policyValue, int policyValueLength,
537                          PRInt32 *result)
538 {
539     PRInt32 val = atoi(policyValue);
540     int i;
541 
542     if ((val != 0) || (*policyValue == '0')) {
543         *result = val;
544         return SECSuccess;
545     }
546     for (i = 0; i < PR_ARRAY_SIZE(sslOptList); i++) {
547         if (policyValueLength == sslOptList[i].name_size &&
548             PORT_Strncasecmp(sslOptList[i].name, policyValue,
549                              sslOptList[i].name_size) == 0) {
550             *result = sslOptList[i].option;
551             return SECSuccess;
552         }
553     }
554     return SECFailure;
555 }
556 
557 /* Policy operations:
558  *     Disallow: operation is disallowed by policy. Implies disabled.
559  *     Allow: operation is allowed by policy (but could be disabled).
560  *     Disable: operation is turned off by default (but could be allowed).
561  *     Enable: operation is enabled by default. Implies allowed.
562  */
563 typedef enum {
564     NSS_DISALLOW,
565     NSS_ALLOW,
566     NSS_DISABLE,
567     NSS_ENABLE
568 } NSSPolicyOperation;
569 
570 /* apply the operator specific policy */
571 SECStatus
secmod_setPolicyOperation(SECOidTag oid,NSSPolicyOperation operation,PRUint32 value)572 secmod_setPolicyOperation(SECOidTag oid, NSSPolicyOperation operation,
573                           PRUint32 value)
574 {
575     SECStatus rv = SECSuccess;
576     switch (operation) {
577         case NSS_DISALLOW:
578             /* clear the requested policy bits */
579             rv = NSS_SetAlgorithmPolicy(oid, 0, value);
580             break;
581         case NSS_ALLOW:
582             /* set the requested policy bits */
583             rv = NSS_SetAlgorithmPolicy(oid, value, 0);
584             break;
585         /* enable/disable only apply to SSL cipher suites (future S/MIME).
586          * Enable/disable is implemented by clearing the DEFAULT_NOT_VALID
587          * flag, then setting the NSS_USE_DEFAULT_SSL_ENABLE flag to the
588          * correct value. The ssl policy code will then sort out what to
589          * set based on ciphers and cipher suite values.*/
590         case NSS_DISABLE:
591             if (value & (NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SSL_KX)) {
592                 /* clear not valid and enable */
593                 rv = NSS_SetAlgorithmPolicy(oid, 0,
594                                             NSS_USE_DEFAULT_NOT_VALID |
595                                                 NSS_USE_DEFAULT_SSL_ENABLE);
596             }
597             break;
598         case NSS_ENABLE:
599             if (value & (NSS_USE_ALG_IN_SSL | NSS_USE_ALG_IN_SSL_KX)) {
600                 /* set enable, clear not valid. NOTE: enable implies allow! */
601                 rv = NSS_SetAlgorithmPolicy(oid, value | NSS_USE_DEFAULT_SSL_ENABLE,
602                                             NSS_USE_DEFAULT_NOT_VALID);
603             }
604             break;
605         default:
606             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
607             rv = SECFailure;
608             break;
609     }
610     return rv;
611 }
612 
613 const char *
secmod_getOperationString(NSSPolicyOperation operation)614 secmod_getOperationString(NSSPolicyOperation operation)
615 {
616     switch (operation) {
617         case NSS_DISALLOW:
618             return "disallow";
619         case NSS_ALLOW:
620             return "allow";
621         case NSS_DISABLE:
622             return "disable";
623         case NSS_ENABLE:
624             return "enable";
625         default:
626             break;
627     }
628     return "invalid";
629 }
630 
631 static SECStatus
secmod_applyCryptoPolicy(const char * policyString,NSSPolicyOperation operation,PRBool printPolicyFeedback)632 secmod_applyCryptoPolicy(const char *policyString, NSSPolicyOperation operation,
633                          PRBool printPolicyFeedback)
634 {
635     const char *cipher, *currentString;
636     unsigned i, j;
637     SECStatus rv = SECSuccess;
638     PRBool unknown;
639 
640     if (policyString == NULL || policyString[0] == 0) {
641         return SECSuccess; /* do nothing */
642     }
643 
644     /* if we change any of these, make sure it gets applied in ssl as well */
645     NSS_SetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, NSS_USE_POLICY_IN_SSL, 0);
646 
647     for (currentString = policyString; currentString;) {
648         int length;
649         PRBool newValue = PR_FALSE;
650 
651         cipher = secmod_ArgGetSubValue(currentString, ':', 0, &length,
652                                        &currentString);
653         unknown = PR_TRUE;
654         if (length >= 3 && cipher[3] == '/') {
655             newValue = PR_TRUE;
656         }
657         if ((newValue || (length == 3)) && PORT_Strncasecmp(cipher, "all", 3) == 0) {
658             /* disable or enable all options by default */
659             PRUint32 value = 0;
660             if (newValue) {
661                 value = secmod_parsePolicyValue(&cipher[3] + 1, length - 3 - 1, printPolicyFeedback);
662             }
663             for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
664                 const algListsDef *algOptList = &algOptLists[i];
665                 for (j = 0; j < algOptList->entries; j++) {
666                     if (!newValue) {
667                         value = algOptList->list[j].val;
668                     }
669                     secmod_setPolicyOperation(algOptList->list[j].oid, operation, value);
670                 }
671             }
672             continue;
673         }
674 
675         for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
676             const algListsDef *algOptList = &algOptLists[i];
677             for (j = 0; j < algOptList->entries; j++) {
678                 const oidValDef *algOpt = &algOptList->list[j];
679                 unsigned name_size = algOpt->name_size;
680                 PRBool newOption = PR_FALSE;
681 
682                 if ((length >= name_size) && (cipher[name_size] == '/')) {
683                     newOption = PR_TRUE;
684                 }
685                 if ((newOption || algOpt->name_size == length) &&
686                     PORT_Strncasecmp(algOpt->name, cipher, name_size) == 0) {
687                     PRUint32 value = algOpt->val;
688                     if (newOption) {
689                         value = secmod_parsePolicyValue(&cipher[name_size] + 1,
690                                                         length - name_size - 1,
691                                                         printPolicyFeedback);
692                     }
693                     rv = secmod_setPolicyOperation(algOptList->list[j].oid, operation, value);
694                     if (rv != SECSuccess) {
695                         /* could not enable option */
696                         /* NSS_SetAlgorithPolicy should have set the error code */
697                         return SECFailure;
698                     }
699                     unknown = PR_FALSE;
700                     break;
701                 }
702             }
703         }
704         if (!unknown) {
705             continue;
706         }
707 
708         for (i = 0; i < PR_ARRAY_SIZE(freeOptList); i++) {
709             const optionFreeDef *freeOpt = &freeOptList[i];
710             unsigned name_size = freeOpt->name_size;
711 
712             if ((length > name_size) && cipher[name_size] == '=' &&
713                 PORT_Strncasecmp(freeOpt->name, cipher, name_size) == 0) {
714                 PRInt32 val;
715                 const char *policyValue = &cipher[name_size + 1];
716                 int policyValueLength = length - name_size - 1;
717                 rv = secmod_getPolicyOptValue(policyValue, policyValueLength,
718                                               &val);
719                 if (rv != SECSuccess) {
720                     if (printPolicyFeedback) {
721                         PR_SetEnv("NSS_POLICY_FAIL=1");
722                         fprintf(stderr, "NSS-POLICY-FAIL %.*s: unknown value: %.*s\n",
723                                 length, cipher, policyValueLength, policyValue);
724                     }
725                     return SECFailure;
726                 }
727                 rv = NSS_OptionSet(freeOpt->option, val);
728                 if (rv != SECSuccess) {
729                     /* could not enable option */
730                     /* NSS_OptionSet should have set the error code */
731                     return SECFailure;
732                 }
733                 /* to allow the policy to expand in the future. ignore ciphers
734                  * we don't understand */
735                 unknown = PR_FALSE;
736                 break;
737             }
738         }
739 
740         if (unknown && printPolicyFeedback) {
741             PR_SetEnv("NSS_POLICY_FAIL=1");
742             fprintf(stderr, "NSS-POLICY-FAIL %s: unknown identifier: %.*s\n",
743                     secmod_getOperationString(operation), length, cipher);
744         }
745     }
746     return rv;
747 }
748 
749 static void
secmod_sanityCheckCryptoPolicy(void)750 secmod_sanityCheckCryptoPolicy(void)
751 {
752     unsigned i, j;
753     SECStatus rv = SECSuccess;
754     unsigned num_kx_enabled = 0;
755     unsigned num_ssl_enabled = 0;
756     unsigned num_sig_enabled = 0;
757     unsigned enabledCount[PR_ARRAY_SIZE(algOptLists)];
758     const char *sWarn = "WARN";
759     const char *sInfo = "INFO";
760     PRBool haveWarning = PR_FALSE;
761 
762     for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
763         const algListsDef *algOptList = &algOptLists[i];
764         enabledCount[i] = 0;
765         for (j = 0; j < algOptList->entries; j++) {
766             const oidValDef *algOpt = &algOptList->list[j];
767             PRUint32 value;
768             PRBool anyEnabled = PR_FALSE;
769             rv = NSS_GetAlgorithmPolicy(algOpt->oid, &value);
770             if (rv != SECSuccess) {
771                 PR_SetEnv("NSS_POLICY_FAIL=1");
772                 fprintf(stderr, "NSS-POLICY-FAIL: internal failure with NSS_GetAlgorithmPolicy at %u\n", i);
773                 return;
774             }
775 
776             if ((algOpt->val & NSS_USE_ALG_IN_SSL_KX) && (value & NSS_USE_ALG_IN_SSL_KX)) {
777                 ++num_kx_enabled;
778                 anyEnabled = PR_TRUE;
779                 fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for KX\n", algOpt->name);
780             }
781             if ((algOpt->val & NSS_USE_ALG_IN_SSL) && (value & NSS_USE_ALG_IN_SSL)) {
782                 ++num_ssl_enabled;
783                 anyEnabled = PR_TRUE;
784                 fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for SSL\n", algOpt->name);
785             }
786             if ((algOpt->val & NSS_USE_ALG_IN_CERT_SIGNATURE) &&
787                 ((value & NSS_USE_CERT_SIGNATURE_OK) == NSS_USE_CERT_SIGNATURE_OK)) {
788                 ++num_sig_enabled;
789                 anyEnabled = PR_TRUE;
790                 fprintf(stderr, "NSS-POLICY-INFO: %s is enabled for CERT-SIGNATURE\n", algOpt->name);
791             }
792             if (anyEnabled) {
793                 ++enabledCount[i];
794             }
795         }
796     }
797     fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG-KX: %u\n", num_kx_enabled ? sInfo : sWarn, num_kx_enabled);
798     fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-SSL-ALG: %u\n", num_ssl_enabled ? sInfo : sWarn, num_ssl_enabled);
799     fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-CERT-SIG: %u\n", num_sig_enabled ? sInfo : sWarn, num_sig_enabled);
800     if (!num_kx_enabled || !num_ssl_enabled || !num_sig_enabled) {
801         haveWarning = PR_TRUE;
802     }
803     for (i = 0; i < PR_ARRAY_SIZE(algOptLists); i++) {
804         const algListsDef *algOptList = &algOptLists[i];
805         fprintf(stderr, "NSS-POLICY-%s: NUMBER-OF-%s: %u\n", enabledCount[i] ? sInfo : sWarn, algOptList->description, enabledCount[i]);
806         if (!enabledCount[i] && !algOptList->allowEmpty) {
807             haveWarning = PR_TRUE;
808         }
809     }
810     if (haveWarning) {
811         PR_SetEnv("NSS_POLICY_WARN=1");
812     }
813 }
814 
815 static SECStatus
secmod_parseCryptoPolicy(const char * policyConfig,PRBool printPolicyFeedback)816 secmod_parseCryptoPolicy(const char *policyConfig, PRBool printPolicyFeedback)
817 {
818     char *args;
819     SECStatus rv;
820 
821     if (policyConfig == NULL) {
822         return SECSuccess; /* no policy given */
823     }
824     /* make sure we initialize the oid table and set all the default policy
825      * values first so we can override them here */
826     rv = SECOID_Init();
827     if (rv != SECSuccess) {
828         return rv;
829     }
830     args = NSSUTIL_ArgGetParamValue("disallow", policyConfig);
831     rv = secmod_applyCryptoPolicy(args, NSS_DISALLOW, printPolicyFeedback);
832     if (args)
833         PORT_Free(args);
834     if (rv != SECSuccess) {
835         return rv;
836     }
837     args = NSSUTIL_ArgGetParamValue("allow", policyConfig);
838     rv = secmod_applyCryptoPolicy(args, NSS_ALLOW, printPolicyFeedback);
839     if (args)
840         PORT_Free(args);
841     if (rv != SECSuccess) {
842         return rv;
843     }
844     args = NSSUTIL_ArgGetParamValue("disable", policyConfig);
845     rv = secmod_applyCryptoPolicy(args, NSS_DISABLE, printPolicyFeedback);
846     if (args)
847         PORT_Free(args);
848     if (rv != SECSuccess) {
849         return rv;
850     }
851     args = NSSUTIL_ArgGetParamValue("enable", policyConfig);
852     rv = secmod_applyCryptoPolicy(args, NSS_ENABLE, printPolicyFeedback);
853     if (args)
854         PORT_Free(args);
855     if (rv != SECSuccess) {
856         return rv;
857     }
858     /* this has to be last. Everything after this will be a noop */
859     if (NSSUTIL_ArgHasFlag("flags", "ssl-lock", policyConfig)) {
860         PRInt32 locks;
861         /* don't overwrite other (future) lock flags */
862         rv = NSS_OptionGet(NSS_DEFAULT_LOCKS, &locks);
863         if (rv == SECSuccess) {
864             rv = NSS_OptionSet(NSS_DEFAULT_LOCKS, locks | NSS_DEFAULT_SSL_LOCK);
865         }
866         if (rv != SECSuccess) {
867             return rv;
868         }
869     }
870     if (NSSUTIL_ArgHasFlag("flags", "policy-lock", policyConfig)) {
871         NSS_LockPolicy();
872     }
873     if (printPolicyFeedback) {
874         /* This helps to distinguish configurations that don't contain any
875          * policy config= statement. */
876         PR_SetEnv("NSS_POLICY_LOADED=1");
877         fprintf(stderr, "NSS-POLICY-INFO: LOADED-SUCCESSFULLY\n");
878         secmod_sanityCheckCryptoPolicy();
879     }
880     return rv;
881 }
882 
883 /*
884  * for 3.4 we continue to use the old SECMODModule structure
885  */
886 SECMODModule *
SECMOD_CreateModuleEx(const char * library,const char * moduleName,const char * parameters,const char * nss,const char * config)887 SECMOD_CreateModuleEx(const char *library, const char *moduleName,
888                       const char *parameters, const char *nss,
889                       const char *config)
890 {
891     SECMODModule *mod;
892     SECStatus rv;
893     char *slotParams, *ciphers;
894     /* pk11pars.h still does not have const char * interfaces */
895     char *nssc = (char *)nss;
896     PRBool printPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nssc);
897 
898     rv = secmod_parseCryptoPolicy(config, printPolicyFeedback);
899 
900     /* do not load the module if policy parsing fails */
901     if (rv != SECSuccess) {
902         if (printPolicyFeedback) {
903             PR_SetEnv("NSS_POLICY_FAIL=1");
904             fprintf(stderr, "NSS-POLICY-FAIL: policy config parsing failed, not loading module %s\n", moduleName);
905         }
906         return NULL;
907     }
908 
909     mod = secmod_NewModule();
910     if (mod == NULL)
911         return NULL;
912 
913     mod->commonName = PORT_ArenaStrdup(mod->arena, moduleName ? moduleName : "");
914     if (library) {
915         mod->dllName = PORT_ArenaStrdup(mod->arena, library);
916     }
917     /* new field */
918     if (parameters) {
919         mod->libraryParams = PORT_ArenaStrdup(mod->arena, parameters);
920     }
921 
922     mod->internal = NSSUTIL_ArgHasFlag("flags", "internal", nssc);
923     mod->isFIPS = NSSUTIL_ArgHasFlag("flags", "FIPS", nssc);
924     /* if the system FIPS mode is enabled, force FIPS to be on */
925     if (SECMOD_GetSystemFIPSEnabled()) {
926         mod->isFIPS = PR_TRUE;
927     }
928     mod->isCritical = NSSUTIL_ArgHasFlag("flags", "critical", nssc);
929     slotParams = NSSUTIL_ArgGetParamValue("slotParams", nssc);
930     mod->slotInfo = NSSUTIL_ArgParseSlotInfo(mod->arena, slotParams,
931                                              &mod->slotInfoCount);
932     if (slotParams)
933         PORT_Free(slotParams);
934     /* new field */
935     mod->trustOrder = NSSUTIL_ArgReadLong("trustOrder", nssc,
936                                           NSSUTIL_DEFAULT_TRUST_ORDER, NULL);
937     /* new field */
938     mod->cipherOrder = NSSUTIL_ArgReadLong("cipherOrder", nssc,
939                                            NSSUTIL_DEFAULT_CIPHER_ORDER, NULL);
940     /* new field */
941     mod->isModuleDB = NSSUTIL_ArgHasFlag("flags", "moduleDB", nssc);
942     mod->moduleDBOnly = NSSUTIL_ArgHasFlag("flags", "moduleDBOnly", nssc);
943     if (mod->moduleDBOnly)
944         mod->isModuleDB = PR_TRUE;
945 
946     /* we need more bits, but we also want to preserve binary compatibility
947      * so we overload the isModuleDB PRBool with additional flags.
948      * These flags are only valid if mod->isModuleDB is already set.
949      * NOTE: this depends on the fact that PRBool is at least a char on
950      * all platforms. These flags are only valid if moduleDB is set, so
951      * code checking if (mod->isModuleDB) will continue to work correctly. */
952     if (mod->isModuleDB) {
953         char flags = SECMOD_FLAG_MODULE_DB_IS_MODULE_DB;
954         if (NSSUTIL_ArgHasFlag("flags", "skipFirst", nssc)) {
955             flags |= SECMOD_FLAG_MODULE_DB_SKIP_FIRST;
956         }
957         if (NSSUTIL_ArgHasFlag("flags", "defaultModDB", nssc)) {
958             flags |= SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB;
959         }
960         if (NSSUTIL_ArgHasFlag("flags", "policyOnly", nssc)) {
961             flags |= SECMOD_FLAG_MODULE_DB_POLICY_ONLY;
962         }
963         /* additional moduleDB flags could be added here in the future */
964         mod->isModuleDB = (PRBool)flags;
965     }
966 
967     if (mod->internal) {
968         char flags = SECMOD_FLAG_INTERNAL_IS_INTERNAL;
969 
970         if (NSSUTIL_ArgHasFlag("flags", "internalKeySlot", nssc)) {
971             flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
972         }
973         mod->internal = (PRBool)flags;
974     }
975 
976     ciphers = NSSUTIL_ArgGetParamValue("ciphers", nssc);
977     NSSUTIL_ArgParseCipherFlags(&mod->ssl[0], ciphers);
978     if (ciphers)
979         PORT_Free(ciphers);
980 
981     secmod_PrivateModuleCount++;
982 
983     return mod;
984 }
985 
986 PRBool
SECMOD_GetSkipFirstFlag(SECMODModule * mod)987 SECMOD_GetSkipFirstFlag(SECMODModule *mod)
988 {
989     char flags = (char)mod->isModuleDB;
990 
991     return (flags & SECMOD_FLAG_MODULE_DB_SKIP_FIRST) ? PR_TRUE : PR_FALSE;
992 }
993 
994 PRBool
SECMOD_GetDefaultModDBFlag(SECMODModule * mod)995 SECMOD_GetDefaultModDBFlag(SECMODModule *mod)
996 {
997     char flags = (char)mod->isModuleDB;
998 
999     return (flags & SECMOD_FLAG_MODULE_DB_DEFAULT_MODDB) ? PR_TRUE : PR_FALSE;
1000 }
1001 
1002 PRBool
secmod_PolicyOnly(SECMODModule * mod)1003 secmod_PolicyOnly(SECMODModule *mod)
1004 {
1005     char flags = (char)mod->isModuleDB;
1006 
1007     return (flags & SECMOD_FLAG_MODULE_DB_POLICY_ONLY) ? PR_TRUE : PR_FALSE;
1008 }
1009 
1010 PRBool
secmod_IsInternalKeySlot(SECMODModule * mod)1011 secmod_IsInternalKeySlot(SECMODModule *mod)
1012 {
1013     char flags = (char)mod->internal;
1014 
1015     return (flags & SECMOD_FLAG_INTERNAL_KEY_SLOT) ? PR_TRUE : PR_FALSE;
1016 }
1017 
1018 void
secmod_SetInternalKeySlotFlag(SECMODModule * mod,PRBool val)1019 secmod_SetInternalKeySlotFlag(SECMODModule *mod, PRBool val)
1020 {
1021     char flags = (char)mod->internal;
1022 
1023     if (val) {
1024         flags |= SECMOD_FLAG_INTERNAL_KEY_SLOT;
1025     } else {
1026         flags &= ~SECMOD_FLAG_INTERNAL_KEY_SLOT;
1027     }
1028     mod->internal = flags;
1029 }
1030 
1031 /*
1032  * copy desc and value into target. Target is known to be big enough to
1033  * hold desc +2 +value, which is good because the result of this will be
1034  * *desc"*value". We may, however, have to add some escapes for special
1035  * characters imbedded into value (rare). This string potentially comes from
1036  * a user, so we don't want the user overflowing the target buffer by using
1037  * excessive escapes. To prevent this we count the escapes we need to add and
1038  * try to expand the buffer with Realloc.
1039  */
1040 static char *
secmod_doDescCopy(char * target,char ** base,int * baseLen,const char * desc,int descLen,char * value)1041 secmod_doDescCopy(char *target, char **base, int *baseLen,
1042                   const char *desc, int descLen, char *value)
1043 {
1044     int diff, esc_len;
1045 
1046     esc_len = NSSUTIL_EscapeSize(value, '\"') - 1;
1047     diff = esc_len - strlen(value);
1048     if (diff > 0) {
1049         /* we need to escape... expand newSpecPtr as well to make sure
1050          * we don't overflow it */
1051         int offset = target - *base;
1052         char *newPtr = PORT_Realloc(*base, *baseLen + diff);
1053         if (!newPtr) {
1054             return target; /* not enough space, just drop the whole copy */
1055         }
1056         *baseLen += diff;
1057         target = newPtr + offset;
1058         *base = newPtr;
1059         value = NSSUTIL_Escape(value, '\"');
1060         if (value == NULL) {
1061             return target; /* couldn't escape value, just drop the copy */
1062         }
1063     }
1064     PORT_Memcpy(target, desc, descLen);
1065     target += descLen;
1066     *target++ = '\"';
1067     PORT_Memcpy(target, value, esc_len);
1068     target += esc_len;
1069     *target++ = '\"';
1070     if (diff > 0) {
1071         PORT_Free(value);
1072     }
1073     return target;
1074 }
1075 
1076 #define SECMOD_SPEC_COPY(new, start, end) \
1077     if (end > start) {                    \
1078         int _cnt = end - start;           \
1079         PORT_Memcpy(new, start, _cnt);    \
1080         new += _cnt;                      \
1081     }
1082 #define SECMOD_TOKEN_DESCRIPTION "tokenDescription="
1083 #define SECMOD_SLOT_DESCRIPTION "slotDescription="
1084 
1085 /*
1086  * Find any tokens= values in the module spec.
1087  * Always return a new spec which does not have any tokens= arguments.
1088  * If tokens= arguments are found, Split the the various tokens defined into
1089  * an array of child specs to return.
1090  *
1091  * Caller is responsible for freeing the child spec and the new token
1092  * spec.
1093  */
1094 char *
secmod_ParseModuleSpecForTokens(PRBool convert,PRBool isFIPS,const char * moduleSpec,char *** children,CK_SLOT_ID ** ids)1095 secmod_ParseModuleSpecForTokens(PRBool convert, PRBool isFIPS,
1096                                 const char *moduleSpec, char ***children,
1097                                 CK_SLOT_ID **ids)
1098 {
1099     int newSpecLen = PORT_Strlen(moduleSpec) + 2;
1100     char *newSpec = PORT_Alloc(newSpecLen);
1101     char *newSpecPtr = newSpec;
1102     const char *modulePrev = moduleSpec;
1103     char *target = NULL;
1104     char *tmp = NULL;
1105     char **childArray = NULL;
1106     const char *tokenIndex;
1107     CK_SLOT_ID *idArray = NULL;
1108     int tokenCount = 0;
1109     int i;
1110 
1111     if (newSpec == NULL) {
1112         return NULL;
1113     }
1114 
1115     *children = NULL;
1116     if (ids) {
1117         *ids = NULL;
1118     }
1119     moduleSpec = NSSUTIL_ArgStrip(moduleSpec);
1120     SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
1121 
1122     /* Notes on 'convert' and 'isFIPS' flags: The base parameters for opening
1123      * a new softoken module takes the following parameters to name the
1124      * various tokens:
1125      *
1126      *  cryptoTokenDescription: name of the non-fips crypto token.
1127      *  cryptoSlotDescription: name of the non-fips crypto slot.
1128      *  dbTokenDescription: name of the non-fips db token.
1129      *  dbSlotDescription: name of the non-fips db slot.
1130      *  FIPSTokenDescription: name of the fips db/crypto token.
1131      *  FIPSSlotDescription: name of the fips db/crypto slot.
1132      *
1133      * if we are opening a new slot, we need to have the following
1134      * parameters:
1135      *  tokenDescription: name of the token.
1136      *  slotDescription: name of the slot.
1137      *
1138      *
1139      * The convert flag tells us to drop the unnecessary *TokenDescription
1140      * and *SlotDescription arguments and convert the appropriate pair
1141      * (either db or FIPS based on the isFIPS flag) to tokenDescription and
1142      * slotDescription).
1143      */
1144     /*
1145      * walk down the list. if we find a tokens= argument, save it,
1146      * otherise copy the argument.
1147      */
1148     while (*moduleSpec) {
1149         int next;
1150         modulePrev = moduleSpec;
1151         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, target, "tokens=",
1152                                   modulePrev = moduleSpec;
1153                                   /* skip copying */)
1154         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoTokenDescription=",
1155                                   if (convert) { modulePrev = moduleSpec; });
1156         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "cryptoSlotDescription=",
1157                                   if (convert) { modulePrev = moduleSpec; });
1158         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "dbTokenDescription=",
1159                                   if (convert) {
1160                                       modulePrev = moduleSpec;
1161                                       if (!isFIPS) {
1162                                           newSpecPtr = secmod_doDescCopy(newSpecPtr,
1163                                                                          &newSpec, &newSpecLen,
1164                                                                          SECMOD_TOKEN_DESCRIPTION,
1165                                                                          sizeof(SECMOD_TOKEN_DESCRIPTION) - 1,
1166                                                                          tmp);
1167                                       }
1168                                   });
1169         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "dbSlotDescription=",
1170                                   if (convert) {
1171                                       modulePrev = moduleSpec; /* skip copying */
1172                                       if (!isFIPS) {
1173                                           newSpecPtr = secmod_doDescCopy(newSpecPtr,
1174                                                                          &newSpec, &newSpecLen,
1175                                                                          SECMOD_SLOT_DESCRIPTION,
1176                                                                          sizeof(SECMOD_SLOT_DESCRIPTION) - 1,
1177                                                                          tmp);
1178                                       }
1179                                   });
1180         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSTokenDescription=",
1181                                   if (convert) {
1182                                       modulePrev = moduleSpec; /* skip copying */
1183                                       if (isFIPS) {
1184                                           newSpecPtr = secmod_doDescCopy(newSpecPtr,
1185                                                                          &newSpec, &newSpecLen,
1186                                                                          SECMOD_TOKEN_DESCRIPTION,
1187                                                                          sizeof(SECMOD_TOKEN_DESCRIPTION) - 1,
1188                                                                          tmp);
1189                                       }
1190                                   });
1191         NSSUTIL_HANDLE_STRING_ARG(moduleSpec, tmp, "FIPSSlotDescription=",
1192                                   if (convert) {
1193                                       modulePrev = moduleSpec; /* skip copying */
1194                                       if (isFIPS) {
1195                                           newSpecPtr = secmod_doDescCopy(newSpecPtr,
1196                                                                          &newSpec, &newSpecLen,
1197                                                                          SECMOD_SLOT_DESCRIPTION,
1198                                                                          sizeof(SECMOD_SLOT_DESCRIPTION) - 1,
1199                                                                          tmp);
1200                                       }
1201                                   });
1202         NSSUTIL_HANDLE_FINAL_ARG(moduleSpec)
1203         SECMOD_SPEC_COPY(newSpecPtr, modulePrev, moduleSpec);
1204     }
1205     if (tmp) {
1206         PORT_Free(tmp);
1207         tmp = NULL;
1208     }
1209     *newSpecPtr = 0;
1210 
1211     /* no target found, return the newSpec */
1212     if (target == NULL) {
1213         return newSpec;
1214     }
1215 
1216     /* now build the child array from target */
1217     /*first count them */
1218     for (tokenIndex = NSSUTIL_ArgStrip(target); *tokenIndex;
1219          tokenIndex = NSSUTIL_ArgStrip(NSSUTIL_ArgSkipParameter(tokenIndex))) {
1220         tokenCount++;
1221     }
1222 
1223     childArray = PORT_NewArray(char *, tokenCount + 1);
1224     if (childArray == NULL) {
1225         /* just return the spec as is then */
1226         PORT_Free(target);
1227         return newSpec;
1228     }
1229     if (ids) {
1230         idArray = PORT_NewArray(CK_SLOT_ID, tokenCount + 1);
1231         if (idArray == NULL) {
1232             PORT_Free(childArray);
1233             PORT_Free(target);
1234             return newSpec;
1235         }
1236     }
1237 
1238     /* now fill them in */
1239     for (tokenIndex = NSSUTIL_ArgStrip(target), i = 0;
1240          *tokenIndex && (i < tokenCount);
1241          tokenIndex = NSSUTIL_ArgStrip(tokenIndex)) {
1242         int next;
1243         char *name = NSSUTIL_ArgGetLabel(tokenIndex, &next);
1244         tokenIndex += next;
1245 
1246         if (idArray) {
1247             idArray[i] = NSSUTIL_ArgDecodeNumber(name);
1248         }
1249 
1250         PORT_Free(name); /* drop the explicit number */
1251 
1252         /* if anything is left, copy the args to the child array */
1253         if (!NSSUTIL_ArgIsBlank(*tokenIndex)) {
1254             childArray[i++] = NSSUTIL_ArgFetchValue(tokenIndex, &next);
1255             tokenIndex += next;
1256         }
1257     }
1258 
1259     PORT_Free(target);
1260     childArray[i] = 0;
1261     if (idArray) {
1262         idArray[i] = 0;
1263     }
1264 
1265     /* return it */
1266     *children = childArray;
1267     if (ids) {
1268         *ids = idArray;
1269     }
1270     return newSpec;
1271 }
1272 
1273 /* get the database and flags from the spec */
1274 static char *
secmod_getConfigDir(const char * spec,char ** certPrefix,char ** keyPrefix,PRBool * readOnly)1275 secmod_getConfigDir(const char *spec, char **certPrefix, char **keyPrefix,
1276                     PRBool *readOnly)
1277 {
1278     char *config = NULL;
1279 
1280     *certPrefix = NULL;
1281     *keyPrefix = NULL;
1282     *readOnly = NSSUTIL_ArgHasFlag("flags", "readOnly", spec);
1283     if (NSSUTIL_ArgHasFlag("flags", "nocertdb", spec) ||
1284         NSSUTIL_ArgHasFlag("flags", "nokeydb", spec)) {
1285         return NULL;
1286     }
1287 
1288     spec = NSSUTIL_ArgStrip(spec);
1289     while (*spec) {
1290         int next;
1291         NSSUTIL_HANDLE_STRING_ARG(spec, config, "configdir=", ;)
1292         NSSUTIL_HANDLE_STRING_ARG(spec, *certPrefix, "certPrefix=", ;)
1293         NSSUTIL_HANDLE_STRING_ARG(spec, *keyPrefix, "keyPrefix=", ;)
1294         NSSUTIL_HANDLE_FINAL_ARG(spec)
1295     }
1296     return config;
1297 }
1298 
1299 struct SECMODConfigListStr {
1300     char *config;
1301     char *certPrefix;
1302     char *keyPrefix;
1303     PRBool isReadOnly;
1304 };
1305 
1306 /*
1307  * return an array of already openned databases from a spec list.
1308  */
1309 SECMODConfigList *
secmod_GetConfigList(PRBool isFIPS,char * spec,int * count)1310 secmod_GetConfigList(PRBool isFIPS, char *spec, int *count)
1311 {
1312     char **children;
1313     CK_SLOT_ID *ids;
1314     char *strippedSpec;
1315     int childCount;
1316     SECMODConfigList *conflist = NULL;
1317     int i;
1318 
1319     strippedSpec = secmod_ParseModuleSpecForTokens(PR_TRUE, isFIPS,
1320                                                    spec, &children, &ids);
1321     if (strippedSpec == NULL) {
1322         return NULL;
1323     }
1324 
1325     for (childCount = 0; children && children[childCount]; childCount++)
1326         ;
1327     *count = childCount + 1; /* include strippedSpec */
1328     conflist = PORT_NewArray(SECMODConfigList, *count);
1329     if (conflist == NULL) {
1330         *count = 0;
1331         goto loser;
1332     }
1333 
1334     conflist[0].config = secmod_getConfigDir(strippedSpec,
1335                                              &conflist[0].certPrefix,
1336                                              &conflist[0].keyPrefix,
1337                                              &conflist[0].isReadOnly);
1338     for (i = 0; i < childCount; i++) {
1339         conflist[i + 1].config = secmod_getConfigDir(children[i],
1340                                                      &conflist[i + 1].certPrefix,
1341                                                      &conflist[i + 1].keyPrefix,
1342                                                      &conflist[i + 1].isReadOnly);
1343     }
1344 
1345 loser:
1346     secmod_FreeChildren(children, ids);
1347     PORT_Free(strippedSpec);
1348     return conflist;
1349 }
1350 
1351 /*
1352  * determine if we are trying to open an old dbm database. For this test
1353  * RDB databases should return PR_FALSE.
1354  */
1355 static PRBool
secmod_configIsDBM(char * configDir)1356 secmod_configIsDBM(char *configDir)
1357 {
1358     char *env;
1359 
1360     /* explicit dbm open */
1361     if (strncmp(configDir, "dbm:", 4) == 0) {
1362         return PR_TRUE;
1363     }
1364     /* explicit open of a non-dbm database */
1365     if ((strncmp(configDir, "sql:", 4) == 0) ||
1366         (strncmp(configDir, "rdb:", 4) == 0) ||
1367         (strncmp(configDir, "extern:", 7) == 0)) {
1368         return PR_FALSE;
1369     }
1370     env = PR_GetEnvSecure("NSS_DEFAULT_DB_TYPE");
1371     /* implicit dbm open */
1372     if ((env == NULL) || (strcmp(env, "dbm") == 0)) {
1373         return PR_TRUE;
1374     }
1375     /* implicit non-dbm open */
1376     return PR_FALSE;
1377 }
1378 
1379 /*
1380  * match two prefixes. prefix may be NULL. NULL patches '\0'
1381  */
1382 static PRBool
secmod_matchPrefix(char * prefix1,char * prefix2)1383 secmod_matchPrefix(char *prefix1, char *prefix2)
1384 {
1385     if ((prefix1 == NULL) || (*prefix1 == 0)) {
1386         if ((prefix2 == NULL) || (*prefix2 == 0)) {
1387             return PR_TRUE;
1388         }
1389         return PR_FALSE;
1390     }
1391     if (strcmp(prefix1, prefix2) == 0) {
1392         return PR_TRUE;
1393     }
1394     return PR_FALSE;
1395 }
1396 
1397 /* do two config paramters match? Not all callers are compariing
1398  * SECMODConfigLists directly, so this function breaks them out to their
1399  * components. */
1400 static PRBool
secmod_matchConfig(char * configDir1,char * configDir2,char * certPrefix1,char * certPrefix2,char * keyPrefix1,char * keyPrefix2,PRBool isReadOnly1,PRBool isReadOnly2)1401 secmod_matchConfig(char *configDir1, char *configDir2,
1402                    char *certPrefix1, char *certPrefix2,
1403                    char *keyPrefix1, char *keyPrefix2,
1404                    PRBool isReadOnly1, PRBool isReadOnly2)
1405 {
1406     /* TODO: Document the answer to the question:
1407      *       "Why not allow them to match if they are both NULL?"
1408      * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1318633#c1
1409      */
1410     if ((configDir1 == NULL) || (configDir2 == NULL)) {
1411         return PR_FALSE;
1412     }
1413     if (strcmp(configDir1, configDir2) != 0) {
1414         return PR_FALSE;
1415     }
1416     if (!secmod_matchPrefix(certPrefix1, certPrefix2)) {
1417         return PR_FALSE;
1418     }
1419     if (!secmod_matchPrefix(keyPrefix1, keyPrefix2)) {
1420         return PR_FALSE;
1421     }
1422     /* these last test -- if we just need the DB open read only,
1423      * than any open will suffice, but if we requested it read/write
1424      * and it's only open read only, we need to open it again */
1425     if (isReadOnly1) {
1426         return PR_TRUE;
1427     }
1428     if (isReadOnly2) { /* isReadonly1 == PR_FALSE */
1429         return PR_FALSE;
1430     }
1431     return PR_TRUE;
1432 }
1433 
1434 /*
1435  * return true if we are requesting a database that is already openned.
1436  */
1437 PRBool
secmod_MatchConfigList(const char * spec,SECMODConfigList * conflist,int count)1438 secmod_MatchConfigList(const char *spec, SECMODConfigList *conflist, int count)
1439 {
1440     char *config;
1441     char *certPrefix;
1442     char *keyPrefix;
1443     PRBool isReadOnly;
1444     PRBool ret = PR_FALSE;
1445     int i;
1446 
1447     config = secmod_getConfigDir(spec, &certPrefix, &keyPrefix, &isReadOnly);
1448     if (!config) {
1449         goto done;
1450     }
1451 
1452     /* NOTE: we dbm isn't multiple open safe. If we open the same database
1453      * twice from two different locations, then we can corrupt our database
1454      * (the cache will be inconsistent). Protect against this by claiming
1455      * for comparison only that we are always openning dbm databases read only.
1456      */
1457     if (secmod_configIsDBM(config)) {
1458         isReadOnly = 1;
1459     }
1460     for (i = 0; i < count; i++) {
1461         if (secmod_matchConfig(config, conflist[i].config, certPrefix,
1462                                conflist[i].certPrefix, keyPrefix,
1463                                conflist[i].keyPrefix, isReadOnly,
1464                                conflist[i].isReadOnly)) {
1465             ret = PR_TRUE;
1466             goto done;
1467         }
1468     }
1469 
1470     ret = PR_FALSE;
1471 done:
1472     PORT_Free(config);
1473     PORT_Free(certPrefix);
1474     PORT_Free(keyPrefix);
1475     return ret;
1476 }
1477 
1478 /*
1479  * Find the slot id from the module spec. If the slot is the database slot, we
1480  * can get the slot id from the default database slot.
1481  */
1482 CK_SLOT_ID
secmod_GetSlotIDFromModuleSpec(const char * moduleSpec,SECMODModule * module)1483 secmod_GetSlotIDFromModuleSpec(const char *moduleSpec, SECMODModule *module)
1484 {
1485     char *tmp_spec = NULL;
1486     char **children, **thisChild;
1487     CK_SLOT_ID *ids, *thisID, slotID = -1;
1488     char *inConfig = NULL, *thisConfig = NULL;
1489     char *inCertPrefix = NULL, *thisCertPrefix = NULL;
1490     char *inKeyPrefix = NULL, *thisKeyPrefix = NULL;
1491     PRBool inReadOnly, thisReadOnly;
1492 
1493     inConfig = secmod_getConfigDir(moduleSpec, &inCertPrefix, &inKeyPrefix,
1494                                    &inReadOnly);
1495     if (!inConfig) {
1496         goto done;
1497     }
1498 
1499     if (secmod_configIsDBM(inConfig)) {
1500         inReadOnly = 1;
1501     }
1502 
1503     tmp_spec = secmod_ParseModuleSpecForTokens(PR_TRUE, module->isFIPS,
1504                                                module->libraryParams, &children, &ids);
1505     if (tmp_spec == NULL) {
1506         goto done;
1507     }
1508 
1509     /* first check to see if the parent is the database */
1510     thisConfig = secmod_getConfigDir(tmp_spec, &thisCertPrefix, &thisKeyPrefix,
1511                                      &thisReadOnly);
1512     if (!thisConfig) {
1513         goto done;
1514     }
1515     if (secmod_matchConfig(inConfig, thisConfig, inCertPrefix, thisCertPrefix,
1516                            inKeyPrefix, thisKeyPrefix, inReadOnly, thisReadOnly)) {
1517         /* yup it's the default key slot, get the id for it */
1518         PK11SlotInfo *slot = PK11_GetInternalKeySlot();
1519         if (slot) {
1520             slotID = slot->slotID;
1521             PK11_FreeSlot(slot);
1522         }
1523         goto done;
1524     }
1525 
1526     /* find id of the token */
1527     for (thisChild = children, thisID = ids; thisChild && *thisChild; thisChild++, thisID++) {
1528         PORT_Free(thisConfig);
1529         PORT_Free(thisCertPrefix);
1530         PORT_Free(thisKeyPrefix);
1531         thisConfig = secmod_getConfigDir(*thisChild, &thisCertPrefix,
1532                                          &thisKeyPrefix, &thisReadOnly);
1533         if (thisConfig == NULL) {
1534             continue;
1535         }
1536         if (secmod_matchConfig(inConfig, thisConfig, inCertPrefix, thisCertPrefix,
1537                                inKeyPrefix, thisKeyPrefix, inReadOnly, thisReadOnly)) {
1538             slotID = *thisID;
1539             break;
1540         }
1541     }
1542 
1543 done:
1544     PORT_Free(inConfig);
1545     PORT_Free(inCertPrefix);
1546     PORT_Free(inKeyPrefix);
1547     PORT_Free(thisConfig);
1548     PORT_Free(thisCertPrefix);
1549     PORT_Free(thisKeyPrefix);
1550     if (tmp_spec) {
1551         secmod_FreeChildren(children, ids);
1552         PORT_Free(tmp_spec);
1553     }
1554     return slotID;
1555 }
1556 
1557 void
secmod_FreeConfigList(SECMODConfigList * conflist,int count)1558 secmod_FreeConfigList(SECMODConfigList *conflist, int count)
1559 {
1560     int i;
1561     for (i = 0; i < count; i++) {
1562         PORT_Free(conflist[i].config);
1563         PORT_Free(conflist[i].certPrefix);
1564         PORT_Free(conflist[i].keyPrefix);
1565     }
1566     PORT_Free(conflist);
1567 }
1568 
1569 void
secmod_FreeChildren(char ** children,CK_SLOT_ID * ids)1570 secmod_FreeChildren(char **children, CK_SLOT_ID *ids)
1571 {
1572     char **thisChild;
1573 
1574     if (!children) {
1575         return;
1576     }
1577 
1578     for (thisChild = children; thisChild && *thisChild; thisChild++) {
1579         PORT_Free(*thisChild);
1580     }
1581     PORT_Free(children);
1582     if (ids) {
1583         PORT_Free(ids);
1584     }
1585     return;
1586 }
1587 
1588 /*
1589  * caclulate the length of each child record:
1590  * " 0x{id}=<{escaped_child}>"
1591  */
1592 static int
secmod_getChildLength(char * child,CK_SLOT_ID id)1593 secmod_getChildLength(char *child, CK_SLOT_ID id)
1594 {
1595     int length = NSSUTIL_DoubleEscapeSize(child, '>', ']');
1596     if (id == 0) {
1597         length++;
1598     }
1599     while (id) {
1600         length++;
1601         id = id >> 4;
1602     }
1603     length += 6; /* {sp}0x[id]=<{child}> */
1604     return length;
1605 }
1606 
1607 /*
1608  * Build a child record:
1609  * " 0x{id}=<{escaped_child}>"
1610  */
1611 static SECStatus
secmod_mkTokenChild(char ** next,int * length,char * child,CK_SLOT_ID id)1612 secmod_mkTokenChild(char **next, int *length, char *child, CK_SLOT_ID id)
1613 {
1614     int len;
1615     char *escSpec;
1616 
1617     len = PR_snprintf(*next, *length, " 0x%x=<", id);
1618     if (len < 0) {
1619         return SECFailure;
1620     }
1621     *next += len;
1622     *length -= len;
1623     escSpec = NSSUTIL_DoubleEscape(child, '>', ']');
1624     if (escSpec == NULL) {
1625         return SECFailure;
1626     }
1627     if (*child && (*escSpec == 0)) {
1628         PORT_Free(escSpec);
1629         return SECFailure;
1630     }
1631     len = strlen(escSpec);
1632     if (len + 1 > *length) {
1633         PORT_Free(escSpec);
1634         return SECFailure;
1635     }
1636     PORT_Memcpy(*next, escSpec, len);
1637     *next += len;
1638     *length -= len;
1639     PORT_Free(escSpec);
1640     **next = '>';
1641     (*next)++;
1642     (*length)--;
1643     return SECSuccess;
1644 }
1645 
1646 #define TOKEN_STRING " tokens=["
1647 
1648 char *
secmod_MkAppendTokensList(PLArenaPool * arena,char * oldParam,char * newToken,CK_SLOT_ID newID,char ** children,CK_SLOT_ID * ids)1649 secmod_MkAppendTokensList(PLArenaPool *arena, char *oldParam, char *newToken,
1650                           CK_SLOT_ID newID, char **children, CK_SLOT_ID *ids)
1651 {
1652     char *rawParam = NULL;  /* oldParam with tokens stripped off */
1653     char *newParam = NULL;  /* space for the return parameter */
1654     char *nextParam = NULL; /* current end of the new parameter */
1655     char **oldChildren = NULL;
1656     CK_SLOT_ID *oldIds = NULL;
1657     void *mark = NULL; /* mark the arena pool in case we need
1658                         * to release it */
1659     int length, i, tmpLen;
1660     SECStatus rv;
1661 
1662     /* first strip out and save the old tokenlist */
1663     rawParam = secmod_ParseModuleSpecForTokens(PR_FALSE, PR_FALSE,
1664                                                oldParam, &oldChildren, &oldIds);
1665     if (!rawParam) {
1666         goto loser;
1667     }
1668 
1669     /* now calculate the total length of the new buffer */
1670     /* First the 'fixed stuff', length of rawparam (does not include a NULL),
1671      * length of the token string (does include the NULL), closing bracket */
1672     length = strlen(rawParam) + sizeof(TOKEN_STRING) + 1;
1673     /* now add then length of all the old children */
1674     for (i = 0; oldChildren && oldChildren[i]; i++) {
1675         length += secmod_getChildLength(oldChildren[i], oldIds[i]);
1676     }
1677 
1678     /* add the new token */
1679     length += secmod_getChildLength(newToken, newID);
1680 
1681     /* and it's new children */
1682     for (i = 0; children && children[i]; i++) {
1683         if (ids[i] == -1) {
1684             continue;
1685         }
1686         length += secmod_getChildLength(children[i], ids[i]);
1687     }
1688 
1689     /* now allocate and build the string */
1690     mark = PORT_ArenaMark(arena);
1691     if (!mark) {
1692         goto loser;
1693     }
1694     newParam = PORT_ArenaAlloc(arena, length);
1695     if (!newParam) {
1696         goto loser;
1697     }
1698 
1699     PORT_Strcpy(newParam, oldParam);
1700     tmpLen = strlen(oldParam);
1701     nextParam = newParam + tmpLen;
1702     length -= tmpLen;
1703     PORT_Memcpy(nextParam, TOKEN_STRING, sizeof(TOKEN_STRING) - 1);
1704     nextParam += sizeof(TOKEN_STRING) - 1;
1705     length -= sizeof(TOKEN_STRING) - 1;
1706 
1707     for (i = 0; oldChildren && oldChildren[i]; i++) {
1708         rv = secmod_mkTokenChild(&nextParam, &length, oldChildren[i], oldIds[i]);
1709         if (rv != SECSuccess) {
1710             goto loser;
1711         }
1712     }
1713 
1714     rv = secmod_mkTokenChild(&nextParam, &length, newToken, newID);
1715     if (rv != SECSuccess) {
1716         goto loser;
1717     }
1718 
1719     for (i = 0; children && children[i]; i++) {
1720         if (ids[i] == -1) {
1721             continue;
1722         }
1723         rv = secmod_mkTokenChild(&nextParam, &length, children[i], ids[i]);
1724         if (rv != SECSuccess) {
1725             goto loser;
1726         }
1727     }
1728 
1729     if (length < 2) {
1730         goto loser;
1731     }
1732 
1733     *nextParam++ = ']';
1734     *nextParam++ = 0;
1735 
1736     /* we are going to return newParam now, don't release the mark */
1737     PORT_ArenaUnmark(arena, mark);
1738     mark = NULL;
1739 
1740 loser:
1741     if (mark) {
1742         PORT_ArenaRelease(arena, mark);
1743         newParam = NULL; /* if the mark is still active,
1744                           * don't return the param */
1745     }
1746     if (rawParam) {
1747         PORT_Free(rawParam);
1748     }
1749     if (oldChildren) {
1750         secmod_FreeChildren(oldChildren, oldIds);
1751     }
1752     return newParam;
1753 }
1754 
1755 static char *
secmod_mkModuleSpec(SECMODModule * module)1756 secmod_mkModuleSpec(SECMODModule *module)
1757 {
1758     char *nss = NULL, *modSpec = NULL, **slotStrings = NULL;
1759     int slotCount, i, si;
1760     SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
1761 
1762     /* allocate target slot info strings */
1763     slotCount = 0;
1764 
1765     SECMOD_GetReadLock(moduleLock);
1766     if (module->slotCount) {
1767         for (i = 0; i < module->slotCount; i++) {
1768             if (module->slots[i]->defaultFlags != 0) {
1769                 slotCount++;
1770             }
1771         }
1772     } else {
1773         slotCount = module->slotInfoCount;
1774     }
1775 
1776     slotStrings = (char **)PORT_ZAlloc(slotCount * sizeof(char *));
1777     if (slotStrings == NULL) {
1778         SECMOD_ReleaseReadLock(moduleLock);
1779         goto loser;
1780     }
1781 
1782     /* build the slot info strings */
1783     if (module->slotCount) {
1784         for (i = 0, si = 0; i < module->slotCount; i++) {
1785             if (module->slots[i]->defaultFlags) {
1786                 PORT_Assert(si < slotCount);
1787                 if (si >= slotCount)
1788                     break;
1789                 slotStrings[si] = NSSUTIL_MkSlotString(module->slots[i]->slotID,
1790                                                        module->slots[i]->defaultFlags,
1791                                                        module->slots[i]->timeout,
1792                                                        module->slots[i]->askpw,
1793                                                        module->slots[i]->hasRootCerts,
1794                                                        module->slots[i]->hasRootTrust);
1795                 si++;
1796             }
1797         }
1798     } else {
1799         for (i = 0; i < slotCount; i++) {
1800             slotStrings[i] = NSSUTIL_MkSlotString(
1801                 module->slotInfo[i].slotID,
1802                 module->slotInfo[i].defaultFlags,
1803                 module->slotInfo[i].timeout,
1804                 module->slotInfo[i].askpw,
1805                 module->slotInfo[i].hasRootCerts,
1806                 module->slotInfo[i].hasRootTrust);
1807         }
1808     }
1809 
1810     SECMOD_ReleaseReadLock(moduleLock);
1811     nss = NSSUTIL_MkNSSString(slotStrings, slotCount, module->internal,
1812                               module->isFIPS, module->isModuleDB,
1813                               module->moduleDBOnly, module->isCritical,
1814                               module->trustOrder, module->cipherOrder,
1815                               module->ssl[0], module->ssl[1]);
1816     modSpec = NSSUTIL_MkModuleSpec(module->dllName, module->commonName,
1817                                    module->libraryParams, nss);
1818     PORT_Free(slotStrings);
1819     PR_smprintf_free(nss);
1820 loser:
1821     return (modSpec);
1822 }
1823 
1824 char **
SECMOD_GetModuleSpecList(SECMODModule * module)1825 SECMOD_GetModuleSpecList(SECMODModule *module)
1826 {
1827     SECMODModuleDBFunc func = (SECMODModuleDBFunc)module->moduleDBFunc;
1828     if (func) {
1829         return (*func)(SECMOD_MODULE_DB_FUNCTION_FIND,
1830                        module->libraryParams, NULL);
1831     }
1832     return NULL;
1833 }
1834 
1835 SECStatus
SECMOD_AddPermDB(SECMODModule * module)1836 SECMOD_AddPermDB(SECMODModule *module)
1837 {
1838     SECMODModuleDBFunc func;
1839     char *moduleSpec;
1840     char **retString;
1841 
1842     if (module->parent == NULL)
1843         return SECFailure;
1844 
1845     func = (SECMODModuleDBFunc)module->parent->moduleDBFunc;
1846     if (func) {
1847         moduleSpec = secmod_mkModuleSpec(module);
1848         retString = (*func)(SECMOD_MODULE_DB_FUNCTION_ADD,
1849                             module->parent->libraryParams, moduleSpec);
1850         PORT_Free(moduleSpec);
1851         if (retString != NULL)
1852             return SECSuccess;
1853     }
1854     return SECFailure;
1855 }
1856 
1857 SECStatus
SECMOD_DeletePermDB(SECMODModule * module)1858 SECMOD_DeletePermDB(SECMODModule *module)
1859 {
1860     SECMODModuleDBFunc func;
1861     char *moduleSpec;
1862     char **retString;
1863 
1864     if (module->parent == NULL)
1865         return SECFailure;
1866 
1867     func = (SECMODModuleDBFunc)module->parent->moduleDBFunc;
1868     if (func) {
1869         moduleSpec = secmod_mkModuleSpec(module);
1870         retString = (*func)(SECMOD_MODULE_DB_FUNCTION_DEL,
1871                             module->parent->libraryParams, moduleSpec);
1872         PORT_Free(moduleSpec);
1873         if (retString != NULL)
1874             return SECSuccess;
1875     }
1876     return SECFailure;
1877 }
1878 
1879 SECStatus
SECMOD_FreeModuleSpecList(SECMODModule * module,char ** moduleSpecList)1880 SECMOD_FreeModuleSpecList(SECMODModule *module, char **moduleSpecList)
1881 {
1882     SECMODModuleDBFunc func = (SECMODModuleDBFunc)module->moduleDBFunc;
1883     char **retString;
1884     if (func) {
1885         retString = (*func)(SECMOD_MODULE_DB_FUNCTION_RELEASE,
1886                             module->libraryParams, moduleSpecList);
1887         if (retString != NULL)
1888             return SECSuccess;
1889     }
1890     return SECFailure;
1891 }
1892 
1893 /*
1894  * load a PKCS#11 module but do not add it to the default NSS trust domain
1895  */
1896 SECMODModule *
SECMOD_LoadModule(char * modulespec,SECMODModule * parent,PRBool recurse)1897 SECMOD_LoadModule(char *modulespec, SECMODModule *parent, PRBool recurse)
1898 {
1899     char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss = NULL;
1900     char *config = NULL;
1901     SECStatus status;
1902     SECMODModule *module = NULL;
1903     SECMODModule *oldModule = NULL;
1904     SECStatus rv;
1905     PRBool forwardPolicyFeedback = PR_FALSE;
1906 
1907     /* initialize the underlying module structures */
1908     SECMOD_Init();
1909 
1910     status = NSSUTIL_ArgParseModuleSpecEx(modulespec, &library, &moduleName,
1911                                           &parameters, &nss,
1912                                           &config);
1913     if (status != SECSuccess) {
1914         goto loser;
1915     }
1916 
1917     module = SECMOD_CreateModuleEx(library, moduleName, parameters, nss, config);
1918     forwardPolicyFeedback = NSSUTIL_ArgHasFlag("flags", "printPolicyFeedback", nss);
1919     if (library)
1920         PORT_Free(library);
1921     if (moduleName)
1922         PORT_Free(moduleName);
1923     if (parameters)
1924         PORT_Free(parameters);
1925     if (nss)
1926         PORT_Free(nss);
1927     if (config)
1928         PORT_Free(config);
1929     if (!module) {
1930         goto loser;
1931     }
1932 
1933     /* a policy only stanza doesn't actually get 'loaded'. policy has already
1934      * been parsed as a side effect of the CreateModuleEx call */
1935     if (secmod_PolicyOnly(module)) {
1936         return module;
1937     }
1938     if (parent) {
1939         module->parent = SECMOD_ReferenceModule(parent);
1940         if (module->internal && secmod_IsInternalKeySlot(parent)) {
1941             module->internal = parent->internal;
1942         }
1943     }
1944 
1945     /* load it */
1946     rv = secmod_LoadPKCS11Module(module, &oldModule);
1947     if (rv != SECSuccess) {
1948         goto loser;
1949     }
1950 
1951     /* if we just reload an old module, no need to add it to any lists.
1952      * we simple release all our references */
1953     if (oldModule) {
1954         /* This module already exists, don't link it anywhere. This
1955          * will probably destroy this module */
1956         SECMOD_DestroyModule(module);
1957         return oldModule;
1958     }
1959 
1960     if (recurse && module->isModuleDB) {
1961         char **moduleSpecList;
1962         PORT_SetError(0);
1963 
1964         moduleSpecList = SECMOD_GetModuleSpecList(module);
1965         if (moduleSpecList) {
1966             char **index;
1967 
1968             index = moduleSpecList;
1969             if (*index && SECMOD_GetSkipFirstFlag(module)) {
1970                 index++;
1971             }
1972 
1973             for (; *index; index++) {
1974                 SECMODModule *child;
1975                 if (0 == PORT_Strcmp(*index, modulespec)) {
1976                     /* avoid trivial infinite recursion */
1977                     PORT_SetError(SEC_ERROR_NO_MODULE);
1978                     rv = SECFailure;
1979                     break;
1980                 }
1981                 if (!forwardPolicyFeedback) {
1982                     child = SECMOD_LoadModule(*index, module, PR_TRUE);
1983                 } else {
1984                     /* Add printPolicyFeedback to the nss flags */
1985                     char *specWithForwards =
1986                         NSSUTIL_AddNSSFlagToModuleSpec(*index, "printPolicyFeedback");
1987                     child = SECMOD_LoadModule(specWithForwards, module, PR_TRUE);
1988                     PORT_Free(specWithForwards);
1989                 }
1990                 if (!child)
1991                     break;
1992                 if (child->isCritical && !child->loaded) {
1993                     int err = PORT_GetError();
1994                     if (!err)
1995                         err = SEC_ERROR_NO_MODULE;
1996                     SECMOD_DestroyModule(child);
1997                     PORT_SetError(err);
1998                     rv = SECFailure;
1999                     break;
2000                 }
2001                 SECMOD_DestroyModule(child);
2002             }
2003             SECMOD_FreeModuleSpecList(module, moduleSpecList);
2004         } else {
2005             if (!PORT_GetError())
2006                 PORT_SetError(SEC_ERROR_NO_MODULE);
2007             rv = SECFailure;
2008         }
2009     }
2010 
2011     if (rv != SECSuccess) {
2012         goto loser;
2013     }
2014 
2015     /* inherit the reference */
2016     if (!module->moduleDBOnly) {
2017         SECMOD_AddModuleToList(module);
2018     } else {
2019         SECMOD_AddModuleToDBOnlyList(module);
2020     }
2021 
2022     /* handle any additional work here */
2023     return module;
2024 
2025 loser:
2026     if (module) {
2027         if (module->loaded) {
2028             SECMOD_UnloadModule(module);
2029         }
2030         SECMOD_AddModuleToUnloadList(module);
2031     }
2032     return module;
2033 }
2034 
2035 /*
2036  * load a PKCS#11 module and add it to the default NSS trust domain
2037  */
2038 SECMODModule *
SECMOD_LoadUserModule(char * modulespec,SECMODModule * parent,PRBool recurse)2039 SECMOD_LoadUserModule(char *modulespec, SECMODModule *parent, PRBool recurse)
2040 {
2041     SECStatus rv = SECSuccess;
2042     SECMODModule *newmod = SECMOD_LoadModule(modulespec, parent, recurse);
2043     SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
2044 
2045     if (newmod) {
2046         SECMOD_GetReadLock(moduleLock);
2047         rv = STAN_AddModuleToDefaultTrustDomain(newmod);
2048         SECMOD_ReleaseReadLock(moduleLock);
2049         if (SECSuccess != rv) {
2050             SECMOD_DestroyModule(newmod);
2051             return NULL;
2052         }
2053     }
2054     return newmod;
2055 }
2056 
2057 /*
2058  * remove the PKCS#11 module from the default NSS trust domain, call
2059  * C_Finalize, and destroy the module structure
2060  */
2061 SECStatus
SECMOD_UnloadUserModule(SECMODModule * mod)2062 SECMOD_UnloadUserModule(SECMODModule *mod)
2063 {
2064     SECStatus rv = SECSuccess;
2065     int atype = 0;
2066     SECMODListLock *moduleLock = SECMOD_GetDefaultModuleListLock();
2067     if (!mod) {
2068         return SECFailure;
2069     }
2070 
2071     SECMOD_GetReadLock(moduleLock);
2072     rv = STAN_RemoveModuleFromDefaultTrustDomain(mod);
2073     SECMOD_ReleaseReadLock(moduleLock);
2074     if (SECSuccess != rv) {
2075         return SECFailure;
2076     }
2077     return SECMOD_DeleteModuleEx(NULL, mod, &atype, PR_FALSE);
2078 }
2079