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 ¤tString);
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 ¤tString);
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 ¶meters, &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