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  * This file implements PKCS 11 on top of our existing security modules
6  *
7  * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
8  *   This implementation has two slots:
9  *      slot 1 is our generic crypto support. It does not require login.
10  *   It supports Public Key ops, and all they bulk ciphers and hashes.
11  *   It can also support Private Key ops for imported Private keys. It does
12  *   not have any token storage.
13  *      slot 2 is our private key support. It requires a login before use. It
14  *   can store Private Keys and Certs as token objects. Currently only private
15  *   keys and their associated Certificates are saved on the token.
16  *
17  *   In this implementation, session objects are only visible to the session
18  *   that created or generated them.
19  */
20 #include "seccomon.h"
21 #include "secitem.h"
22 #include "pkcs11.h"
23 #include "pkcs11i.h"
24 #include "softoken.h"
25 #include "lowkeyi.h"
26 #include "blapi.h"
27 #include "secder.h"
28 #include "secport.h"
29 #include "secrng.h"
30 #include "prtypes.h"
31 #include "nspr.h"
32 #include "softkver.h"
33 #include "secoid.h"
34 #include "sftkdb.h"
35 #include "utilpars.h"
36 #include "ec.h"
37 #include "secasn1.h"
38 #include "secerr.h"
39 #include "lgglue.h"
40 
41 PRBool parentForkedAfterC_Initialize;
42 
43 #ifndef NO_FORK_CHECK
44 
45 PRBool sftkForkCheckDisabled;
46 
47 #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
48 PRBool forked = PR_FALSE;
49 #endif
50 
51 #if defined(CHECK_FORK_GETPID) || defined(CHECK_FORK_MIXED)
52 #include <unistd.h>
53 pid_t myPid;
54 #endif
55 
56 #ifdef CHECK_FORK_MIXED
57 #include <sys/systeminfo.h>
58 PRBool usePthread_atfork;
59 #endif
60 
61 #endif
62 
63 /*
64  * ******************** Static data *******************************
65  */
66 
67 /* The next three strings must be exactly 32 characters long */
68 static char *manufacturerID = "Mozilla Foundation              ";
69 static char manufacturerID_space[33];
70 static char *libraryDescription = "NSS Internal Crypto Services    ";
71 static char libraryDescription_space[33];
72 
73 /*
74  * In FIPS mode, we disallow login attempts for 1 second after a login
75  * failure so that there are at most 60 login attempts per minute.
76  */
77 static PRIntervalTime loginWaitTime;
78 static PRUint32 minSessionObjectHandle = 1U;
79 
80 #define __PASTE(x, y) x##y
81 
82 /*
83  * we renamed all our internal functions, get the correct
84  * definitions for them...
85  */
86 #undef CK_PKCS11_FUNCTION_INFO
87 #undef CK_NEED_ARG_LIST
88 
89 #define CK_EXTERN extern
90 #define CK_PKCS11_FUNCTION_INFO(func) \
91     CK_RV __PASTE(NS, func)
92 #define CK_NEED_ARG_LIST 1
93 
94 #include "pkcs11f.h"
95 
96 /* build the crypto module table */
97 static const CK_FUNCTION_LIST sftk_funcList = {
98     { 1, 10 },
99 
100 #undef CK_PKCS11_FUNCTION_INFO
101 #undef CK_NEED_ARG_LIST
102 
103 #define CK_PKCS11_FUNCTION_INFO(func) \
104     __PASTE(NS, func)                 \
105     ,
106 #include "pkcs11f.h"
107 
108 };
109 
110 #undef CK_PKCS11_FUNCTION_INFO
111 #undef CK_NEED_ARG_LIST
112 
113 #undef __PASTE
114 
115 /* List of DES Weak Keys */
116 typedef unsigned char desKey[8];
117 static const desKey sftk_desWeakTable[] = {
118 #ifdef noParity
119     /* weak */
120     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
121     { 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e },
122     { 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0 },
123     { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
124     /* semi-weak */
125     { 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe },
126     { 0xfe, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0xfe },
127 
128     { 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 },
129     { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
130 
131     { 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x0f, 0x00, 0x0f },
132     { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
133 
134     { 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
135     { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
136 
137     { 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e },
138     { 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 },
139 
140     { 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe },
141     { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 },
142 #else
143     /* weak */
144     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
145     { 0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e },
146     { 0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1 },
147     { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe },
148 
149     /* semi-weak */
150     { 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe },
151     { 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01 },
152 
153     { 0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1 },
154     { 0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e },
155 
156     { 0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1 },
157     { 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01 },
158 
159     { 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe },
160     { 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e },
161 
162     { 0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e },
163     { 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01 },
164 
165     { 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe },
166     { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1 }
167 #endif
168 };
169 
170 static const int sftk_desWeakTableSize = sizeof(sftk_desWeakTable) /
171                                          sizeof(sftk_desWeakTable[0]);
172 
173 /* DES KEY Parity conversion table. Takes each byte/2 as an index, returns
174  * that byte with the proper parity bit set */
175 static const unsigned char parityTable[256] = {
176     /* Even...0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e */
177     /* E */ 0x01, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e,
178     /* Odd....0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e */
179     /* O */ 0x10, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x1f,
180     /* Odd....0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e */
181     /* O */ 0x20, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f,
182     /* Even...0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e */
183     /* E */ 0x31, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x3e,
184     /* Odd....0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e */
185     /* O */ 0x40, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f,
186     /* Even...0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e */
187     /* E */ 0x51, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 0x5e,
188     /* Even...0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e */
189     /* E */ 0x61, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e,
190     /* Odd....0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e */
191     /* O */ 0x70, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c, 0x7f,
192     /* Odd....0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e */
193     /* O */ 0x80, 0x83, 0x85, 0x86, 0x89, 0x8a, 0x8c, 0x8f,
194     /* Even...0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e */
195     /* E */ 0x91, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 0x9e,
196     /* Even...0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae */
197     /* E */ 0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xae,
198     /* Odd....0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe */
199     /* O */ 0xb0, 0xb3, 0xb5, 0xb6, 0xb9, 0xba, 0xbc, 0xbf,
200     /* Even...0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce */
201     /* E */ 0xc1, 0xc2, 0xc4, 0xc7, 0xc8, 0xcb, 0xcd, 0xce,
202     /* Odd....0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde */
203     /* O */ 0xd0, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 0xdf,
204     /* Odd....0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee */
205     /* O */ 0xe0, 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xef,
206     /* Even...0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe */
207     /* E */ 0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe,
208 };
209 
210 /* Mechanisms */
211 struct mechanismList {
212     CK_MECHANISM_TYPE type;
213     CK_MECHANISM_INFO info;
214     PRBool privkey;
215 };
216 
217 /*
218  * the following table includes a complete list of mechanism defined by
219  * PKCS #11 version 2.01. Those Mechanisms not supported by this PKCS #11
220  * module are ifdef'ed out.
221  */
222 #define CKF_EN_DE CKF_ENCRYPT | CKF_DECRYPT
223 #define CKF_WR_UN CKF_WRAP | CKF_UNWRAP
224 #define CKF_SN_VR CKF_SIGN | CKF_VERIFY
225 #define CKF_SN_RE CKF_SIGN_RECOVER | CKF_VERIFY_RECOVER
226 
227 #define CKF_EN_DE_WR_UN CKF_EN_DE | CKF_WR_UN
228 #define CKF_SN_VR_RE CKF_SN_VR | CKF_SN_RE
229 #define CKF_DUZ_IT_ALL CKF_EN_DE_WR_UN | CKF_SN_VR_RE
230 
231 #define CKF_EC_PNU CKF_EC_FP | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS
232 
233 #define CKF_EC_BPNU CKF_EC_F_2M | CKF_EC_PNU
234 
235 #define CK_MAX 0xffffffff
236 
237 static const struct mechanismList mechanisms[] = {
238 
239     /*
240       * PKCS #11 Mechanism List.
241       *
242       * The first argument is the PKCS #11 Mechanism we support.
243       * The second argument is Mechanism info structure. It includes:
244       *    The minimum key size,
245       *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
246       *       in bytes for RC5, AES, Camellia, and CAST*
247       *       ignored for DES*, IDEA and FORTEZZA based
248       *    The maximum key size,
249       *       in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs.
250       *       in bytes for RC5, AES, Camellia, and CAST*
251       *       ignored for DES*, IDEA and FORTEZZA based
252       *     Flags
253       *       What operations are supported by this mechanism.
254       *  The third argument is a bool which tells if this mechanism is
255       *    supported in the database token.
256       *
257       */
258 
259     /* ------------------------- RSA Operations ---------------------------*/
260     { CKM_RSA_PKCS_KEY_PAIR_GEN, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
261     { CKM_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_DUZ_IT_ALL }, PR_TRUE },
262     { CKM_RSA_PKCS_PSS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
263     { CKM_RSA_PKCS_OAEP, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_EN_DE_WR_UN }, PR_TRUE },
264 #ifdef SFTK_RSA9796_SUPPORTED
265     { CKM_RSA_9796, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_DUZ_IT_ALL }, PR_TRUE },
266 #endif
267     { CKM_RSA_X_509, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_DUZ_IT_ALL }, PR_TRUE },
268     /* -------------- RSA Multipart Signing Operations -------------------- */
269     { CKM_MD2_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
270     { CKM_MD5_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
271     { CKM_SHA1_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
272     { CKM_SHA224_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
273     { CKM_SHA256_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
274     { CKM_SHA384_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
275     { CKM_SHA512_RSA_PKCS, { RSA_MIN_MODULUS_BITS, CK_MAX, CKF_SN_VR }, PR_TRUE },
276     /* ------------------------- DSA Operations --------------------------- */
277     { CKM_DSA_KEY_PAIR_GEN, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
278     { CKM_DSA, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
279     { CKM_DSA_PARAMETER_GEN, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_GENERATE }, PR_TRUE },
280     { CKM_DSA_SHA1, { DSA_MIN_P_BITS, DSA_MAX_P_BITS, CKF_SN_VR }, PR_TRUE },
281     /* -------------------- Diffie Hellman Operations --------------------- */
282     /* no diffie hellman yet */
283     { CKM_DH_PKCS_KEY_PAIR_GEN, { DH_MIN_P_BITS, DH_MAX_P_BITS, CKF_GENERATE_KEY_PAIR }, PR_TRUE },
284     { CKM_DH_PKCS_DERIVE, { DH_MIN_P_BITS, DH_MAX_P_BITS, CKF_DERIVE }, PR_TRUE },
285 #ifndef NSS_DISABLE_ECC
286     /* -------------------- Elliptic Curve Operations --------------------- */
287     { CKM_EC_KEY_PAIR_GEN, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_GENERATE_KEY_PAIR | CKF_EC_BPNU }, PR_TRUE },
288     { CKM_ECDH1_DERIVE, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_DERIVE | CKF_EC_BPNU }, PR_TRUE },
289     { CKM_ECDSA, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
290     { CKM_ECDSA_SHA1, { EC_MIN_KEY_BITS, EC_MAX_KEY_BITS, CKF_SN_VR | CKF_EC_BPNU }, PR_TRUE },
291 #endif /* NSS_DISABLE_ECC */
292     /* ------------------------- RC2 Operations --------------------------- */
293     { CKM_RC2_KEY_GEN, { 1, 128, CKF_GENERATE }, PR_TRUE },
294     { CKM_RC2_ECB, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
295     { CKM_RC2_CBC, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
296     { CKM_RC2_MAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
297     { CKM_RC2_MAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
298     { CKM_RC2_CBC_PAD, { 1, 128, CKF_EN_DE_WR_UN }, PR_TRUE },
299     /* ------------------------- RC4 Operations --------------------------- */
300     { CKM_RC4_KEY_GEN, { 1, 256, CKF_GENERATE }, PR_FALSE },
301     { CKM_RC4, { 1, 256, CKF_EN_DE_WR_UN }, PR_FALSE },
302     /* ------------------------- DES Operations --------------------------- */
303     { CKM_DES_KEY_GEN, { 8, 8, CKF_GENERATE }, PR_TRUE },
304     { CKM_DES_ECB, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
305     { CKM_DES_CBC, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
306     { CKM_DES_MAC, { 8, 8, CKF_SN_VR }, PR_TRUE },
307     { CKM_DES_MAC_GENERAL, { 8, 8, CKF_SN_VR }, PR_TRUE },
308     { CKM_DES_CBC_PAD, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
309     { CKM_DES2_KEY_GEN, { 24, 24, CKF_GENERATE }, PR_TRUE },
310     { CKM_DES3_KEY_GEN, { 24, 24, CKF_GENERATE }, PR_TRUE },
311     { CKM_DES3_ECB, { 24, 24, CKF_EN_DE_WR_UN }, PR_TRUE },
312     { CKM_DES3_CBC, { 24, 24, CKF_EN_DE_WR_UN }, PR_TRUE },
313     { CKM_DES3_MAC, { 24, 24, CKF_SN_VR }, PR_TRUE },
314     { CKM_DES3_MAC_GENERAL, { 24, 24, CKF_SN_VR }, PR_TRUE },
315     { CKM_DES3_CBC_PAD, { 24, 24, CKF_EN_DE_WR_UN }, PR_TRUE },
316     /* ------------------------- CDMF Operations --------------------------- */
317     { CKM_CDMF_KEY_GEN, { 8, 8, CKF_GENERATE }, PR_TRUE },
318     { CKM_CDMF_ECB, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
319     { CKM_CDMF_CBC, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
320     { CKM_CDMF_MAC, { 8, 8, CKF_SN_VR }, PR_TRUE },
321     { CKM_CDMF_MAC_GENERAL, { 8, 8, CKF_SN_VR }, PR_TRUE },
322     { CKM_CDMF_CBC_PAD, { 8, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
323     /* ------------------------- AES Operations --------------------------- */
324     { CKM_AES_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
325     { CKM_AES_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
326     { CKM_AES_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
327     { CKM_AES_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
328     { CKM_AES_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
329     { CKM_AES_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
330     { CKM_AES_CTS, { 16, 32, CKF_EN_DE }, PR_TRUE },
331     { CKM_AES_CTR, { 16, 32, CKF_EN_DE }, PR_TRUE },
332     { CKM_AES_GCM, { 16, 32, CKF_EN_DE }, PR_TRUE },
333     /* ------------------------- Camellia Operations --------------------- */
334     { CKM_CAMELLIA_KEY_GEN, { 16, 32, CKF_GENERATE }, PR_TRUE },
335     { CKM_CAMELLIA_ECB, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
336     { CKM_CAMELLIA_CBC, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
337     { CKM_CAMELLIA_MAC, { 16, 32, CKF_SN_VR }, PR_TRUE },
338     { CKM_CAMELLIA_MAC_GENERAL, { 16, 32, CKF_SN_VR }, PR_TRUE },
339     { CKM_CAMELLIA_CBC_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
340     /* ------------------------- SEED Operations --------------------------- */
341     { CKM_SEED_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
342     { CKM_SEED_ECB, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
343     { CKM_SEED_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
344     { CKM_SEED_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
345     { CKM_SEED_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
346     { CKM_SEED_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
347 #ifndef NSS_DISABLE_CHACHAPOLY
348     /* ------------------------- ChaCha20 Operations ---------------------- */
349     { CKM_NSS_CHACHA20_KEY_GEN, { 32, 32, CKF_GENERATE }, PR_TRUE },
350     { CKM_NSS_CHACHA20_POLY1305, { 32, 32, CKF_EN_DE }, PR_TRUE },
351 #endif /* NSS_DISABLE_CHACHAPOLY */
352     /* ------------------------- Hashing Operations ----------------------- */
353     { CKM_MD2, { 0, 0, CKF_DIGEST }, PR_FALSE },
354     { CKM_MD2_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
355     { CKM_MD2_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
356     { CKM_MD5, { 0, 0, CKF_DIGEST }, PR_FALSE },
357     { CKM_MD5_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
358     { CKM_MD5_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
359     { CKM_SHA_1, { 0, 0, CKF_DIGEST }, PR_FALSE },
360     { CKM_SHA_1_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
361     { CKM_SHA_1_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
362     { CKM_SHA224, { 0, 0, CKF_DIGEST }, PR_FALSE },
363     { CKM_SHA224_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
364     { CKM_SHA224_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
365     { CKM_SHA256, { 0, 0, CKF_DIGEST }, PR_FALSE },
366     { CKM_SHA256_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
367     { CKM_SHA256_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
368     { CKM_SHA384, { 0, 0, CKF_DIGEST }, PR_FALSE },
369     { CKM_SHA384_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
370     { CKM_SHA384_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
371     { CKM_SHA512, { 0, 0, CKF_DIGEST }, PR_FALSE },
372     { CKM_SHA512_HMAC, { 1, 128, CKF_SN_VR }, PR_TRUE },
373     { CKM_SHA512_HMAC_GENERAL, { 1, 128, CKF_SN_VR }, PR_TRUE },
374     { CKM_TLS_PRF_GENERAL, { 0, 512, CKF_SN_VR }, PR_FALSE },
375     { CKM_TLS_MAC, { 0, 512, CKF_SN_VR }, PR_FALSE },
376     { CKM_NSS_TLS_PRF_GENERAL_SHA256,
377       { 0, 512, CKF_SN_VR },
378       PR_FALSE },
379     /* ------------------------- HKDF Operations -------------------------- */
380     { CKM_NSS_HKDF_SHA1, { 1, 128, CKF_DERIVE }, PR_TRUE },
381     { CKM_NSS_HKDF_SHA256, { 1, 128, CKF_DERIVE }, PR_TRUE },
382     { CKM_NSS_HKDF_SHA384, { 1, 128, CKF_DERIVE }, PR_TRUE },
383     { CKM_NSS_HKDF_SHA512, { 1, 128, CKF_DERIVE }, PR_TRUE },
384 /* ------------------------- CAST Operations --------------------------- */
385 #ifdef NSS_SOFTOKEN_DOES_CAST
386     /* Cast operations are not supported ( yet? ) */
387     { CKM_CAST_KEY_GEN, { 1, 8, CKF_GENERATE }, PR_TRUE },
388     { CKM_CAST_ECB, { 1, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
389     { CKM_CAST_CBC, { 1, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
390     { CKM_CAST_MAC, { 1, 8, CKF_SN_VR }, PR_TRUE },
391     { CKM_CAST_MAC_GENERAL, { 1, 8, CKF_SN_VR }, PR_TRUE },
392     { CKM_CAST_CBC_PAD, { 1, 8, CKF_EN_DE_WR_UN }, PR_TRUE },
393     { CKM_CAST3_KEY_GEN, { 1, 16, CKF_GENERATE }, PR_TRUE },
394     { CKM_CAST3_ECB, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
395     { CKM_CAST3_CBC, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
396     { CKM_CAST3_MAC, { 1, 16, CKF_SN_VR }, PR_TRUE },
397     { CKM_CAST3_MAC_GENERAL, { 1, 16, CKF_SN_VR }, PR_TRUE },
398     { CKM_CAST3_CBC_PAD, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
399     { CKM_CAST5_KEY_GEN, { 1, 16, CKF_GENERATE }, PR_TRUE },
400     { CKM_CAST5_ECB, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
401     { CKM_CAST5_CBC, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
402     { CKM_CAST5_MAC, { 1, 16, CKF_SN_VR }, PR_TRUE },
403     { CKM_CAST5_MAC_GENERAL, { 1, 16, CKF_SN_VR }, PR_TRUE },
404     { CKM_CAST5_CBC_PAD, { 1, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
405 #endif
406 #if NSS_SOFTOKEN_DOES_RC5
407     /* ------------------------- RC5 Operations --------------------------- */
408     { CKM_RC5_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
409     { CKM_RC5_ECB, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
410     { CKM_RC5_CBC, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
411     { CKM_RC5_MAC, { 1, 32, CKF_SN_VR }, PR_TRUE },
412     { CKM_RC5_MAC_GENERAL, { 1, 32, CKF_SN_VR }, PR_TRUE },
413     { CKM_RC5_CBC_PAD, { 1, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
414 #endif
415 #ifdef NSS_SOFTOKEN_DOES_IDEA
416     /* ------------------------- IDEA Operations -------------------------- */
417     { CKM_IDEA_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
418     { CKM_IDEA_ECB, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
419     { CKM_IDEA_CBC, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
420     { CKM_IDEA_MAC, { 16, 16, CKF_SN_VR }, PR_TRUE },
421     { CKM_IDEA_MAC_GENERAL, { 16, 16, CKF_SN_VR }, PR_TRUE },
422     { CKM_IDEA_CBC_PAD, { 16, 16, CKF_EN_DE_WR_UN }, PR_TRUE },
423 #endif
424     /* --------------------- Secret Key Operations ------------------------ */
425     { CKM_GENERIC_SECRET_KEY_GEN, { 1, 32, CKF_GENERATE }, PR_TRUE },
426     { CKM_CONCATENATE_BASE_AND_KEY, { 1, 32, CKF_GENERATE }, PR_FALSE },
427     { CKM_CONCATENATE_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
428     { CKM_CONCATENATE_DATA_AND_BASE, { 1, 32, CKF_GENERATE }, PR_FALSE },
429     { CKM_XOR_BASE_AND_DATA, { 1, 32, CKF_GENERATE }, PR_FALSE },
430     { CKM_EXTRACT_KEY_FROM_KEY, { 1, 32, CKF_DERIVE }, PR_FALSE },
431     /* ---------------------- SSL Key Derivations ------------------------- */
432     { CKM_SSL3_PRE_MASTER_KEY_GEN, { 48, 48, CKF_GENERATE }, PR_FALSE },
433     { CKM_SSL3_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
434     { CKM_SSL3_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
435     { CKM_SSL3_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
436     { CKM_SSL3_MD5_MAC, { 0, 16, CKF_DERIVE }, PR_FALSE },
437     { CKM_SSL3_SHA1_MAC, { 0, 20, CKF_DERIVE }, PR_FALSE },
438     { CKM_MD5_KEY_DERIVATION, { 0, 16, CKF_DERIVE }, PR_FALSE },
439     { CKM_MD2_KEY_DERIVATION, { 0, 16, CKF_DERIVE }, PR_FALSE },
440     { CKM_SHA1_KEY_DERIVATION, { 0, 20, CKF_DERIVE }, PR_FALSE },
441     { CKM_SHA224_KEY_DERIVATION, { 0, 28, CKF_DERIVE }, PR_FALSE },
442     { CKM_SHA256_KEY_DERIVATION, { 0, 32, CKF_DERIVE }, PR_FALSE },
443     { CKM_SHA384_KEY_DERIVATION, { 0, 48, CKF_DERIVE }, PR_FALSE },
444     { CKM_SHA512_KEY_DERIVATION, { 0, 64, CKF_DERIVE }, PR_FALSE },
445     { CKM_TLS_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
446     { CKM_TLS12_MASTER_KEY_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
447     { CKM_NSS_TLS_MASTER_KEY_DERIVE_SHA256,
448       { 48, 48, CKF_DERIVE },
449       PR_FALSE },
450     { CKM_TLS_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
451     { CKM_TLS12_MASTER_KEY_DERIVE_DH, { 8, 128, CKF_DERIVE }, PR_FALSE },
452     { CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256,
453       { 8, 128, CKF_DERIVE },
454       PR_FALSE },
455     { CKM_TLS_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
456     { CKM_TLS12_KEY_AND_MAC_DERIVE, { 48, 48, CKF_DERIVE }, PR_FALSE },
457     { CKM_NSS_TLS_KEY_AND_MAC_DERIVE_SHA256,
458       { 48, 48, CKF_DERIVE },
459       PR_FALSE },
460     { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE,
461       { 48, 128, CKF_DERIVE },
462       PR_FALSE },
463     { CKM_NSS_TLS_EXTENDED_MASTER_KEY_DERIVE_DH,
464       { 48, 128, CKF_DERIVE },
465       PR_FALSE },
466     /* ---------------------- PBE Key Derivations  ------------------------ */
467     { CKM_PBE_MD2_DES_CBC, { 8, 8, CKF_DERIVE }, PR_TRUE },
468     { CKM_PBE_MD5_DES_CBC, { 8, 8, CKF_DERIVE }, PR_TRUE },
469     /* ------------------ NETSCAPE PBE Key Derivations  ------------------- */
470     { CKM_NETSCAPE_PBE_SHA1_DES_CBC, { 8, 8, CKF_GENERATE }, PR_TRUE },
471     { CKM_NETSCAPE_PBE_SHA1_FAULTY_3DES_CBC, { 24, 24, CKF_GENERATE }, PR_TRUE },
472     { CKM_PBE_SHA1_DES3_EDE_CBC, { 24, 24, CKF_GENERATE }, PR_TRUE },
473     { CKM_PBE_SHA1_DES2_EDE_CBC, { 24, 24, CKF_GENERATE }, PR_TRUE },
474     { CKM_PBE_SHA1_RC2_40_CBC, { 40, 40, CKF_GENERATE }, PR_TRUE },
475     { CKM_PBE_SHA1_RC2_128_CBC, { 128, 128, CKF_GENERATE }, PR_TRUE },
476     { CKM_PBE_SHA1_RC4_40, { 40, 40, CKF_GENERATE }, PR_TRUE },
477     { CKM_PBE_SHA1_RC4_128, { 128, 128, CKF_GENERATE }, PR_TRUE },
478     { CKM_PBA_SHA1_WITH_SHA1_HMAC, { 20, 20, CKF_GENERATE }, PR_TRUE },
479     { CKM_PKCS5_PBKD2, { 1, 256, CKF_GENERATE }, PR_TRUE },
480     { CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN, { 20, 20, CKF_GENERATE }, PR_TRUE },
481     { CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
482     { CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN, { 16, 16, CKF_GENERATE }, PR_TRUE },
483     /* ------------------ AES Key Wrap (also encrypt)  ------------------- */
484     { CKM_NETSCAPE_AES_KEY_WRAP, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
485     { CKM_NETSCAPE_AES_KEY_WRAP_PAD, { 16, 32, CKF_EN_DE_WR_UN }, PR_TRUE },
486     /* --------------------------- J-PAKE -------------------------------- */
487     { CKM_NSS_JPAKE_ROUND1_SHA1, { 0, 0, CKF_GENERATE }, PR_TRUE },
488     { CKM_NSS_JPAKE_ROUND1_SHA256, { 0, 0, CKF_GENERATE }, PR_TRUE },
489     { CKM_NSS_JPAKE_ROUND1_SHA384, { 0, 0, CKF_GENERATE }, PR_TRUE },
490     { CKM_NSS_JPAKE_ROUND1_SHA512, { 0, 0, CKF_GENERATE }, PR_TRUE },
491     { CKM_NSS_JPAKE_ROUND2_SHA1, { 0, 0, CKF_DERIVE }, PR_TRUE },
492     { CKM_NSS_JPAKE_ROUND2_SHA256, { 0, 0, CKF_DERIVE }, PR_TRUE },
493     { CKM_NSS_JPAKE_ROUND2_SHA384, { 0, 0, CKF_DERIVE }, PR_TRUE },
494     { CKM_NSS_JPAKE_ROUND2_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE },
495     { CKM_NSS_JPAKE_FINAL_SHA1, { 0, 0, CKF_DERIVE }, PR_TRUE },
496     { CKM_NSS_JPAKE_FINAL_SHA256, { 0, 0, CKF_DERIVE }, PR_TRUE },
497     { CKM_NSS_JPAKE_FINAL_SHA384, { 0, 0, CKF_DERIVE }, PR_TRUE },
498     { CKM_NSS_JPAKE_FINAL_SHA512, { 0, 0, CKF_DERIVE }, PR_TRUE },
499     /* -------------------- Constant Time TLS MACs ----------------------- */
500     { CKM_NSS_HMAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE },
501     { CKM_NSS_SSL3_MAC_CONSTANT_TIME, { 0, 0, CKF_DIGEST }, PR_TRUE }
502 };
503 static const CK_ULONG mechanismCount = sizeof(mechanisms) / sizeof(mechanisms[0]);
504 
505 /* sigh global so fipstokn can read it */
506 PRBool nsc_init = PR_FALSE;
507 
508 #if defined(CHECK_FORK_PTHREAD) || defined(CHECK_FORK_MIXED)
509 
510 #include <pthread.h>
511 
512 static void
ForkedChild(void)513 ForkedChild(void)
514 {
515     if (nsc_init || nsf_init) {
516         forked = PR_TRUE;
517     }
518 }
519 
520 #endif
521 
522 static char *
sftk_setStringName(const char * inString,char * buffer,int buffer_length,PRBool nullTerminate)523 sftk_setStringName(const char *inString, char *buffer, int buffer_length, PRBool nullTerminate)
524 {
525     int full_length, string_length;
526 
527     full_length = nullTerminate ? buffer_length - 1 : buffer_length;
528     string_length = PORT_Strlen(inString);
529     /*
530      *  shorten the string, respecting utf8 encoding
531      *  to do so, we work backward from the end
532      *  bytes looking from the end are either:
533      *    - ascii [0x00,0x7f]
534      *    - the [2-n]th byte of a multibyte sequence
535      *        [0x3F,0xBF], i.e, most significant 2 bits are '10'
536      *    - the first byte of a multibyte sequence [0xC0,0xFD],
537      *        i.e, most significant 2 bits are '11'
538      *
539      *    When the string is too long, we lop off any trailing '10' bytes,
540      *  if any. When these are all eliminated we lop off
541      *  one additional byte. Thus if we lopped any '10'
542      *  we'll be lopping a '11' byte (the first byte of the multibyte sequence),
543      *  otherwise we're lopping off an ascii character.
544      *
545      *    To test for '10' bytes, we first AND it with
546      *  11000000 (0xc0) so that we get 10000000 (0x80) if and only if
547      *  the byte starts with 10. We test for equality.
548      */
549     while (string_length > full_length) {
550         /* need to shorten */
551         while (string_length > 0 &&
552                ((inString[string_length - 1] & (char)0xc0) == (char)0x80)) {
553             /* lop off '10' byte */
554             string_length--;
555         }
556         /*
557          * test string_length in case bad data is received
558          * and string consisted of all '10' bytes,
559          * avoiding any infinite loop
560          */
561         if (string_length) {
562             /* remove either '11' byte or an asci byte */
563             string_length--;
564         }
565     }
566     PORT_Memset(buffer, ' ', full_length);
567     if (nullTerminate) {
568         buffer[full_length] = 0;
569     }
570     PORT_Memcpy(buffer, inString, string_length);
571     return buffer;
572 }
573 /*
574  * Configuration utils
575  */
576 static CK_RV
sftk_configure(const char * man,const char * libdes)577 sftk_configure(const char *man, const char *libdes)
578 {
579 
580     /* make sure the internationalization was done correctly... */
581     if (man) {
582         manufacturerID = sftk_setStringName(man, manufacturerID_space,
583                                             sizeof(manufacturerID_space), PR_TRUE);
584     }
585     if (libdes) {
586         libraryDescription = sftk_setStringName(libdes,
587                                                 libraryDescription_space, sizeof(libraryDescription_space),
588                                                 PR_TRUE);
589     }
590 
591     return CKR_OK;
592 }
593 
594 /*
595  * ******************** Password Utilities *******************************
596  */
597 
598 /*
599  * see if the key DB password is enabled
600  */
601 static PRBool
sftk_hasNullPassword(SFTKSlot * slot,SFTKDBHandle * keydb)602 sftk_hasNullPassword(SFTKSlot *slot, SFTKDBHandle *keydb)
603 {
604     PRBool pwenabled;
605 
606     pwenabled = PR_FALSE;
607     if (sftkdb_HasPasswordSet(keydb) == SECSuccess) {
608         PRBool tokenRemoved = PR_FALSE;
609         SECStatus rv = sftkdb_CheckPassword(keydb, "", &tokenRemoved);
610         if (tokenRemoved) {
611             sftk_CloseAllSessions(slot, PR_FALSE);
612         }
613         return (rv == SECSuccess);
614     }
615 
616     return pwenabled;
617 }
618 
619 /*
620  * ******************** Object Creation Utilities ***************************
621  */
622 
623 /* Make sure a given attribute exists. If it doesn't, initialize it to
624  * value and len
625  */
626 CK_RV
sftk_defaultAttribute(SFTKObject * object,CK_ATTRIBUTE_TYPE type,const void * value,unsigned int len)627 sftk_defaultAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,
628                       const void *value, unsigned int len)
629 {
630     if (!sftk_hasAttribute(object, type)) {
631         return sftk_AddAttributeType(object, type, value, len);
632     }
633     return CKR_OK;
634 }
635 
636 /*
637  * check the consistancy and initialize a Data Object
638  */
639 static CK_RV
sftk_handleDataObject(SFTKSession * session,SFTKObject * object)640 sftk_handleDataObject(SFTKSession *session, SFTKObject *object)
641 {
642     CK_RV crv;
643 
644     /* first reject private and token data objects */
645     if (sftk_isTrue(object, CKA_PRIVATE) || sftk_isTrue(object, CKA_TOKEN)) {
646         return CKR_ATTRIBUTE_VALUE_INVALID;
647     }
648 
649     /* now just verify the required date fields */
650     crv = sftk_defaultAttribute(object, CKA_APPLICATION, NULL, 0);
651     if (crv != CKR_OK)
652         return crv;
653     crv = sftk_defaultAttribute(object, CKA_VALUE, NULL, 0);
654     if (crv != CKR_OK)
655         return crv;
656 
657     return CKR_OK;
658 }
659 
660 /*
661  * check the consistancy and initialize a Certificate Object
662  */
663 static CK_RV
sftk_handleCertObject(SFTKSession * session,SFTKObject * object)664 sftk_handleCertObject(SFTKSession *session, SFTKObject *object)
665 {
666     CK_CERTIFICATE_TYPE type;
667     SFTKAttribute *attribute;
668     CK_RV crv;
669 
670     /* certificates must have a type */
671     if (!sftk_hasAttribute(object, CKA_CERTIFICATE_TYPE)) {
672         return CKR_TEMPLATE_INCOMPLETE;
673     }
674 
675     /* we can't store any certs private */
676     if (sftk_isTrue(object, CKA_PRIVATE)) {
677         return CKR_ATTRIBUTE_VALUE_INVALID;
678     }
679 
680     /* We only support X.509 Certs for now */
681     attribute = sftk_FindAttribute(object, CKA_CERTIFICATE_TYPE);
682     if (attribute == NULL)
683         return CKR_TEMPLATE_INCOMPLETE;
684     type = *(CK_CERTIFICATE_TYPE *)attribute->attrib.pValue;
685     sftk_FreeAttribute(attribute);
686 
687     if (type != CKC_X_509) {
688         return CKR_ATTRIBUTE_VALUE_INVALID;
689     }
690 
691     /* X.509 Certificate */
692 
693     /* make sure we have a cert */
694     if (!sftk_hasAttribute(object, CKA_VALUE)) {
695         return CKR_TEMPLATE_INCOMPLETE;
696     }
697 
698     /* in PKCS #11, Subject is a required field */
699     if (!sftk_hasAttribute(object, CKA_SUBJECT)) {
700         return CKR_TEMPLATE_INCOMPLETE;
701     }
702 
703     /* in PKCS #11, Issuer is a required field */
704     if (!sftk_hasAttribute(object, CKA_ISSUER)) {
705         return CKR_TEMPLATE_INCOMPLETE;
706     }
707 
708     /* in PKCS #11, Serial is a required field */
709     if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) {
710         return CKR_TEMPLATE_INCOMPLETE;
711     }
712 
713     /* add it to the object */
714     object->objectInfo = NULL;
715     object->infoFree = (SFTKFree)NULL;
716 
717     /* now just verify the required date fields */
718     crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
719     if (crv != CKR_OK) {
720         return crv;
721     }
722 
723     if (sftk_isTrue(object, CKA_TOKEN)) {
724         SFTKSlot *slot = session->slot;
725         SFTKDBHandle *certHandle = sftk_getCertDB(slot);
726 
727         if (certHandle == NULL) {
728             return CKR_TOKEN_WRITE_PROTECTED;
729         }
730 
731         crv = sftkdb_write(certHandle, object, &object->handle);
732         sftk_freeDB(certHandle);
733         return crv;
734     }
735 
736     return CKR_OK;
737 }
738 
739 /*
740  * check the consistancy and initialize a Trust Object
741  */
742 static CK_RV
sftk_handleTrustObject(SFTKSession * session,SFTKObject * object)743 sftk_handleTrustObject(SFTKSession *session, SFTKObject *object)
744 {
745     /* we can't store any certs private */
746     if (sftk_isTrue(object, CKA_PRIVATE)) {
747         return CKR_ATTRIBUTE_VALUE_INVALID;
748     }
749 
750     /* certificates must have a type */
751     if (!sftk_hasAttribute(object, CKA_ISSUER)) {
752         return CKR_TEMPLATE_INCOMPLETE;
753     }
754     if (!sftk_hasAttribute(object, CKA_SERIAL_NUMBER)) {
755         return CKR_TEMPLATE_INCOMPLETE;
756     }
757     if (!sftk_hasAttribute(object, CKA_CERT_SHA1_HASH)) {
758         return CKR_TEMPLATE_INCOMPLETE;
759     }
760     if (!sftk_hasAttribute(object, CKA_CERT_MD5_HASH)) {
761         return CKR_TEMPLATE_INCOMPLETE;
762     }
763 
764     if (sftk_isTrue(object, CKA_TOKEN)) {
765         SFTKSlot *slot = session->slot;
766         SFTKDBHandle *certHandle = sftk_getCertDB(slot);
767         CK_RV crv;
768 
769         if (certHandle == NULL) {
770             return CKR_TOKEN_WRITE_PROTECTED;
771         }
772 
773         crv = sftkdb_write(certHandle, object, &object->handle);
774         sftk_freeDB(certHandle);
775         return crv;
776     }
777 
778     return CKR_OK;
779 }
780 
781 /*
782  * check the consistancy and initialize a Trust Object
783  */
784 static CK_RV
sftk_handleSMimeObject(SFTKSession * session,SFTKObject * object)785 sftk_handleSMimeObject(SFTKSession *session, SFTKObject *object)
786 {
787 
788     /* we can't store any certs private */
789     if (sftk_isTrue(object, CKA_PRIVATE)) {
790         return CKR_ATTRIBUTE_VALUE_INVALID;
791     }
792 
793     /* certificates must have a type */
794     if (!sftk_hasAttribute(object, CKA_SUBJECT)) {
795         return CKR_TEMPLATE_INCOMPLETE;
796     }
797     if (!sftk_hasAttribute(object, CKA_NETSCAPE_EMAIL)) {
798         return CKR_TEMPLATE_INCOMPLETE;
799     }
800 
801     if (sftk_isTrue(object, CKA_TOKEN)) {
802         SFTKSlot *slot = session->slot;
803         SFTKDBHandle *certHandle;
804         CK_RV crv;
805 
806         PORT_Assert(slot);
807         if (slot == NULL) {
808             return CKR_SESSION_HANDLE_INVALID;
809         }
810 
811         certHandle = sftk_getCertDB(slot);
812         if (certHandle == NULL) {
813             return CKR_TOKEN_WRITE_PROTECTED;
814         }
815 
816         crv = sftkdb_write(certHandle, object, &object->handle);
817         sftk_freeDB(certHandle);
818         return crv;
819     }
820 
821     return CKR_OK;
822 }
823 
824 /*
825  * check the consistancy and initialize a Trust Object
826  */
827 static CK_RV
sftk_handleCrlObject(SFTKSession * session,SFTKObject * object)828 sftk_handleCrlObject(SFTKSession *session, SFTKObject *object)
829 {
830 
831     /* we can't store any certs private */
832     if (sftk_isTrue(object, CKA_PRIVATE)) {
833         return CKR_ATTRIBUTE_VALUE_INVALID;
834     }
835 
836     /* certificates must have a type */
837     if (!sftk_hasAttribute(object, CKA_SUBJECT)) {
838         return CKR_TEMPLATE_INCOMPLETE;
839     }
840     if (!sftk_hasAttribute(object, CKA_VALUE)) {
841         return CKR_TEMPLATE_INCOMPLETE;
842     }
843 
844     if (sftk_isTrue(object, CKA_TOKEN)) {
845         SFTKSlot *slot = session->slot;
846         SFTKDBHandle *certHandle = sftk_getCertDB(slot);
847         CK_RV crv;
848 
849         if (certHandle == NULL) {
850             return CKR_TOKEN_WRITE_PROTECTED;
851         }
852 
853         crv = sftkdb_write(certHandle, object, &object->handle);
854         sftk_freeDB(certHandle);
855         return crv;
856     }
857 
858     return CKR_OK;
859 }
860 
861 /*
862  * check the consistancy and initialize a Public Key Object
863  */
864 static CK_RV
sftk_handlePublicKeyObject(SFTKSession * session,SFTKObject * object,CK_KEY_TYPE key_type)865 sftk_handlePublicKeyObject(SFTKSession *session, SFTKObject *object,
866                            CK_KEY_TYPE key_type)
867 {
868     CK_BBOOL encrypt = CK_TRUE;
869     CK_BBOOL recover = CK_TRUE;
870     CK_BBOOL wrap = CK_TRUE;
871     CK_BBOOL derive = CK_FALSE;
872     CK_BBOOL verify = CK_TRUE;
873     CK_RV crv;
874 
875     switch (key_type) {
876         case CKK_RSA:
877             crv = sftk_ConstrainAttribute(object, CKA_MODULUS,
878                                           RSA_MIN_MODULUS_BITS, 0, 0);
879             if (crv != CKR_OK) {
880                 return crv;
881             }
882             crv = sftk_ConstrainAttribute(object, CKA_PUBLIC_EXPONENT, 2, 0, 0);
883             if (crv != CKR_OK) {
884                 return crv;
885             }
886             break;
887         case CKK_DSA:
888             crv = sftk_ConstrainAttribute(object, CKA_SUBPRIME,
889                                           DSA_MIN_Q_BITS, DSA_MAX_Q_BITS, 0);
890             if (crv != CKR_OK) {
891                 return crv;
892             }
893             crv = sftk_ConstrainAttribute(object, CKA_PRIME,
894                                           DSA_MIN_P_BITS, DSA_MAX_P_BITS, 64);
895             if (crv != CKR_OK) {
896                 return crv;
897             }
898             crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DSA_MAX_P_BITS, 0);
899             if (crv != CKR_OK) {
900                 return crv;
901             }
902             crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DSA_MAX_P_BITS, 0);
903             if (crv != CKR_OK) {
904                 return crv;
905             }
906             encrypt = CK_FALSE;
907             recover = CK_FALSE;
908             wrap = CK_FALSE;
909             break;
910         case CKK_DH:
911             crv = sftk_ConstrainAttribute(object, CKA_PRIME,
912                                           DH_MIN_P_BITS, DH_MAX_P_BITS, 0);
913             if (crv != CKR_OK) {
914                 return crv;
915             }
916             crv = sftk_ConstrainAttribute(object, CKA_BASE, 2, DH_MAX_P_BITS, 0);
917             if (crv != CKR_OK) {
918                 return crv;
919             }
920             crv = sftk_ConstrainAttribute(object, CKA_VALUE, 2, DH_MAX_P_BITS, 0);
921             if (crv != CKR_OK) {
922                 return crv;
923             }
924             verify = CK_FALSE;
925             derive = CK_TRUE;
926             encrypt = CK_FALSE;
927             recover = CK_FALSE;
928             wrap = CK_FALSE;
929             break;
930 #ifndef NSS_DISABLE_ECC
931         case CKK_EC:
932             if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) {
933                 return CKR_TEMPLATE_INCOMPLETE;
934             }
935             if (!sftk_hasAttribute(object, CKA_EC_POINT)) {
936                 return CKR_TEMPLATE_INCOMPLETE;
937             }
938             derive = CK_TRUE; /* for ECDH */
939             verify = CK_TRUE; /* for ECDSA */
940             encrypt = CK_FALSE;
941             recover = CK_FALSE;
942             wrap = CK_FALSE;
943             break;
944 #endif /* NSS_DISABLE_ECC */
945         default:
946             return CKR_ATTRIBUTE_VALUE_INVALID;
947     }
948 
949     /* make sure the required fields exist */
950     crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
951     if (crv != CKR_OK)
952         return crv;
953     crv = sftk_defaultAttribute(object, CKA_ENCRYPT, &encrypt, sizeof(CK_BBOOL));
954     if (crv != CKR_OK)
955         return crv;
956     crv = sftk_defaultAttribute(object, CKA_VERIFY, &verify, sizeof(CK_BBOOL));
957     if (crv != CKR_OK)
958         return crv;
959     crv = sftk_defaultAttribute(object, CKA_VERIFY_RECOVER,
960                                 &recover, sizeof(CK_BBOOL));
961     if (crv != CKR_OK)
962         return crv;
963     crv = sftk_defaultAttribute(object, CKA_WRAP, &wrap, sizeof(CK_BBOOL));
964     if (crv != CKR_OK)
965         return crv;
966     crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
967     if (crv != CKR_OK)
968         return crv;
969 
970     object->objectInfo = sftk_GetPubKey(object, key_type, &crv);
971     if (object->objectInfo == NULL) {
972         return crv;
973     }
974     object->infoFree = (SFTKFree)nsslowkey_DestroyPublicKey;
975 
976     /* Check that an imported EC key is valid */
977     if (key_type == CKK_EC) {
978         NSSLOWKEYPublicKey *pubKey = (NSSLOWKEYPublicKey *)object->objectInfo;
979         SECStatus rv = EC_ValidatePublicKey(&pubKey->u.ec.ecParams,
980                                             &pubKey->u.ec.publicValue);
981 
982         if (rv != SECSuccess) {
983             return CKR_TEMPLATE_INCONSISTENT;
984         }
985     }
986 
987     if (sftk_isTrue(object, CKA_TOKEN)) {
988         SFTKSlot *slot = session->slot;
989         SFTKDBHandle *certHandle = sftk_getCertDB(slot);
990 
991         if (certHandle == NULL) {
992             return CKR_TOKEN_WRITE_PROTECTED;
993         }
994 
995         crv = sftkdb_write(certHandle, object, &object->handle);
996         sftk_freeDB(certHandle);
997         return crv;
998     }
999 
1000     return CKR_OK;
1001 }
1002 
1003 static NSSLOWKEYPrivateKey *
1004 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key, CK_RV *rvp);
1005 
1006 static SECStatus
1007 sftk_verifyRSAPrivateKey(SFTKObject *object, PRBool fillIfNeeded);
1008 
1009 /*
1010  * check the consistancy and initialize a Private Key Object
1011  */
1012 static CK_RV
sftk_handlePrivateKeyObject(SFTKSession * session,SFTKObject * object,CK_KEY_TYPE key_type)1013 sftk_handlePrivateKeyObject(SFTKSession *session, SFTKObject *object, CK_KEY_TYPE key_type)
1014 {
1015     CK_BBOOL cktrue = CK_TRUE;
1016     CK_BBOOL encrypt = CK_TRUE;
1017     CK_BBOOL sign = CK_FALSE;
1018     CK_BBOOL recover = CK_TRUE;
1019     CK_BBOOL wrap = CK_TRUE;
1020     CK_BBOOL derive = CK_TRUE;
1021     CK_BBOOL ckfalse = CK_FALSE;
1022     PRBool createObjectInfo = PR_TRUE;
1023     PRBool fillPrivateKey = PR_FALSE;
1024     int missing_rsa_mod_component = 0;
1025     int missing_rsa_exp_component = 0;
1026     int missing_rsa_crt_component = 0;
1027 
1028     SECItem mod;
1029     CK_RV crv;
1030     SECStatus rv;
1031 
1032     switch (key_type) {
1033         case CKK_RSA:
1034             if (!sftk_hasAttribute(object, CKA_MODULUS)) {
1035                 missing_rsa_mod_component++;
1036             }
1037             if (!sftk_hasAttribute(object, CKA_PUBLIC_EXPONENT)) {
1038                 missing_rsa_exp_component++;
1039             }
1040             if (!sftk_hasAttribute(object, CKA_PRIVATE_EXPONENT)) {
1041                 missing_rsa_exp_component++;
1042             }
1043             if (!sftk_hasAttribute(object, CKA_PRIME_1)) {
1044                 missing_rsa_mod_component++;
1045             }
1046             if (!sftk_hasAttribute(object, CKA_PRIME_2)) {
1047                 missing_rsa_mod_component++;
1048             }
1049             if (!sftk_hasAttribute(object, CKA_EXPONENT_1)) {
1050                 missing_rsa_crt_component++;
1051             }
1052             if (!sftk_hasAttribute(object, CKA_EXPONENT_2)) {
1053                 missing_rsa_crt_component++;
1054             }
1055             if (!sftk_hasAttribute(object, CKA_COEFFICIENT)) {
1056                 missing_rsa_crt_component++;
1057             }
1058             if (missing_rsa_mod_component || missing_rsa_exp_component ||
1059                 missing_rsa_crt_component) {
1060                 /* we are missing a component, see if we have enough to rebuild
1061                  * the rest */
1062                 int have_exp = 2 - missing_rsa_exp_component;
1063                 int have_component = 5 -
1064                                      (missing_rsa_exp_component + missing_rsa_mod_component);
1065 
1066                 if ((have_exp == 0) || (have_component < 3)) {
1067                     /* nope, not enough to reconstruct the private key */
1068                     return CKR_TEMPLATE_INCOMPLETE;
1069                 }
1070                 fillPrivateKey = PR_TRUE;
1071             }
1072             /*verify the parameters for consistency*/
1073             rv = sftk_verifyRSAPrivateKey(object, fillPrivateKey);
1074             if (rv != SECSuccess) {
1075                 return CKR_TEMPLATE_INCOMPLETE;
1076             }
1077 
1078             /* make sure Netscape DB attribute is set correctly */
1079             crv = sftk_Attribute2SSecItem(NULL, &mod, object, CKA_MODULUS);
1080             if (crv != CKR_OK)
1081                 return crv;
1082             crv = sftk_forceAttribute(object, CKA_NETSCAPE_DB,
1083                                       sftk_item_expand(&mod));
1084             if (mod.data)
1085                 PORT_Free(mod.data);
1086             if (crv != CKR_OK)
1087                 return crv;
1088 
1089             sign = CK_TRUE;
1090             derive = CK_FALSE;
1091             break;
1092         case CKK_DSA:
1093             if (!sftk_hasAttribute(object, CKA_SUBPRIME)) {
1094                 return CKR_TEMPLATE_INCOMPLETE;
1095             }
1096             sign = CK_TRUE;
1097             derive = CK_FALSE;
1098         /* fall through */
1099         case CKK_DH:
1100             if (!sftk_hasAttribute(object, CKA_PRIME)) {
1101                 return CKR_TEMPLATE_INCOMPLETE;
1102             }
1103             if (!sftk_hasAttribute(object, CKA_BASE)) {
1104                 return CKR_TEMPLATE_INCOMPLETE;
1105             }
1106             if (!sftk_hasAttribute(object, CKA_VALUE)) {
1107                 return CKR_TEMPLATE_INCOMPLETE;
1108             }
1109             encrypt = CK_FALSE;
1110             recover = CK_FALSE;
1111             wrap = CK_FALSE;
1112             break;
1113 #ifndef NSS_DISABLE_ECC
1114         case CKK_EC:
1115             if (!sftk_hasAttribute(object, CKA_EC_PARAMS)) {
1116                 return CKR_TEMPLATE_INCOMPLETE;
1117             }
1118             if (!sftk_hasAttribute(object, CKA_VALUE)) {
1119                 return CKR_TEMPLATE_INCOMPLETE;
1120             }
1121             encrypt = CK_FALSE;
1122             sign = CK_TRUE;
1123             recover = CK_FALSE;
1124             wrap = CK_FALSE;
1125             break;
1126 #endif /* NSS_DISABLE_ECC */
1127         case CKK_NSS_JPAKE_ROUND1:
1128             if (!sftk_hasAttribute(object, CKA_PRIME) ||
1129                 !sftk_hasAttribute(object, CKA_SUBPRIME) ||
1130                 !sftk_hasAttribute(object, CKA_BASE)) {
1131                 return CKR_TEMPLATE_INCOMPLETE;
1132             }
1133         /* fall through */
1134         case CKK_NSS_JPAKE_ROUND2:
1135             /* CKA_NSS_JPAKE_SIGNERID and CKA_NSS_JPAKE_PEERID are checked in
1136                the J-PAKE code. */
1137             encrypt = sign = recover = wrap = CK_FALSE;
1138             derive = CK_TRUE;
1139             createObjectInfo = PR_FALSE;
1140             break;
1141         default:
1142             return CKR_ATTRIBUTE_VALUE_INVALID;
1143     }
1144     crv = sftk_defaultAttribute(object, CKA_SUBJECT, NULL, 0);
1145     if (crv != CKR_OK)
1146         return crv;
1147     crv = sftk_defaultAttribute(object, CKA_SENSITIVE, &cktrue, sizeof(CK_BBOOL));
1148     if (crv != CKR_OK)
1149         return crv;
1150     crv = sftk_defaultAttribute(object, CKA_EXTRACTABLE, &cktrue, sizeof(CK_BBOOL));
1151     if (crv != CKR_OK)
1152         return crv;
1153     crv = sftk_defaultAttribute(object, CKA_DECRYPT, &encrypt, sizeof(CK_BBOOL));
1154     if (crv != CKR_OK)
1155         return crv;
1156     crv = sftk_defaultAttribute(object, CKA_SIGN, &sign, sizeof(CK_BBOOL));
1157     if (crv != CKR_OK)
1158         return crv;
1159     crv = sftk_defaultAttribute(object, CKA_SIGN_RECOVER, &recover,
1160                                 sizeof(CK_BBOOL));
1161     if (crv != CKR_OK)
1162         return crv;
1163     crv = sftk_defaultAttribute(object, CKA_UNWRAP, &wrap, sizeof(CK_BBOOL));
1164     if (crv != CKR_OK)
1165         return crv;
1166     crv = sftk_defaultAttribute(object, CKA_DERIVE, &derive, sizeof(CK_BBOOL));
1167     if (crv != CKR_OK)
1168         return crv;
1169     /* the next two bits get modified only in the key gen and token cases */
1170     crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
1171                               &ckfalse, sizeof(CK_BBOOL));
1172     if (crv != CKR_OK)
1173         return crv;
1174     crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
1175                               &ckfalse, sizeof(CK_BBOOL));
1176     if (crv != CKR_OK)
1177         return crv;
1178 
1179     /* should we check the non-token RSA private keys? */
1180 
1181     if (sftk_isTrue(object, CKA_TOKEN)) {
1182         SFTKSlot *slot = session->slot;
1183         SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
1184 
1185         if (keyHandle == NULL) {
1186             return CKR_TOKEN_WRITE_PROTECTED;
1187         }
1188 
1189         crv = sftkdb_write(keyHandle, object, &object->handle);
1190         sftk_freeDB(keyHandle);
1191         return crv;
1192     } else if (createObjectInfo) {
1193         object->objectInfo = sftk_mkPrivKey(object, key_type, &crv);
1194         if (object->objectInfo == NULL)
1195             return crv;
1196         object->infoFree = (SFTKFree)nsslowkey_DestroyPrivateKey;
1197     }
1198     return CKR_OK;
1199 }
1200 
1201 /* forward declare the DES formating function for handleSecretKey */
1202 void sftk_FormatDESKey(unsigned char *key, int length);
1203 
1204 /* Validate secret key data, and set defaults */
1205 static CK_RV
validateSecretKey(SFTKSession * session,SFTKObject * object,CK_KEY_TYPE key_type,PRBool isFIPS)1206 validateSecretKey(SFTKSession *session, SFTKObject *object,
1207                   CK_KEY_TYPE key_type, PRBool isFIPS)
1208 {
1209     CK_RV crv;
1210     CK_BBOOL cktrue = CK_TRUE;
1211     CK_BBOOL ckfalse = CK_FALSE;
1212     SFTKAttribute *attribute = NULL;
1213     unsigned long requiredLen;
1214 
1215     crv = sftk_defaultAttribute(object, CKA_SENSITIVE,
1216                                 isFIPS ? &cktrue : &ckfalse, sizeof(CK_BBOOL));
1217     if (crv != CKR_OK)
1218         return crv;
1219     crv = sftk_defaultAttribute(object, CKA_EXTRACTABLE,
1220                                 &cktrue, sizeof(CK_BBOOL));
1221     if (crv != CKR_OK)
1222         return crv;
1223     crv = sftk_defaultAttribute(object, CKA_ENCRYPT, &cktrue, sizeof(CK_BBOOL));
1224     if (crv != CKR_OK)
1225         return crv;
1226     crv = sftk_defaultAttribute(object, CKA_DECRYPT, &cktrue, sizeof(CK_BBOOL));
1227     if (crv != CKR_OK)
1228         return crv;
1229     crv = sftk_defaultAttribute(object, CKA_SIGN, &ckfalse, sizeof(CK_BBOOL));
1230     if (crv != CKR_OK)
1231         return crv;
1232     crv = sftk_defaultAttribute(object, CKA_VERIFY, &ckfalse, sizeof(CK_BBOOL));
1233     if (crv != CKR_OK)
1234         return crv;
1235     crv = sftk_defaultAttribute(object, CKA_WRAP, &cktrue, sizeof(CK_BBOOL));
1236     if (crv != CKR_OK)
1237         return crv;
1238     crv = sftk_defaultAttribute(object, CKA_UNWRAP, &cktrue, sizeof(CK_BBOOL));
1239     if (crv != CKR_OK)
1240         return crv;
1241 
1242     if (!sftk_hasAttribute(object, CKA_VALUE)) {
1243         return CKR_TEMPLATE_INCOMPLETE;
1244     }
1245     /* the next two bits get modified only in the key gen and token cases */
1246     crv = sftk_forceAttribute(object, CKA_ALWAYS_SENSITIVE,
1247                               &ckfalse, sizeof(CK_BBOOL));
1248     if (crv != CKR_OK)
1249         return crv;
1250     crv = sftk_forceAttribute(object, CKA_NEVER_EXTRACTABLE,
1251                               &ckfalse, sizeof(CK_BBOOL));
1252     if (crv != CKR_OK)
1253         return crv;
1254 
1255     /* some types of keys have a value length */
1256     crv = CKR_OK;
1257     switch (key_type) {
1258         /* force CKA_VALUE_LEN to be set */
1259         case CKK_GENERIC_SECRET:
1260         case CKK_RC2:
1261         case CKK_RC4:
1262 #if NSS_SOFTOKEN_DOES_RC5
1263         case CKK_RC5:
1264 #endif
1265 #ifdef NSS_SOFTOKEN_DOES_CAST
1266         case CKK_CAST:
1267         case CKK_CAST3:
1268         case CKK_CAST5:
1269 #endif
1270 #if NSS_SOFTOKEN_DOES_IDEA
1271         case CKK_IDEA:
1272 #endif
1273             attribute = sftk_FindAttribute(object, CKA_VALUE);
1274             /* shouldn't happen */
1275             if (attribute == NULL)
1276                 return CKR_TEMPLATE_INCOMPLETE;
1277             crv = sftk_forceAttribute(object, CKA_VALUE_LEN,
1278                                       &attribute->attrib.ulValueLen, sizeof(CK_ULONG));
1279             sftk_FreeAttribute(attribute);
1280             break;
1281         /* force the value to have the correct parity */
1282         case CKK_DES:
1283         case CKK_DES2:
1284         case CKK_DES3:
1285         case CKK_CDMF:
1286             attribute = sftk_FindAttribute(object, CKA_VALUE);
1287             /* shouldn't happen */
1288             if (attribute == NULL)
1289                 return CKR_TEMPLATE_INCOMPLETE;
1290             requiredLen = sftk_MapKeySize(key_type);
1291             if (attribute->attrib.ulValueLen != requiredLen) {
1292                 sftk_FreeAttribute(attribute);
1293                 return CKR_KEY_SIZE_RANGE;
1294             }
1295             sftk_FormatDESKey((unsigned char *)attribute->attrib.pValue,
1296                               attribute->attrib.ulValueLen);
1297             sftk_FreeAttribute(attribute);
1298             break;
1299         case CKK_AES:
1300             attribute = sftk_FindAttribute(object, CKA_VALUE);
1301             /* shouldn't happen */
1302             if (attribute == NULL)
1303                 return CKR_TEMPLATE_INCOMPLETE;
1304             if (attribute->attrib.ulValueLen != 16 &&
1305                 attribute->attrib.ulValueLen != 24 &&
1306                 attribute->attrib.ulValueLen != 32) {
1307                 sftk_FreeAttribute(attribute);
1308                 return CKR_KEY_SIZE_RANGE;
1309             }
1310             crv = sftk_forceAttribute(object, CKA_VALUE_LEN,
1311                                       &attribute->attrib.ulValueLen, sizeof(CK_ULONG));
1312             sftk_FreeAttribute(attribute);
1313             break;
1314         default:
1315             break;
1316     }
1317 
1318     return crv;
1319 }
1320 
1321 /*
1322  * check the consistancy and initialize a Secret Key Object
1323  */
1324 static CK_RV
sftk_handleSecretKeyObject(SFTKSession * session,SFTKObject * object,CK_KEY_TYPE key_type,PRBool isFIPS)1325 sftk_handleSecretKeyObject(SFTKSession *session, SFTKObject *object,
1326                            CK_KEY_TYPE key_type, PRBool isFIPS)
1327 {
1328     CK_RV crv;
1329 
1330     /* First validate and set defaults */
1331     crv = validateSecretKey(session, object, key_type, isFIPS);
1332     if (crv != CKR_OK)
1333         goto loser;
1334 
1335     /* If the object is a TOKEN object, store in the database */
1336     if (sftk_isTrue(object, CKA_TOKEN)) {
1337         SFTKSlot *slot = session->slot;
1338         SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
1339         CK_RV crv;
1340 
1341         if (keyHandle == NULL) {
1342             return CKR_TOKEN_WRITE_PROTECTED;
1343         }
1344 
1345         crv = sftkdb_write(keyHandle, object, &object->handle);
1346         sftk_freeDB(keyHandle);
1347         return crv;
1348     }
1349 
1350 loser:
1351 
1352     return crv;
1353 }
1354 
1355 /*
1356  * check the consistancy and initialize a Key Object
1357  */
1358 static CK_RV
sftk_handleKeyObject(SFTKSession * session,SFTKObject * object)1359 sftk_handleKeyObject(SFTKSession *session, SFTKObject *object)
1360 {
1361     SFTKAttribute *attribute;
1362     CK_KEY_TYPE key_type;
1363     CK_BBOOL ckfalse = CK_FALSE;
1364     CK_RV crv;
1365 
1366     /* verify the required fields */
1367     if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
1368         return CKR_TEMPLATE_INCOMPLETE;
1369     }
1370 
1371     /* now verify the common fields */
1372     crv = sftk_defaultAttribute(object, CKA_ID, NULL, 0);
1373     if (crv != CKR_OK)
1374         return crv;
1375     crv = sftk_defaultAttribute(object, CKA_START_DATE, NULL, 0);
1376     if (crv != CKR_OK)
1377         return crv;
1378     crv = sftk_defaultAttribute(object, CKA_END_DATE, NULL, 0);
1379     if (crv != CKR_OK)
1380         return crv;
1381     /* CKA_DERIVE is common to all keys, but it's default value is
1382      * key dependent */
1383     crv = sftk_defaultAttribute(object, CKA_LOCAL, &ckfalse, sizeof(CK_BBOOL));
1384     if (crv != CKR_OK)
1385         return crv;
1386 
1387     /* get the key type */
1388     attribute = sftk_FindAttribute(object, CKA_KEY_TYPE);
1389     if (!attribute) {
1390         return CKR_ATTRIBUTE_VALUE_INVALID;
1391     }
1392     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
1393     sftk_FreeAttribute(attribute);
1394 
1395     switch (object->objclass) {
1396         case CKO_PUBLIC_KEY:
1397             return sftk_handlePublicKeyObject(session, object, key_type);
1398         case CKO_PRIVATE_KEY:
1399             return sftk_handlePrivateKeyObject(session, object, key_type);
1400         case CKO_SECRET_KEY:
1401             /* make sure the required fields exist */
1402             return sftk_handleSecretKeyObject(session, object, key_type,
1403                                               (PRBool)(session->slot->slotID == FIPS_SLOT_ID));
1404         default:
1405             break;
1406     }
1407     return CKR_ATTRIBUTE_VALUE_INVALID;
1408 }
1409 
1410 /*
1411  * check the consistancy and Verify a DSA Parameter Object
1412  */
1413 static CK_RV
sftk_handleDSAParameterObject(SFTKSession * session,SFTKObject * object)1414 sftk_handleDSAParameterObject(SFTKSession *session, SFTKObject *object)
1415 {
1416     SFTKAttribute *primeAttr = NULL;
1417     SFTKAttribute *subPrimeAttr = NULL;
1418     SFTKAttribute *baseAttr = NULL;
1419     SFTKAttribute *seedAttr = NULL;
1420     SFTKAttribute *hAttr = NULL;
1421     SFTKAttribute *attribute;
1422     CK_RV crv = CKR_TEMPLATE_INCOMPLETE;
1423     PQGParams params;
1424     PQGVerify vfy, *verify = NULL;
1425     SECStatus result, rv;
1426     /* This bool keeps track of whether or not we need verify parameters.
1427      * If a P, Q and G or supplied, we dont' need verify parameters, as we
1428      * have PQ and G.
1429      *   - If G is not supplied, the presumption is that we want to
1430      * verify P and Q only.
1431      *   - If counter is supplied, it is presumed we want to verify PQ because
1432      * the counter is only used in verification.
1433      *   - If H is supplied, is is presumed we want to verify G because H is
1434      * only used to verify G.
1435      *   - Any verification step must have the SEED (counter or H could be
1436      * missing depending on exactly what we want to verify). If SEED is supplied,
1437      * the code just goes ahead and runs verify (other errors are parameter
1438      * errors are detected by the PQG_VerifyParams function). If SEED is not
1439      * supplied, but we determined that we are trying to verify (because needVfy
1440      * is set, go ahead and return CKR_TEMPLATE_INCOMPLETE.
1441      */
1442     PRBool needVfy = PR_FALSE;
1443 
1444     primeAttr = sftk_FindAttribute(object, CKA_PRIME);
1445     if (primeAttr == NULL)
1446         goto loser;
1447     params.prime.data = primeAttr->attrib.pValue;
1448     params.prime.len = primeAttr->attrib.ulValueLen;
1449 
1450     subPrimeAttr = sftk_FindAttribute(object, CKA_SUBPRIME);
1451     if (subPrimeAttr == NULL)
1452         goto loser;
1453     params.subPrime.data = subPrimeAttr->attrib.pValue;
1454     params.subPrime.len = subPrimeAttr->attrib.ulValueLen;
1455 
1456     baseAttr = sftk_FindAttribute(object, CKA_BASE);
1457     if (baseAttr != NULL) {
1458         params.base.data = baseAttr->attrib.pValue;
1459         params.base.len = baseAttr->attrib.ulValueLen;
1460     } else {
1461         params.base.data = NULL;
1462         params.base.len = 0;
1463         needVfy = PR_TRUE; /* presumably only including PQ so we can verify
1464                             * them. */
1465     }
1466 
1467     attribute = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_COUNTER);
1468     if (attribute != NULL) {
1469         vfy.counter = *(CK_ULONG *)attribute->attrib.pValue;
1470         sftk_FreeAttribute(attribute);
1471         needVfy = PR_TRUE; /* included a count so we can verify PQ */
1472     } else {
1473         vfy.counter = -1;
1474     }
1475 
1476     hAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_H);
1477     if (hAttr != NULL) {
1478         vfy.h.data = hAttr->attrib.pValue;
1479         vfy.h.len = hAttr->attrib.ulValueLen;
1480         needVfy = PR_TRUE; /* included H so we can verify G */
1481     } else {
1482         vfy.h.data = NULL;
1483         vfy.h.len = 0;
1484     }
1485     seedAttr = sftk_FindAttribute(object, CKA_NETSCAPE_PQG_SEED);
1486     if (seedAttr != NULL) {
1487         vfy.seed.data = seedAttr->attrib.pValue;
1488         vfy.seed.len = seedAttr->attrib.ulValueLen;
1489 
1490         verify = &vfy;
1491     } else if (needVfy) {
1492         goto loser; /* Verify always needs seed, if we need verify and not seed
1493                      * then fail */
1494     }
1495 
1496     crv = CKR_FUNCTION_FAILED;
1497     rv = PQG_VerifyParams(&params, verify, &result);
1498     if (rv == SECSuccess) {
1499         crv = (result == SECSuccess) ? CKR_OK : CKR_ATTRIBUTE_VALUE_INVALID;
1500     }
1501 
1502 loser:
1503     if (hAttr)
1504         sftk_FreeAttribute(hAttr);
1505     if (seedAttr)
1506         sftk_FreeAttribute(seedAttr);
1507     if (baseAttr)
1508         sftk_FreeAttribute(baseAttr);
1509     if (subPrimeAttr)
1510         sftk_FreeAttribute(subPrimeAttr);
1511     if (primeAttr)
1512         sftk_FreeAttribute(primeAttr);
1513 
1514     return crv;
1515 }
1516 
1517 /*
1518  * check the consistancy and initialize a Key Parameter Object
1519  */
1520 static CK_RV
sftk_handleKeyParameterObject(SFTKSession * session,SFTKObject * object)1521 sftk_handleKeyParameterObject(SFTKSession *session, SFTKObject *object)
1522 {
1523     SFTKAttribute *attribute;
1524     CK_KEY_TYPE key_type;
1525     CK_BBOOL ckfalse = CK_FALSE;
1526     CK_RV crv;
1527 
1528     /* verify the required fields */
1529     if (!sftk_hasAttribute(object, CKA_KEY_TYPE)) {
1530         return CKR_TEMPLATE_INCOMPLETE;
1531     }
1532 
1533     /* now verify the common fields */
1534     crv = sftk_defaultAttribute(object, CKA_LOCAL, &ckfalse, sizeof(CK_BBOOL));
1535     if (crv != CKR_OK)
1536         return crv;
1537 
1538     /* get the key type */
1539     attribute = sftk_FindAttribute(object, CKA_KEY_TYPE);
1540     if (!attribute) {
1541         return CKR_ATTRIBUTE_VALUE_INVALID;
1542     }
1543     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;
1544     sftk_FreeAttribute(attribute);
1545 
1546     switch (key_type) {
1547         case CKK_DSA:
1548             return sftk_handleDSAParameterObject(session, object);
1549 
1550         default:
1551             break;
1552     }
1553     return CKR_KEY_TYPE_INCONSISTENT;
1554 }
1555 
1556 /*
1557  * Handle Object does all the object consistancy checks, automatic attribute
1558  * generation, attribute defaulting, etc. If handleObject succeeds, the object
1559  * will be assigned an object handle, and the object installed in the session
1560  * or stored in the DB.
1561  */
1562 CK_RV
sftk_handleObject(SFTKObject * object,SFTKSession * session)1563 sftk_handleObject(SFTKObject *object, SFTKSession *session)
1564 {
1565     SFTKSlot *slot = session->slot;
1566     SFTKAttribute *attribute;
1567     SFTKObject *duplicateObject = NULL;
1568     CK_OBJECT_HANDLE handle;
1569     CK_BBOOL ckfalse = CK_FALSE;
1570     CK_BBOOL cktrue = CK_TRUE;
1571     CK_RV crv;
1572 
1573     /* make sure all the base object types are defined. If not set the
1574      * defaults */
1575     crv = sftk_defaultAttribute(object, CKA_TOKEN, &ckfalse, sizeof(CK_BBOOL));
1576     if (crv != CKR_OK)
1577         return crv;
1578     crv = sftk_defaultAttribute(object, CKA_PRIVATE, &ckfalse, sizeof(CK_BBOOL));
1579     if (crv != CKR_OK)
1580         return crv;
1581     crv = sftk_defaultAttribute(object, CKA_LABEL, NULL, 0);
1582     if (crv != CKR_OK)
1583         return crv;
1584     crv = sftk_defaultAttribute(object, CKA_MODIFIABLE, &cktrue, sizeof(CK_BBOOL));
1585     if (crv != CKR_OK)
1586         return crv;
1587 
1588     /* don't create a private object if we aren't logged in */
1589     if ((!slot->isLoggedIn) && (slot->needLogin) &&
1590         (sftk_isTrue(object, CKA_PRIVATE))) {
1591         return CKR_USER_NOT_LOGGED_IN;
1592     }
1593 
1594     if (((session->info.flags & CKF_RW_SESSION) == 0) &&
1595         (sftk_isTrue(object, CKA_TOKEN))) {
1596         return CKR_SESSION_READ_ONLY;
1597     }
1598 
1599     /* Assign a unique SESSION object handle to every new object,
1600      * whether it is a session object or a token object.
1601      * At this point, all new objects are structured as session objects.
1602      * Objects with the CKA_TOKEN attribute true will be turned into
1603      * token objects and will have a token object handle assigned to
1604      * them by a call to sftk_mkHandle in the handler for each object
1605      * class, invoked below.
1606      *
1607      * It may be helpful to note/remember that
1608      * sftk_narrowToXxxObject uses sftk_isToken,
1609      * sftk_isToken examines the sign bit of the object's handle, but
1610      * sftk_isTrue(...,CKA_TOKEN) examines the CKA_TOKEN attribute.
1611      */
1612     do {
1613         PRUint32 wrappedAround;
1614 
1615         duplicateObject = NULL;
1616         PZ_Lock(slot->objectLock);
1617         wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;
1618         handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;
1619         if (!handle) /* don't allow zero handle */
1620             handle = minSessionObjectHandle;
1621         slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;
1622         /* Is there already a session object with this handle? */
1623         if (wrappedAround) {
1624             sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,
1625                            slot->sessObjHashSize);
1626         }
1627         PZ_Unlock(slot->objectLock);
1628     } while (duplicateObject != NULL);
1629     object->handle = handle;
1630 
1631     /* get the object class */
1632     attribute = sftk_FindAttribute(object, CKA_CLASS);
1633     if (attribute == NULL) {
1634         return CKR_TEMPLATE_INCOMPLETE;
1635     }
1636     object->objclass = *(CK_OBJECT_CLASS *)attribute->attrib.pValue;
1637     sftk_FreeAttribute(attribute);
1638 
1639     /* Now handle the specific object class.
1640      * At this point, all objects are session objects, and the session
1641      * number must be passed to the object class handlers.
1642      */
1643     switch (object->objclass) {
1644         case CKO_DATA:
1645             crv = sftk_handleDataObject(session, object);
1646             break;
1647         case CKO_CERTIFICATE:
1648             crv = sftk_handleCertObject(session, object);
1649             break;
1650         case CKO_NETSCAPE_TRUST:
1651             crv = sftk_handleTrustObject(session, object);
1652             break;
1653         case CKO_NETSCAPE_CRL:
1654             crv = sftk_handleCrlObject(session, object);
1655             break;
1656         case CKO_NETSCAPE_SMIME:
1657             crv = sftk_handleSMimeObject(session, object);
1658             break;
1659         case CKO_PRIVATE_KEY:
1660         case CKO_PUBLIC_KEY:
1661         case CKO_SECRET_KEY:
1662             crv = sftk_handleKeyObject(session, object);
1663             break;
1664         case CKO_KG_PARAMETERS:
1665             crv = sftk_handleKeyParameterObject(session, object);
1666             break;
1667         default:
1668             crv = CKR_ATTRIBUTE_VALUE_INVALID;
1669             break;
1670     }
1671 
1672     /* can't fail from here on out unless the pk_handlXXX functions have
1673      * failed the request */
1674     if (crv != CKR_OK) {
1675         return crv;
1676     }
1677 
1678     /* Now link the object into the slot and session structures.
1679      * If the object has a true CKA_TOKEN attribute, the above object
1680      * class handlers will have set the sign bit in the object handle,
1681      * causing the following test to be true.
1682      */
1683     if (sftk_isToken(object->handle)) {
1684         sftk_convertSessionToToken(object);
1685     } else {
1686         object->slot = slot;
1687         sftk_AddObject(session, object);
1688     }
1689 
1690     return CKR_OK;
1691 }
1692 
1693 /*
1694  * ******************** Public Key Utilities ***************************
1695  */
1696 /* Generate a low public key structure from an object */
1697 NSSLOWKEYPublicKey *
sftk_GetPubKey(SFTKObject * object,CK_KEY_TYPE key_type,CK_RV * crvp)1698 sftk_GetPubKey(SFTKObject *object, CK_KEY_TYPE key_type,
1699                CK_RV *crvp)
1700 {
1701     NSSLOWKEYPublicKey *pubKey;
1702     PLArenaPool *arena;
1703     CK_RV crv;
1704 
1705     if (object->objclass != CKO_PUBLIC_KEY) {
1706         *crvp = CKR_KEY_TYPE_INCONSISTENT;
1707         return NULL;
1708     }
1709 
1710     if (sftk_isToken(object->handle)) {
1711         /* ferret out the token object handle */
1712     }
1713 
1714     /* If we already have a key, use it */
1715     if (object->objectInfo) {
1716         *crvp = CKR_OK;
1717         return (NSSLOWKEYPublicKey *)object->objectInfo;
1718     }
1719 
1720     /* allocate the structure */
1721     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1722     if (arena == NULL) {
1723         *crvp = CKR_HOST_MEMORY;
1724         return NULL;
1725     }
1726 
1727     pubKey = (NSSLOWKEYPublicKey *)
1728         PORT_ArenaAlloc(arena, sizeof(NSSLOWKEYPublicKey));
1729     if (pubKey == NULL) {
1730         PORT_FreeArena(arena, PR_FALSE);
1731         *crvp = CKR_HOST_MEMORY;
1732         return NULL;
1733     }
1734 
1735     /* fill in the structure */
1736     pubKey->arena = arena;
1737     switch (key_type) {
1738         case CKK_RSA:
1739             pubKey->keyType = NSSLOWKEYRSAKey;
1740             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.rsa.modulus,
1741                                           object, CKA_MODULUS);
1742             if (crv != CKR_OK)
1743                 break;
1744             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.rsa.publicExponent,
1745                                           object, CKA_PUBLIC_EXPONENT);
1746             break;
1747         case CKK_DSA:
1748             pubKey->keyType = NSSLOWKEYDSAKey;
1749             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.params.prime,
1750                                           object, CKA_PRIME);
1751             if (crv != CKR_OK)
1752                 break;
1753             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.params.subPrime,
1754                                           object, CKA_SUBPRIME);
1755             if (crv != CKR_OK)
1756                 break;
1757             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.params.base,
1758                                           object, CKA_BASE);
1759             if (crv != CKR_OK)
1760                 break;
1761             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dsa.publicValue,
1762                                           object, CKA_VALUE);
1763             break;
1764         case CKK_DH:
1765             pubKey->keyType = NSSLOWKEYDHKey;
1766             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.prime,
1767                                           object, CKA_PRIME);
1768             if (crv != CKR_OK)
1769                 break;
1770             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.base,
1771                                           object, CKA_BASE);
1772             if (crv != CKR_OK)
1773                 break;
1774             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.dh.publicValue,
1775                                           object, CKA_VALUE);
1776             break;
1777 #ifndef NSS_DISABLE_ECC
1778         case CKK_EC:
1779             pubKey->keyType = NSSLOWKEYECKey;
1780             crv = sftk_Attribute2SSecItem(arena,
1781                                           &pubKey->u.ec.ecParams.DEREncoding,
1782                                           object, CKA_EC_PARAMS);
1783             if (crv != CKR_OK)
1784                 break;
1785 
1786             /* Fill out the rest of the ecParams structure
1787              * based on the encoded params
1788              */
1789             if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding,
1790                               &pubKey->u.ec.ecParams) != SECSuccess) {
1791                 crv = CKR_DOMAIN_PARAMS_INVALID;
1792                 break;
1793             }
1794 
1795             crv = sftk_Attribute2SSecItem(arena, &pubKey->u.ec.publicValue,
1796                                           object, CKA_EC_POINT);
1797             if (crv == CKR_OK) {
1798                 unsigned int keyLen = EC_GetPointSize(&pubKey->u.ec.ecParams);
1799 
1800                 /* special note: We can't just use the first byte to distinguish
1801                  * between EC_POINT_FORM_UNCOMPRESSED and SEC_ASN1_OCTET_STRING.
1802                  * Both are 0x04. */
1803 
1804                 /* Handle the non-DER encoded case.
1805                  * Some curves are always pressumed to be non-DER.
1806                  */
1807                 if (pubKey->u.ec.publicValue.len == keyLen &&
1808                     (pubKey->u.ec.ecParams.fieldID.type == ec_field_plain ||
1809                      pubKey->u.ec.publicValue.data[0] == EC_POINT_FORM_UNCOMPRESSED)) {
1810                     break; /* key was not DER encoded, no need to unwrap */
1811                 }
1812 
1813                 PORT_Assert(pubKey->u.ec.ecParams.name != ECCurve25519);
1814 
1815                 /* handle the encoded case */
1816                 if ((pubKey->u.ec.publicValue.data[0] == SEC_ASN1_OCTET_STRING) &&
1817                     pubKey->u.ec.publicValue.len > keyLen) {
1818                     SECItem publicValue;
1819                     SECStatus rv;
1820 
1821                     rv = SEC_QuickDERDecodeItem(arena, &publicValue,
1822                                                 SEC_ASN1_GET(SEC_OctetStringTemplate),
1823                                                 &pubKey->u.ec.publicValue);
1824                     /* nope, didn't decode correctly */
1825                     if ((rv != SECSuccess) || (publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) || (publicValue.len != keyLen)) {
1826                         crv = CKR_ATTRIBUTE_VALUE_INVALID;
1827                         break;
1828                     }
1829                     /* replace our previous with the decoded key */
1830                     pubKey->u.ec.publicValue = publicValue;
1831                     break;
1832                 }
1833                 crv = CKR_ATTRIBUTE_VALUE_INVALID;
1834             }
1835             break;
1836 #endif /* NSS_DISABLE_ECC */
1837         default:
1838             crv = CKR_KEY_TYPE_INCONSISTENT;
1839             break;
1840     }
1841     *crvp = crv;
1842     if (crv != CKR_OK) {
1843         PORT_FreeArena(arena, PR_FALSE);
1844         return NULL;
1845     }
1846 
1847     object->objectInfo = pubKey;
1848     object->infoFree = (SFTKFree)nsslowkey_DestroyPublicKey;
1849     return pubKey;
1850 }
1851 
1852 /* make a private key from a verified object */
1853 static NSSLOWKEYPrivateKey *
sftk_mkPrivKey(SFTKObject * object,CK_KEY_TYPE key_type,CK_RV * crvp)1854 sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
1855 {
1856     NSSLOWKEYPrivateKey *privKey;
1857     SFTKItemTemplate itemTemplate[SFTK_MAX_ITEM_TEMPLATE];
1858     int itemTemplateCount = 0;
1859     PLArenaPool *arena;
1860     CK_RV crv = CKR_OK;
1861     SECStatus rv;
1862 
1863     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1864     if (arena == NULL) {
1865         *crvp = CKR_HOST_MEMORY;
1866         return NULL;
1867     }
1868 
1869     privKey = (NSSLOWKEYPrivateKey *)
1870         PORT_ArenaZAlloc(arena, sizeof(NSSLOWKEYPrivateKey));
1871     if (privKey == NULL) {
1872         PORT_FreeArena(arena, PR_FALSE);
1873         *crvp = CKR_HOST_MEMORY;
1874         return NULL;
1875     }
1876 
1877     /* in future this would be a switch on key_type */
1878     privKey->arena = arena;
1879     switch (key_type) {
1880         case CKK_RSA:
1881             privKey->keyType = NSSLOWKEYRSAKey;
1882 
1883             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1884                                    &privKey->u.rsa.modulus, CKA_MODULUS);
1885             itemTemplateCount++;
1886             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1887                                    &privKey->u.rsa.publicExponent, CKA_PUBLIC_EXPONENT);
1888             itemTemplateCount++;
1889             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1890                                    &privKey->u.rsa.privateExponent, CKA_PRIVATE_EXPONENT);
1891             itemTemplateCount++;
1892             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1893                                    &privKey->u.rsa.prime1, CKA_PRIME_1);
1894             itemTemplateCount++;
1895             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1896                                    &privKey->u.rsa.prime2, CKA_PRIME_2);
1897             itemTemplateCount++;
1898             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1899                                    &privKey->u.rsa.exponent1, CKA_EXPONENT_1);
1900             itemTemplateCount++;
1901             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1902                                    &privKey->u.rsa.exponent2, CKA_EXPONENT_2);
1903             itemTemplateCount++;
1904             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1905                                    &privKey->u.rsa.coefficient, CKA_COEFFICIENT);
1906             itemTemplateCount++;
1907             rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version,
1908                                  NSSLOWKEY_PRIVATE_KEY_INFO_VERSION);
1909             if (rv != SECSuccess)
1910                 crv = CKR_HOST_MEMORY;
1911             break;
1912 
1913         case CKK_DSA:
1914             privKey->keyType = NSSLOWKEYDSAKey;
1915             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1916                                    &privKey->u.dsa.params.prime, CKA_PRIME);
1917             itemTemplateCount++;
1918             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1919                                    &privKey->u.dsa.params.subPrime, CKA_SUBPRIME);
1920             itemTemplateCount++;
1921             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1922                                    &privKey->u.dsa.params.base, CKA_BASE);
1923             itemTemplateCount++;
1924             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1925                                    &privKey->u.dsa.privateValue, CKA_VALUE);
1926             itemTemplateCount++;
1927             /* privKey was zero'd so public value is already set to NULL, 0
1928              * if we don't set it explicitly */
1929             break;
1930 
1931         case CKK_DH:
1932             privKey->keyType = NSSLOWKEYDHKey;
1933             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1934                                    &privKey->u.dh.prime, CKA_PRIME);
1935             itemTemplateCount++;
1936             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1937                                    &privKey->u.dh.base, CKA_BASE);
1938             itemTemplateCount++;
1939             SFTK_SET_ITEM_TEMPLATE(itemTemplate, itemTemplateCount,
1940                                    &privKey->u.dh.privateValue, CKA_VALUE);
1941             itemTemplateCount++;
1942             /* privKey was zero'd so public value is already set to NULL, 0
1943              * if we don't set it explicitly */
1944             break;
1945 
1946 #ifndef NSS_DISABLE_ECC
1947         case CKK_EC:
1948             privKey->keyType = NSSLOWKEYECKey;
1949             crv = sftk_Attribute2SSecItem(arena,
1950                                           &privKey->u.ec.ecParams.DEREncoding,
1951                                           object, CKA_EC_PARAMS);
1952             if (crv != CKR_OK)
1953                 break;
1954 
1955             /* Fill out the rest of the ecParams structure
1956              * based on the encoded params
1957              */
1958             if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding,
1959                               &privKey->u.ec.ecParams) != SECSuccess) {
1960                 crv = CKR_DOMAIN_PARAMS_INVALID;
1961                 break;
1962             }
1963             crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.privateValue,
1964                                           object, CKA_VALUE);
1965             if (crv != CKR_OK)
1966                 break;
1967 
1968             if (sftk_hasAttribute(object, CKA_NETSCAPE_DB)) {
1969                 crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue,
1970                                               object, CKA_NETSCAPE_DB);
1971                 if (crv != CKR_OK)
1972                     break;
1973                 /* privKey was zero'd so public value is already set to NULL, 0
1974              * if we don't set it explicitly */
1975             }
1976             rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version,
1977                                  NSSLOWKEY_EC_PRIVATE_KEY_VERSION);
1978             if (rv != SECSuccess) {
1979                 crv = CKR_HOST_MEMORY;
1980 /* The following ifdef is needed for Linux arm distros and
1981  * Android as gcc 4.6 has a bug when targeting arm (but not
1982  * thumb). The bug has been fixed in gcc 4.7.
1983  * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56561
1984  */
1985 #if defined(__arm__) && !defined(__thumb__) && defined(__GNUC__)
1986                 *crvp = CKR_HOST_MEMORY;
1987                 break;
1988 #endif
1989             }
1990             break;
1991 #endif /* NSS_DISABLE_ECC */
1992 
1993         default:
1994             crv = CKR_KEY_TYPE_INCONSISTENT;
1995             break;
1996     }
1997     if (crv == CKR_OK && itemTemplateCount != 0) {
1998         PORT_Assert(itemTemplateCount > 0);
1999         PORT_Assert(itemTemplateCount <= SFTK_MAX_ITEM_TEMPLATE);
2000         crv = sftk_MultipleAttribute2SecItem(arena, object, itemTemplate,
2001                                              itemTemplateCount);
2002     }
2003     *crvp = crv;
2004     if (crv != CKR_OK) {
2005         PORT_FreeArena(arena, PR_FALSE);
2006         return NULL;
2007     }
2008     return privKey;
2009 }
2010 
2011 /*
2012  * If a partial RSA private key is present, fill in the rest if necessary,
2013  * and then verify the parameters are well-formed
2014  */
2015 static SECStatus
sftk_verifyRSAPrivateKey(SFTKObject * object,PRBool fillIfNeeded)2016 sftk_verifyRSAPrivateKey(SFTKObject *object, PRBool fillIfNeeded)
2017 {
2018     RSAPrivateKey tmpKey = { 0 };
2019     SFTKAttribute *modulus = NULL;
2020     SFTKAttribute *prime1 = NULL;
2021     SFTKAttribute *prime2 = NULL;
2022     SFTKAttribute *privateExponent = NULL;
2023     SFTKAttribute *publicExponent = NULL;
2024     SFTKAttribute *exponent1 = NULL;
2025     SFTKAttribute *exponent2 = NULL;
2026     SFTKAttribute *coefficient = NULL;
2027     SECStatus rv;
2028     CK_RV crv;
2029 
2030     /* first fill in the components that we have. Populate only uses
2031      * the non-crt components, so only fill those in  */
2032     tmpKey.arena = NULL;
2033     modulus = sftk_FindAttribute(object, CKA_MODULUS);
2034     if (modulus) {
2035         tmpKey.modulus.data = modulus->attrib.pValue;
2036         tmpKey.modulus.len = modulus->attrib.ulValueLen;
2037     }
2038     prime1 = sftk_FindAttribute(object, CKA_PRIME_1);
2039     if (prime1) {
2040         tmpKey.prime1.data = prime1->attrib.pValue;
2041         tmpKey.prime1.len = prime1->attrib.ulValueLen;
2042     }
2043     prime2 = sftk_FindAttribute(object, CKA_PRIME_2);
2044     if (prime2) {
2045         tmpKey.prime2.data = prime2->attrib.pValue;
2046         tmpKey.prime2.len = prime2->attrib.ulValueLen;
2047     }
2048     privateExponent = sftk_FindAttribute(object, CKA_PRIVATE_EXPONENT);
2049     if (privateExponent) {
2050         tmpKey.privateExponent.data = privateExponent->attrib.pValue;
2051         tmpKey.privateExponent.len = privateExponent->attrib.ulValueLen;
2052     }
2053     publicExponent = sftk_FindAttribute(object, CKA_PUBLIC_EXPONENT);
2054     if (publicExponent) {
2055         tmpKey.publicExponent.data = publicExponent->attrib.pValue;
2056         tmpKey.publicExponent.len = publicExponent->attrib.ulValueLen;
2057     }
2058     exponent1 = sftk_FindAttribute(object, CKA_EXPONENT_1);
2059     if (exponent1) {
2060         tmpKey.exponent1.data = exponent1->attrib.pValue;
2061         tmpKey.exponent1.len = exponent1->attrib.ulValueLen;
2062     }
2063     exponent2 = sftk_FindAttribute(object, CKA_EXPONENT_2);
2064     if (exponent2) {
2065         tmpKey.exponent2.data = exponent2->attrib.pValue;
2066         tmpKey.exponent2.len = exponent2->attrib.ulValueLen;
2067     }
2068     coefficient = sftk_FindAttribute(object, CKA_COEFFICIENT);
2069     if (coefficient) {
2070         tmpKey.coefficient.data = coefficient->attrib.pValue;
2071         tmpKey.coefficient.len = coefficient->attrib.ulValueLen;
2072     }
2073 
2074     if (fillIfNeeded) {
2075         /*
2076          * populate requires one exponent plus 2 other components to work.
2077          * we expected our caller to check that first. If that didn't happen,
2078          * populate will simply return an error here.
2079          */
2080         rv = RSA_PopulatePrivateKey(&tmpKey);
2081         if (rv != SECSuccess) {
2082             goto loser;
2083         }
2084     }
2085     rv = RSA_PrivateKeyCheck(&tmpKey);
2086     if (rv != SECSuccess) {
2087         goto loser;
2088     }
2089     /* now that we have a fully populated key, set all our attribute values */
2090     rv = SECFailure;
2091     if (!modulus || modulus->attrib.pValue != tmpKey.modulus.data) {
2092         crv = sftk_forceAttribute(object, CKA_MODULUS,
2093                                   sftk_item_expand(&tmpKey.modulus));
2094         if (crv != CKR_OK)
2095             goto loser;
2096     }
2097     if (!publicExponent ||
2098         publicExponent->attrib.pValue != tmpKey.publicExponent.data) {
2099         crv = sftk_forceAttribute(object, CKA_PUBLIC_EXPONENT,
2100                                   sftk_item_expand(&tmpKey.publicExponent));
2101         if (crv != CKR_OK)
2102             goto loser;
2103     }
2104     if (!privateExponent ||
2105         privateExponent->attrib.pValue != tmpKey.privateExponent.data) {
2106         crv = sftk_forceAttribute(object, CKA_PRIVATE_EXPONENT,
2107                                   sftk_item_expand(&tmpKey.privateExponent));
2108         if (crv != CKR_OK)
2109             goto loser;
2110     }
2111     if (!prime1 || prime1->attrib.pValue != tmpKey.prime1.data) {
2112         crv = sftk_forceAttribute(object, CKA_PRIME_1,
2113                                   sftk_item_expand(&tmpKey.prime1));
2114         if (crv != CKR_OK)
2115             goto loser;
2116     }
2117     if (!prime2 || prime2->attrib.pValue != tmpKey.prime2.data) {
2118         crv = sftk_forceAttribute(object, CKA_PRIME_2,
2119                                   sftk_item_expand(&tmpKey.prime2));
2120         if (crv != CKR_OK)
2121             goto loser;
2122     }
2123     if (!exponent1 || exponent1->attrib.pValue != tmpKey.exponent1.data) {
2124         crv = sftk_forceAttribute(object, CKA_EXPONENT_1,
2125                                   sftk_item_expand(&tmpKey.exponent1));
2126         if (crv != CKR_OK)
2127             goto loser;
2128     }
2129     if (!exponent2 || exponent2->attrib.pValue != tmpKey.exponent2.data) {
2130         crv = sftk_forceAttribute(object, CKA_EXPONENT_2,
2131                                   sftk_item_expand(&tmpKey.exponent2));
2132         if (crv != CKR_OK)
2133             goto loser;
2134     }
2135     if (!coefficient || coefficient->attrib.pValue != tmpKey.coefficient.data) {
2136         crv = sftk_forceAttribute(object, CKA_COEFFICIENT,
2137                                   sftk_item_expand(&tmpKey.coefficient));
2138         if (crv != CKR_OK)
2139             goto loser;
2140     }
2141     rv = SECSuccess;
2142 
2143 /* we're done (one way or the other), clean up all our stuff */
2144 loser:
2145     if (tmpKey.arena) {
2146         PORT_FreeArena(tmpKey.arena, PR_TRUE);
2147     }
2148     if (modulus) {
2149         sftk_FreeAttribute(modulus);
2150     }
2151     if (prime1) {
2152         sftk_FreeAttribute(prime1);
2153     }
2154     if (prime2) {
2155         sftk_FreeAttribute(prime2);
2156     }
2157     if (privateExponent) {
2158         sftk_FreeAttribute(privateExponent);
2159     }
2160     if (publicExponent) {
2161         sftk_FreeAttribute(publicExponent);
2162     }
2163     if (exponent1) {
2164         sftk_FreeAttribute(exponent1);
2165     }
2166     if (exponent2) {
2167         sftk_FreeAttribute(exponent2);
2168     }
2169     if (coefficient) {
2170         sftk_FreeAttribute(coefficient);
2171     }
2172     return rv;
2173 }
2174 
2175 /* Generate a low private key structure from an object */
2176 NSSLOWKEYPrivateKey *
sftk_GetPrivKey(SFTKObject * object,CK_KEY_TYPE key_type,CK_RV * crvp)2177 sftk_GetPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp)
2178 {
2179     NSSLOWKEYPrivateKey *priv = NULL;
2180 
2181     if (object->objclass != CKO_PRIVATE_KEY) {
2182         *crvp = CKR_KEY_TYPE_INCONSISTENT;
2183         return NULL;
2184     }
2185     if (object->objectInfo) {
2186         *crvp = CKR_OK;
2187         return (NSSLOWKEYPrivateKey *)object->objectInfo;
2188     }
2189 
2190     priv = sftk_mkPrivKey(object, key_type, crvp);
2191     object->objectInfo = priv;
2192     object->infoFree = (SFTKFree)nsslowkey_DestroyPrivateKey;
2193     return priv;
2194 }
2195 
2196 /*
2197  **************************** Symetric Key utils ************************
2198  */
2199 /*
2200  * set the DES key with parity bits correctly
2201  */
2202 void
sftk_FormatDESKey(unsigned char * key,int length)2203 sftk_FormatDESKey(unsigned char *key, int length)
2204 {
2205     int i;
2206 
2207     /* format the des key */
2208     for (i = 0; i < length; i++) {
2209         key[i] = parityTable[key[i] >> 1];
2210     }
2211 }
2212 
2213 /*
2214  * check a des key (des2 or des3 subkey) for weak keys.
2215  */
2216 PRBool
sftk_CheckDESKey(unsigned char * key)2217 sftk_CheckDESKey(unsigned char *key)
2218 {
2219     int i;
2220 
2221     /* format the des key with parity  */
2222     sftk_FormatDESKey(key, 8);
2223 
2224     for (i = 0; i < sftk_desWeakTableSize; i++) {
2225         if (PORT_Memcmp(key, sftk_desWeakTable[i], 8) == 0) {
2226             return PR_TRUE;
2227         }
2228     }
2229     return PR_FALSE;
2230 }
2231 
2232 /*
2233  * check if a des or triple des key is weak.
2234  */
2235 PRBool
sftk_IsWeakKey(unsigned char * key,CK_KEY_TYPE key_type)2236 sftk_IsWeakKey(unsigned char *key, CK_KEY_TYPE key_type)
2237 {
2238 
2239     switch (key_type) {
2240         case CKK_DES:
2241             return sftk_CheckDESKey(key);
2242         case CKM_DES2_KEY_GEN:
2243             if (sftk_CheckDESKey(key))
2244                 return PR_TRUE;
2245             return sftk_CheckDESKey(&key[8]);
2246         case CKM_DES3_KEY_GEN:
2247             if (sftk_CheckDESKey(key))
2248                 return PR_TRUE;
2249             if (sftk_CheckDESKey(&key[8]))
2250                 return PR_TRUE;
2251             return sftk_CheckDESKey(&key[16]);
2252         default:
2253             break;
2254     }
2255     return PR_FALSE;
2256 }
2257 
2258 /**********************************************************************
2259  *
2260  *     Start of PKCS 11 functions
2261  *
2262  **********************************************************************/
2263 
2264 /* return the function list */
2265 CK_RV
NSC_GetFunctionList(CK_FUNCTION_LIST_PTR * pFunctionList)2266 NSC_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
2267 {
2268     *pFunctionList = (CK_FUNCTION_LIST_PTR)&sftk_funcList;
2269     return CKR_OK;
2270 }
2271 
2272 /* return the function list */
2273 CK_RV
C_GetFunctionList(CK_FUNCTION_LIST_PTR * pFunctionList)2274 C_GetFunctionList(CK_FUNCTION_LIST_PTR *pFunctionList)
2275 {
2276     return NSC_GetFunctionList(pFunctionList);
2277 }
2278 
2279 static PLHashNumber
sftk_HashNumber(const void * key)2280 sftk_HashNumber(const void *key)
2281 {
2282     return (PLHashNumber)((char *)key - (char *)NULL);
2283 }
2284 
2285 /*
2286  * eventually I'd like to expunge all occurances of XXX_SLOT_ID and
2287  * just go with the info in the slot. This is one place, however,
2288  * where it might be a little difficult.
2289  */
2290 const char *
sftk_getDefTokName(CK_SLOT_ID slotID)2291 sftk_getDefTokName(CK_SLOT_ID slotID)
2292 {
2293     static char buf[33];
2294 
2295     switch (slotID) {
2296         case NETSCAPE_SLOT_ID:
2297             return "NSS Generic Crypto Services     ";
2298         case PRIVATE_KEY_SLOT_ID:
2299             return "NSS Certificate DB              ";
2300         case FIPS_SLOT_ID:
2301             return "NSS FIPS 140-2 Certificate DB   ";
2302         default:
2303             break;
2304     }
2305     sprintf(buf, "NSS Application Token %08x  ", (unsigned int)slotID);
2306     return buf;
2307 }
2308 
2309 const char *
sftk_getDefSlotName(CK_SLOT_ID slotID)2310 sftk_getDefSlotName(CK_SLOT_ID slotID)
2311 {
2312     static char buf[65];
2313 
2314     switch (slotID) {
2315         case NETSCAPE_SLOT_ID:
2316             return "NSS Internal Cryptographic Services                             ";
2317         case PRIVATE_KEY_SLOT_ID:
2318             return "NSS User Private Key and Certificate Services                   ";
2319         case FIPS_SLOT_ID:
2320             return "NSS FIPS 140-2 User Private Key Services                        ";
2321         default:
2322             break;
2323     }
2324     sprintf(buf,
2325             "NSS Application Slot %08x                                   ",
2326             (unsigned int)slotID);
2327     return buf;
2328 }
2329 
2330 static CK_ULONG nscSlotCount[2] = { 0, 0 };
2331 static CK_SLOT_ID_PTR nscSlotList[2] = { NULL, NULL };
2332 static CK_ULONG nscSlotListSize[2] = { 0, 0 };
2333 static PLHashTable *nscSlotHashTable[2] = { NULL, NULL };
2334 
2335 static unsigned int
sftk_GetModuleIndex(CK_SLOT_ID slotID)2336 sftk_GetModuleIndex(CK_SLOT_ID slotID)
2337 {
2338     if ((slotID == FIPS_SLOT_ID) || (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID)) {
2339         return NSC_FIPS_MODULE;
2340     }
2341     return NSC_NON_FIPS_MODULE;
2342 }
2343 
2344 /* look up a slot structure from the ID (used to be a macro when we only
2345  * had two slots) */
2346 /* if all is true, return the slot even if it has been 'unloaded' */
2347 /* if all is false, only return the slots which are present */
2348 SFTKSlot *
sftk_SlotFromID(CK_SLOT_ID slotID,PRBool all)2349 sftk_SlotFromID(CK_SLOT_ID slotID, PRBool all)
2350 {
2351     SFTKSlot *slot;
2352     int index = sftk_GetModuleIndex(slotID);
2353 
2354     if (nscSlotHashTable[index] == NULL)
2355         return NULL;
2356     slot = (SFTKSlot *)PL_HashTableLookupConst(nscSlotHashTable[index],
2357                                                (void *)slotID);
2358     /* cleared slots shouldn't 'show up' */
2359     if (slot && !all && !slot->present)
2360         slot = NULL;
2361     return slot;
2362 }
2363 
2364 SFTKSlot *
sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)2365 sftk_SlotFromSessionHandle(CK_SESSION_HANDLE handle)
2366 {
2367     CK_ULONG slotIDIndex = (handle >> 24) & 0x7f;
2368     CK_ULONG moduleIndex = (handle >> 31) & 1;
2369 
2370     if (slotIDIndex >= nscSlotCount[moduleIndex]) {
2371         return NULL;
2372     }
2373 
2374     return sftk_SlotFromID(nscSlotList[moduleIndex][slotIDIndex], PR_FALSE);
2375 }
2376 
2377 static CK_RV
sftk_RegisterSlot(SFTKSlot * slot,int moduleIndex)2378 sftk_RegisterSlot(SFTKSlot *slot, int moduleIndex)
2379 {
2380     PLHashEntry *entry;
2381     unsigned int index;
2382 
2383     index = sftk_GetModuleIndex(slot->slotID);
2384 
2385     /* make sure the slotID for this module is valid */
2386     if (moduleIndex != index) {
2387         return CKR_SLOT_ID_INVALID;
2388     }
2389 
2390     if (nscSlotList[index] == NULL) {
2391         nscSlotListSize[index] = NSC_SLOT_LIST_BLOCK_SIZE;
2392         nscSlotList[index] = (CK_SLOT_ID *)
2393             PORT_ZAlloc(nscSlotListSize[index] * sizeof(CK_SLOT_ID));
2394         if (nscSlotList[index] == NULL) {
2395             return CKR_HOST_MEMORY;
2396         }
2397     }
2398     if (nscSlotCount[index] >= nscSlotListSize[index]) {
2399         CK_SLOT_ID *oldNscSlotList = nscSlotList[index];
2400         CK_ULONG oldNscSlotListSize = nscSlotListSize[index];
2401         nscSlotListSize[index] += NSC_SLOT_LIST_BLOCK_SIZE;
2402         nscSlotList[index] = (CK_SLOT_ID *)PORT_Realloc(oldNscSlotList,
2403                                                         nscSlotListSize[index] * sizeof(CK_SLOT_ID));
2404         if (nscSlotList[index] == NULL) {
2405             nscSlotList[index] = oldNscSlotList;
2406             nscSlotListSize[index] = oldNscSlotListSize;
2407             return CKR_HOST_MEMORY;
2408         }
2409     }
2410 
2411     if (nscSlotHashTable[index] == NULL) {
2412         nscSlotHashTable[index] = PL_NewHashTable(64, sftk_HashNumber,
2413                                                   PL_CompareValues, PL_CompareValues, NULL, 0);
2414         if (nscSlotHashTable[index] == NULL) {
2415             return CKR_HOST_MEMORY;
2416         }
2417     }
2418 
2419     entry = PL_HashTableAdd(nscSlotHashTable[index], (void *)slot->slotID, slot);
2420     if (entry == NULL) {
2421         return CKR_HOST_MEMORY;
2422     }
2423     slot->index = (nscSlotCount[index] & 0x7f) | ((index << 7) & 0x80);
2424     nscSlotList[index][nscSlotCount[index]++] = slot->slotID;
2425 
2426     return CKR_OK;
2427 }
2428 
2429 /*
2430  * ths function has all the common initialization that happens whenever we
2431  * create a new slot or repurpose an old slot (only valid for slotID's 4
2432  * and greater).
2433  *
2434  * things that are not reinitialized are:
2435  *   slotID (can't change)
2436  *   slotDescription (can't change once defined)
2437  *   the locks and hash tables (difficult to change in running code, and
2438  *     unnecessary. hash tables and list are cleared on shutdown, but they
2439  *     are cleared in a 'friendly' way).
2440  *   session and object ID counters -- so any old sessions and objects in the
2441  *     application will get properly notified that the world has changed.
2442  *
2443  * things that are reinitialized:
2444  *   database (otherwise what would the point be;).
2445  *   state variables related to databases.
2446  *   session count stat info.
2447  *   tokenDescription.
2448  *
2449  * NOTE: slotID's 4 and greater show up as removable devices.
2450  *
2451  */
2452 CK_RV
SFTK_SlotReInit(SFTKSlot * slot,char * configdir,char * updatedir,char * updateID,sftk_token_parameters * params,int moduleIndex)2453 SFTK_SlotReInit(SFTKSlot *slot, char *configdir, char *updatedir,
2454                 char *updateID, sftk_token_parameters *params, int moduleIndex)
2455 {
2456     PRBool needLogin = !params->noKeyDB;
2457     CK_RV crv;
2458 
2459     slot->hasTokens = PR_FALSE;
2460     slot->sessionIDConflict = 0;
2461     slot->sessionCount = 0;
2462     slot->rwSessionCount = 0;
2463     slot->needLogin = PR_FALSE;
2464     slot->isLoggedIn = PR_FALSE;
2465     slot->ssoLoggedIn = PR_FALSE;
2466     slot->DB_loaded = PR_FALSE;
2467     slot->certDB = NULL;
2468     slot->keyDB = NULL;
2469     slot->minimumPinLen = 0;
2470     slot->readOnly = params->readOnly;
2471     sftk_setStringName(params->tokdes ? params->tokdes : sftk_getDefTokName(slot->slotID), slot->tokDescription,
2472                        sizeof(slot->tokDescription), PR_TRUE);
2473     sftk_setStringName(params->updtokdes ? params->updtokdes : " ",
2474                        slot->updateTokDescription,
2475                        sizeof(slot->updateTokDescription), PR_TRUE);
2476 
2477     if ((!params->noCertDB) || (!params->noKeyDB)) {
2478         SFTKDBHandle *certHandle = NULL;
2479         SFTKDBHandle *keyHandle = NULL;
2480         crv = sftk_DBInit(params->configdir ? params->configdir : configdir,
2481                           params->certPrefix, params->keyPrefix,
2482                           params->updatedir ? params->updatedir : updatedir,
2483                           params->updCertPrefix, params->updKeyPrefix,
2484                           params->updateID ? params->updateID : updateID,
2485                           params->readOnly, params->noCertDB, params->noKeyDB,
2486                           params->forceOpen,
2487                           moduleIndex == NSC_FIPS_MODULE,
2488                           &certHandle, &keyHandle);
2489         if (crv != CKR_OK) {
2490             goto loser;
2491         }
2492 
2493         slot->certDB = certHandle;
2494         slot->keyDB = keyHandle;
2495     }
2496     if (needLogin) {
2497         /* if the data base is initialized with a null password,remember that */
2498         slot->needLogin =
2499             (PRBool)!sftk_hasNullPassword(slot, slot->keyDB);
2500         if ((params->minPW >= 0) && (params->minPW <= SFTK_MAX_PIN)) {
2501             slot->minimumPinLen = params->minPW;
2502         }
2503         if ((slot->minimumPinLen == 0) && (params->pwRequired)) {
2504             slot->minimumPinLen = 1;
2505         }
2506         /* Make sure the pin len is set to the Minimum allowed value for fips
2507          * when in FIPS mode. NOTE: we don't set it if the database has not
2508          * been initialized yet so that we can init into level1 mode if needed
2509          */
2510         if ((sftkdb_HasPasswordSet(slot->keyDB) == SECSuccess) &&
2511             (moduleIndex == NSC_FIPS_MODULE) &&
2512             (slot->minimumPinLen < FIPS_MIN_PIN)) {
2513             slot->minimumPinLen = FIPS_MIN_PIN;
2514         }
2515     }
2516 
2517     slot->present = PR_TRUE;
2518     return CKR_OK;
2519 
2520 loser:
2521     SFTK_ShutdownSlot(slot);
2522     return crv;
2523 }
2524 
2525 /*
2526  * initialize one of the slot structures. figure out which by the ID
2527  */
2528 CK_RV
SFTK_SlotInit(char * configdir,char * updatedir,char * updateID,sftk_token_parameters * params,int moduleIndex)2529 SFTK_SlotInit(char *configdir, char *updatedir, char *updateID,
2530               sftk_token_parameters *params, int moduleIndex)
2531 {
2532     unsigned int i;
2533     CK_SLOT_ID slotID = params->slotID;
2534     SFTKSlot *slot;
2535     CK_RV crv = CKR_HOST_MEMORY;
2536 
2537     /*
2538      * first we initialize everything that is 'permanent' with this slot.
2539      * that is everything we aren't going to shutdown if we close this slot
2540      * and open it up again with different databases */
2541 
2542     slot = PORT_ZNew(SFTKSlot);
2543 
2544     if (slot == NULL) {
2545         return CKR_HOST_MEMORY;
2546     }
2547 
2548     slot->optimizeSpace = params->optimizeSpace;
2549     if (slot->optimizeSpace) {
2550         slot->sessObjHashSize = SPACE_SESSION_OBJECT_HASH_SIZE;
2551         slot->sessHashSize = SPACE_SESSION_HASH_SIZE;
2552         slot->numSessionLocks = 1;
2553     } else {
2554         slot->sessObjHashSize = TIME_SESSION_OBJECT_HASH_SIZE;
2555         slot->sessHashSize = TIME_SESSION_HASH_SIZE;
2556         slot->numSessionLocks = slot->sessHashSize / BUCKETS_PER_SESSION_LOCK;
2557     }
2558     slot->sessionLockMask = slot->numSessionLocks - 1;
2559 
2560     slot->slotLock = PZ_NewLock(nssILockSession);
2561     if (slot->slotLock == NULL)
2562         goto mem_loser;
2563     slot->sessionLock = PORT_ZNewArray(PZLock *, slot->numSessionLocks);
2564     if (slot->sessionLock == NULL)
2565         goto mem_loser;
2566     for (i = 0; i < slot->numSessionLocks; i++) {
2567         slot->sessionLock[i] = PZ_NewLock(nssILockSession);
2568         if (slot->sessionLock[i] == NULL)
2569             goto mem_loser;
2570     }
2571     slot->objectLock = PZ_NewLock(nssILockObject);
2572     if (slot->objectLock == NULL)
2573         goto mem_loser;
2574     slot->pwCheckLock = PR_NewLock();
2575     if (slot->pwCheckLock == NULL)
2576         goto mem_loser;
2577     slot->head = PORT_ZNewArray(SFTKSession *, slot->sessHashSize);
2578     if (slot->head == NULL)
2579         goto mem_loser;
2580     slot->sessObjHashTable = PORT_ZNewArray(SFTKObject *, slot->sessObjHashSize);
2581     if (slot->sessObjHashTable == NULL)
2582         goto mem_loser;
2583     slot->tokObjHashTable = PL_NewHashTable(64, sftk_HashNumber, PL_CompareValues,
2584                                             SECITEM_HashCompare, NULL, 0);
2585     if (slot->tokObjHashTable == NULL)
2586         goto mem_loser;
2587 
2588     slot->sessionIDCount = 0;
2589     slot->sessionObjectHandleCount = minSessionObjectHandle;
2590     slot->slotID = slotID;
2591     sftk_setStringName(params->slotdes ? params->slotdes : sftk_getDefSlotName(slotID), slot->slotDescription,
2592                        sizeof(slot->slotDescription), PR_TRUE);
2593 
2594     /* call the reinit code to set everything that changes between token
2595      * init calls */
2596     crv = SFTK_SlotReInit(slot, configdir, updatedir, updateID,
2597                           params, moduleIndex);
2598     if (crv != CKR_OK) {
2599         goto loser;
2600     }
2601     crv = sftk_RegisterSlot(slot, moduleIndex);
2602     if (crv != CKR_OK) {
2603         goto loser;
2604     }
2605     return CKR_OK;
2606 
2607 mem_loser:
2608     crv = CKR_HOST_MEMORY;
2609 loser:
2610     SFTK_DestroySlotData(slot);
2611     return crv;
2612 }
2613 
2614 CK_RV
sftk_CloseAllSessions(SFTKSlot * slot,PRBool logout)2615 sftk_CloseAllSessions(SFTKSlot *slot, PRBool logout)
2616 {
2617     SFTKSession *session;
2618     unsigned int i;
2619     SFTKDBHandle *handle;
2620 
2621     /* first log out the card */
2622     /* special case - if we are in a middle of upgrade, we want to close the
2623      * sessions to fake a token removal to tell the upper level code we have
2624      * switched from one database to another, but we don't want to
2625      * explicity logout in case we can continue the upgrade with the
2626      * existing password if possible.
2627      */
2628     if (logout) {
2629         handle = sftk_getKeyDB(slot);
2630         SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
2631         slot->isLoggedIn = PR_FALSE;
2632         if (slot->needLogin && handle) {
2633             sftkdb_ClearPassword(handle);
2634         }
2635         SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
2636         if (handle) {
2637             sftk_freeDB(handle);
2638         }
2639     }
2640 
2641     /* now close all the current sessions */
2642     /* NOTE: If you try to open new sessions before NSC_CloseAllSessions
2643      * completes, some of those new sessions may or may not be closed by
2644      * NSC_CloseAllSessions... but any session running when this code starts
2645      * will guarrenteed be close, and no session will be partially closed */
2646     for (i = 0; i < slot->sessHashSize; i++) {
2647         PZLock *lock = SFTK_SESSION_LOCK(slot, i);
2648         do {
2649             SKIP_AFTER_FORK(PZ_Lock(lock));
2650             session = slot->head[i];
2651             /* hand deque */
2652             /* this duplicates function of NSC_close session functions, but
2653              * because we know that we are freeing all the sessions, we can
2654              * do more efficient processing */
2655             if (session) {
2656                 slot->head[i] = session->next;
2657                 if (session->next)
2658                     session->next->prev = NULL;
2659                 session->next = session->prev = NULL;
2660                 SKIP_AFTER_FORK(PZ_Unlock(lock));
2661                 SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
2662                 --slot->sessionCount;
2663                 SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
2664                 if (session->info.flags & CKF_RW_SESSION) {
2665                     (void)PR_ATOMIC_DECREMENT(&slot->rwSessionCount);
2666                 }
2667             } else {
2668                 SKIP_AFTER_FORK(PZ_Unlock(lock));
2669             }
2670             if (session)
2671                 sftk_FreeSession(session);
2672         } while (session != NULL);
2673     }
2674     return CKR_OK;
2675 }
2676 
2677 /*
2678  * shut down the databases.
2679  * we get the slot lock (which also protects slot->certDB and slot->keyDB)
2680  * and clear the values so the new users will not find the databases.
2681  * once things are clear, we can release our references to the databases.
2682  * The databases will close when the last reference is released.
2683  *
2684  * We use reference counts so that we don't crash if someone shuts down
2685  * a token that another thread is actively using.
2686  */
2687 static void
sftk_DBShutdown(SFTKSlot * slot)2688 sftk_DBShutdown(SFTKSlot *slot)
2689 {
2690     SFTKDBHandle *certHandle;
2691     SFTKDBHandle *keyHandle;
2692     SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
2693     certHandle = slot->certDB;
2694     slot->certDB = NULL;
2695     keyHandle = slot->keyDB;
2696     slot->keyDB = NULL;
2697     SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
2698     if (certHandle) {
2699         sftk_freeDB(certHandle);
2700     }
2701     if (keyHandle) {
2702         sftk_freeDB(keyHandle);
2703     }
2704 }
2705 
2706 CK_RV
SFTK_ShutdownSlot(SFTKSlot * slot)2707 SFTK_ShutdownSlot(SFTKSlot *slot)
2708 {
2709     /* make sure no new PK11 calls work except C_GetSlotInfo */
2710     slot->present = PR_FALSE;
2711 
2712     /* close all outstanding sessions
2713      * the sessHashSize variable guarentees we have all the session
2714      * mechanism set up */
2715     if (slot->head) {
2716         sftk_CloseAllSessions(slot, PR_TRUE);
2717     }
2718 
2719     /* clear all objects.. session objects are cleared as a result of
2720      * closing all the sessions. We just need to clear the token object
2721      * cache. slot->tokObjHashTable guarentees we have the token
2722      * infrastructure set up. */
2723     if (slot->tokObjHashTable) {
2724         SFTK_ClearTokenKeyHashTable(slot);
2725     }
2726 
2727     /* clear the slot description for the next guy */
2728     PORT_Memset(slot->tokDescription, 0, sizeof(slot->tokDescription));
2729 
2730     /* now shut down the databases. */
2731     sftk_DBShutdown(slot);
2732     return CKR_OK;
2733 }
2734 
2735 /*
2736  * initialize one of the slot structures. figure out which by the ID
2737  */
2738 CK_RV
SFTK_DestroySlotData(SFTKSlot * slot)2739 SFTK_DestroySlotData(SFTKSlot *slot)
2740 {
2741     unsigned int i;
2742 
2743     SFTK_ShutdownSlot(slot);
2744 
2745     if (slot->tokObjHashTable) {
2746         PL_HashTableDestroy(slot->tokObjHashTable);
2747         slot->tokObjHashTable = NULL;
2748     }
2749 
2750     if (slot->sessObjHashTable) {
2751         PORT_Free(slot->sessObjHashTable);
2752         slot->sessObjHashTable = NULL;
2753     }
2754     slot->sessObjHashSize = 0;
2755 
2756     if (slot->head) {
2757         PORT_Free(slot->head);
2758         slot->head = NULL;
2759     }
2760     slot->sessHashSize = 0;
2761 
2762     /* OK everything has been disassembled, now we can finally get rid
2763      * of the locks */
2764     SKIP_AFTER_FORK(PZ_DestroyLock(slot->slotLock));
2765     slot->slotLock = NULL;
2766     if (slot->sessionLock) {
2767         for (i = 0; i < slot->numSessionLocks; i++) {
2768             if (slot->sessionLock[i]) {
2769                 SKIP_AFTER_FORK(PZ_DestroyLock(slot->sessionLock[i]));
2770                 slot->sessionLock[i] = NULL;
2771             }
2772         }
2773         PORT_Free(slot->sessionLock);
2774         slot->sessionLock = NULL;
2775     }
2776     if (slot->objectLock) {
2777         SKIP_AFTER_FORK(PZ_DestroyLock(slot->objectLock));
2778         slot->objectLock = NULL;
2779     }
2780     if (slot->pwCheckLock) {
2781         SKIP_AFTER_FORK(PR_DestroyLock(slot->pwCheckLock));
2782         slot->pwCheckLock = NULL;
2783     }
2784     PORT_Free(slot);
2785     return CKR_OK;
2786 }
2787 
2788 /*
2789  * handle the SECMOD.db
2790  */
2791 char **
NSC_ModuleDBFunc(unsigned long function,char * parameters,void * args)2792 NSC_ModuleDBFunc(unsigned long function, char *parameters, void *args)
2793 {
2794     char *secmod = NULL;
2795     char *appName = NULL;
2796     char *filename = NULL;
2797     NSSDBType dbType = NSS_DB_TYPE_NONE;
2798     PRBool rw;
2799     static char *success = "Success";
2800     char **rvstr = NULL;
2801 
2802     rvstr = NSSUTIL_DoModuleDBFunction(function, parameters, args);
2803     if (rvstr != NULL) {
2804         return rvstr;
2805     }
2806 
2807     if (PORT_GetError() != SEC_ERROR_LEGACY_DATABASE) {
2808         return NULL;
2809     }
2810 
2811     /* The legacy database uses the old dbm, which is only linked with the
2812      * legacy DB handler, which is only callable from softoken */
2813 
2814     secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
2815                                     &filename, &rw);
2816 
2817     switch (function) {
2818         case SECMOD_MODULE_DB_FUNCTION_FIND:
2819             if (secmod == NULL) {
2820                 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2821                 goto loser;
2822             }
2823             if (rw && (dbType != NSS_DB_TYPE_LEGACY) &&
2824                 (dbType != NSS_DB_TYPE_MULTIACCESS)) {
2825                 /* if we get here, we are trying to update the local database */
2826                 /* force data from the legacy DB */
2827                 char *oldSecmod = NULL;
2828                 char *oldAppName = NULL;
2829                 char *oldFilename = NULL;
2830                 PRBool oldrw;
2831                 char **strings = NULL;
2832                 int i;
2833 
2834                 dbType = NSS_DB_TYPE_LEGACY;
2835                 oldSecmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &oldAppName,
2836                                                    &oldFilename, &oldrw);
2837                 strings = sftkdbCall_ReadSecmodDB(appName, oldFilename, oldSecmod,
2838                                                   (char *)parameters, oldrw);
2839                 if (strings) {
2840                     /* write out the strings */
2841                     for (i = 0; strings[i]; i++) {
2842                         NSSUTIL_DoModuleDBFunction(SECMOD_MODULE_DB_FUNCTION_ADD,
2843                                                    parameters, strings[i]);
2844                     }
2845                     sftkdbCall_ReleaseSecmodDBData(oldAppName, oldFilename, oldSecmod,
2846                                                    (char **)strings, oldrw);
2847                 } else {
2848                     /* write out a dummy record */
2849                     NSSUTIL_DoModuleDBFunction(SECMOD_MODULE_DB_FUNCTION_ADD,
2850                                                parameters, " ");
2851                 }
2852                 if (oldSecmod) {
2853                     PR_smprintf_free(oldSecmod);
2854                 }
2855                 if (oldAppName) {
2856                     PORT_Free(oldAppName);
2857                 }
2858                 if (oldFilename) {
2859                     PORT_Free(oldFilename);
2860                 }
2861                 rvstr = NSSUTIL_DoModuleDBFunction(function, parameters, args);
2862                 break;
2863             }
2864             rvstr = sftkdbCall_ReadSecmodDB(appName, filename, secmod,
2865                                             (char *)parameters, rw);
2866             break;
2867         case SECMOD_MODULE_DB_FUNCTION_ADD:
2868             if (secmod == NULL) {
2869                 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2870                 goto loser;
2871             }
2872             rvstr = (sftkdbCall_AddSecmodDB(appName, filename, secmod,
2873                                             (char *)args, rw) == SECSuccess)
2874                         ? &success
2875                         : NULL;
2876             break;
2877         case SECMOD_MODULE_DB_FUNCTION_DEL:
2878             if (secmod == NULL) {
2879                 PORT_SetError(SEC_ERROR_INVALID_ARGS);
2880                 goto loser;
2881             }
2882             rvstr = (sftkdbCall_DeleteSecmodDB(appName, filename, secmod,
2883                                                (char *)args, rw) == SECSuccess)
2884                         ? &success
2885                         : NULL;
2886             break;
2887         case SECMOD_MODULE_DB_FUNCTION_RELEASE:
2888             rvstr = (sftkdbCall_ReleaseSecmodDBData(appName, filename, secmod,
2889                                                     (char **)args, rw) == SECSuccess)
2890                         ? &success
2891                         : NULL;
2892             break;
2893     }
2894 
2895 loser:
2896     if (secmod)
2897         PR_smprintf_free(secmod);
2898     if (appName)
2899         PORT_Free(appName);
2900     if (filename)
2901         PORT_Free(filename);
2902     return rvstr;
2903 }
2904 
2905 static void
nscFreeAllSlots(int moduleIndex)2906 nscFreeAllSlots(int moduleIndex)
2907 {
2908     /* free all the slots */
2909     SFTKSlot *slot = NULL;
2910     CK_SLOT_ID slotID;
2911     int i;
2912 
2913     if (nscSlotList[moduleIndex]) {
2914         CK_ULONG tmpSlotCount = nscSlotCount[moduleIndex];
2915         CK_SLOT_ID_PTR tmpSlotList = nscSlotList[moduleIndex];
2916         PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
2917 
2918         /* first close all the session */
2919         for (i = 0; i < (int)tmpSlotCount; i++) {
2920             slotID = tmpSlotList[i];
2921             (void)NSC_CloseAllSessions(slotID);
2922         }
2923 
2924         /* now clear out the statics */
2925         nscSlotList[moduleIndex] = NULL;
2926         nscSlotCount[moduleIndex] = 0;
2927         nscSlotHashTable[moduleIndex] = NULL;
2928         nscSlotListSize[moduleIndex] = 0;
2929 
2930         for (i = 0; i < (int)tmpSlotCount; i++) {
2931             slotID = tmpSlotList[i];
2932             slot = (SFTKSlot *)
2933                 PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
2934             PORT_Assert(slot);
2935             if (!slot)
2936                 continue;
2937             SFTK_DestroySlotData(slot);
2938             PL_HashTableRemove(tmpSlotHashTable, (void *)slotID);
2939         }
2940         PORT_Free(tmpSlotList);
2941         PL_HashTableDestroy(tmpSlotHashTable);
2942     }
2943 }
2944 
2945 static void
sftk_closePeer(PRBool isFIPS)2946 sftk_closePeer(PRBool isFIPS)
2947 {
2948     CK_SLOT_ID slotID = isFIPS ? PRIVATE_KEY_SLOT_ID : FIPS_SLOT_ID;
2949     SFTKSlot *slot;
2950     int moduleIndex = isFIPS ? NSC_NON_FIPS_MODULE : NSC_FIPS_MODULE;
2951     PLHashTable *tmpSlotHashTable = nscSlotHashTable[moduleIndex];
2952 
2953     slot = (SFTKSlot *)PL_HashTableLookup(tmpSlotHashTable, (void *)slotID);
2954     if (slot == NULL) {
2955         return;
2956     }
2957     sftk_DBShutdown(slot);
2958     return;
2959 }
2960 
2961 /* NSC_Initialize initializes the Cryptoki library. */
2962 CK_RV
nsc_CommonInitialize(CK_VOID_PTR pReserved,PRBool isFIPS)2963 nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS)
2964 {
2965     CK_RV crv = CKR_OK;
2966     SECStatus rv;
2967     CK_C_INITIALIZE_ARGS *init_args = (CK_C_INITIALIZE_ARGS *)pReserved;
2968     int i;
2969     int moduleIndex = isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE;
2970 
2971     if (isFIPS) {
2972         loginWaitTime = PR_SecondsToInterval(1);
2973     }
2974 
2975     ENABLE_FORK_CHECK();
2976 
2977     rv = SECOID_Init();
2978     if (rv != SECSuccess) {
2979         crv = CKR_DEVICE_ERROR;
2980         return crv;
2981     }
2982 
2983     rv = RNG_RNGInit(); /* initialize random number generator */
2984     if (rv != SECSuccess) {
2985         crv = CKR_DEVICE_ERROR;
2986         return crv;
2987     }
2988     rv = BL_Init(); /* initialize freebl engine */
2989     if (rv != SECSuccess) {
2990         crv = CKR_DEVICE_ERROR;
2991         return crv;
2992     }
2993 
2994     /* NOTE:
2995      * we should be getting out mutexes from this list, not statically binding
2996      * them from NSPR. This should happen before we allow the internal to split
2997      * off from the rest on NSS.
2998      */
2999 
3000     /* initialize the key and cert db's */
3001     if (init_args && (!(init_args->flags & CKF_OS_LOCKING_OK))) {
3002         if (init_args->CreateMutex && init_args->DestroyMutex &&
3003             init_args->LockMutex && init_args->UnlockMutex) {
3004             /* softoken always uses NSPR (ie. OS locking), and doesn't know how
3005              * to use the lock functions provided by the application.
3006              */
3007             crv = CKR_CANT_LOCK;
3008             return crv;
3009         }
3010         if (init_args->CreateMutex || init_args->DestroyMutex ||
3011             init_args->LockMutex || init_args->UnlockMutex) {
3012             /* only some of the lock functions were provided by the
3013              * application. This is invalid per PKCS#11 spec.
3014              */
3015             crv = CKR_ARGUMENTS_BAD;
3016             return crv;
3017         }
3018     }
3019     crv = CKR_ARGUMENTS_BAD;
3020     if ((init_args && init_args->LibraryParameters)) {
3021         sftk_parameters paramStrings;
3022 
3023         crv = sftk_parseParameters((char *)init_args->LibraryParameters, &paramStrings, isFIPS);
3024         if (crv != CKR_OK) {
3025             return crv;
3026         }
3027         crv = sftk_configure(paramStrings.man, paramStrings.libdes);
3028         if (crv != CKR_OK) {
3029             goto loser;
3030         }
3031 
3032         /* if we have a peer already open, have him close his DB's so we
3033          * don't clobber each other. */
3034         if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) {
3035             sftk_closePeer(isFIPS);
3036             if (sftk_audit_enabled) {
3037                 if (isFIPS && nsc_init) {
3038                     sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE,
3039                                          "enabled FIPS mode");
3040                 } else {
3041                     sftk_LogAuditMessage(NSS_AUDIT_INFO, NSS_AUDIT_FIPS_STATE,
3042                                          "disabled FIPS mode");
3043                 }
3044             }
3045         }
3046 
3047         for (i = 0; i < paramStrings.token_count; i++) {
3048             crv = SFTK_SlotInit(paramStrings.configdir,
3049                                 paramStrings.updatedir, paramStrings.updateID,
3050                                 &paramStrings.tokens[i], moduleIndex);
3051             if (crv != CKR_OK) {
3052                 nscFreeAllSlots(moduleIndex);
3053                 break;
3054             }
3055         }
3056     loser:
3057         sftk_freeParams(&paramStrings);
3058     }
3059     if (CKR_OK == crv) {
3060         sftk_InitFreeLists();
3061     }
3062 
3063 #ifndef NO_FORK_CHECK
3064     if (CKR_OK == crv) {
3065 #if defined(CHECK_FORK_MIXED)
3066         /* Before Solaris 10, fork handlers are not unregistered at dlclose()
3067          * time. So, we only use pthread_atfork on Solaris 10 and later. For
3068          * earlier versions, we use PID checks.
3069          */
3070         char buf[200];
3071         int major = 0, minor = 0;
3072 
3073         long rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
3074         if (rv > 0 && rv < sizeof(buf)) {
3075             if (2 == sscanf(buf, "%d.%d", &major, &minor)) {
3076                 /* Are we on Solaris 10 or greater ? */
3077                 if (major > 5 || (5 == major && minor >= 10)) {
3078                     /* we are safe to use pthread_atfork */
3079                     usePthread_atfork = PR_TRUE;
3080                 }
3081             }
3082         }
3083         if (usePthread_atfork) {
3084             pthread_atfork(NULL, NULL, ForkedChild);
3085         } else {
3086             myPid = getpid();
3087         }
3088 
3089 #elif defined(CHECK_FORK_PTHREAD)
3090         pthread_atfork(NULL, NULL, ForkedChild);
3091 #elif defined(CHECK_FORK_GETPID)
3092         myPid = getpid();
3093 #else
3094 #error Incorrect fork check method.
3095 #endif
3096     }
3097 #endif
3098     return crv;
3099 }
3100 
3101 CK_RV
NSC_Initialize(CK_VOID_PTR pReserved)3102 NSC_Initialize(CK_VOID_PTR pReserved)
3103 {
3104     CK_RV crv;
3105 
3106     sftk_ForkReset(pReserved, &crv);
3107 
3108     if (nsc_init) {
3109         return CKR_CRYPTOKI_ALREADY_INITIALIZED;
3110     }
3111     crv = nsc_CommonInitialize(pReserved, PR_FALSE);
3112     nsc_init = (PRBool)(crv == CKR_OK);
3113     return crv;
3114 }
3115 
3116 /* NSC_Finalize indicates that an application is done with the
3117  * Cryptoki library.*/
3118 CK_RV
nsc_CommonFinalize(CK_VOID_PTR pReserved,PRBool isFIPS)3119 nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS)
3120 {
3121     /* propagate the fork status to freebl and util */
3122     BL_SetForkState(parentForkedAfterC_Initialize);
3123     UTIL_SetForkState(parentForkedAfterC_Initialize);
3124 
3125     nscFreeAllSlots(isFIPS ? NSC_FIPS_MODULE : NSC_NON_FIPS_MODULE);
3126 
3127     /* don't muck with the globals if our peer is still initialized */
3128     if (isFIPS && nsc_init) {
3129         return CKR_OK;
3130     }
3131     if (!isFIPS && nsf_init) {
3132         return CKR_OK;
3133     }
3134 
3135     sftk_CleanupFreeLists();
3136     sftkdb_Shutdown();
3137 
3138     /* This function does not discard all our previously aquired entropy. */
3139     RNG_RNGShutdown();
3140 
3141     /* tell freeBL to clean up after itself */
3142     BL_Cleanup();
3143 
3144     /* reset fork status in freebl. We must do this before BL_Unload so that
3145      * this call doesn't force freebl to be reloaded. */
3146     BL_SetForkState(PR_FALSE);
3147 
3148     /* unload freeBL shared library from memory. This may only decrement the
3149      * OS refcount if it's been loaded multiple times, eg. by libssl */
3150     BL_Unload();
3151 
3152     /* clean up the default OID table */
3153     SECOID_Shutdown();
3154 
3155     /* reset fork status in util */
3156     UTIL_SetForkState(PR_FALSE);
3157 
3158     nsc_init = PR_FALSE;
3159 
3160 #ifdef CHECK_FORK_MIXED
3161     if (!usePthread_atfork) {
3162         myPid = 0; /* allow CHECK_FORK in the next softoken initialization to
3163                     * succeed */
3164     } else {
3165         forked = PR_FALSE; /* allow reinitialization */
3166     }
3167 #elif defined(CHECK_FORK_GETPID)
3168     myPid = 0; /* allow reinitialization */
3169 #elif defined(CHECK_FORK_PTHREAD)
3170     forked = PR_FALSE; /* allow reinitialization */
3171 #endif
3172     return CKR_OK;
3173 }
3174 
3175 /* Hard-reset the entire softoken PKCS#11 module if the parent process forked
3176  * while it was initialized. */
3177 PRBool
sftk_ForkReset(CK_VOID_PTR pReserved,CK_RV * crv)3178 sftk_ForkReset(CK_VOID_PTR pReserved, CK_RV *crv)
3179 {
3180 #ifndef NO_FORK_CHECK
3181     if (PARENT_FORKED()) {
3182         parentForkedAfterC_Initialize = PR_TRUE;
3183         if (nsc_init) {
3184             /* finalize non-FIPS token */
3185             *crv = nsc_CommonFinalize(pReserved, PR_FALSE);
3186             PORT_Assert(CKR_OK == *crv);
3187             nsc_init = (PRBool) !(*crv == CKR_OK);
3188         }
3189         if (nsf_init) {
3190             /* finalize FIPS token */
3191             *crv = nsc_CommonFinalize(pReserved, PR_TRUE);
3192             PORT_Assert(CKR_OK == *crv);
3193             nsf_init = (PRBool) !(*crv == CKR_OK);
3194         }
3195         parentForkedAfterC_Initialize = PR_FALSE;
3196         return PR_TRUE;
3197     }
3198 #endif
3199     return PR_FALSE;
3200 }
3201 
3202 /* NSC_Finalize indicates that an application is done with the
3203  * Cryptoki library.*/
3204 CK_RV
NSC_Finalize(CK_VOID_PTR pReserved)3205 NSC_Finalize(CK_VOID_PTR pReserved)
3206 {
3207     CK_RV crv;
3208 
3209     /* reset entire PKCS#11 module upon fork */
3210     if (sftk_ForkReset(pReserved, &crv)) {
3211         return crv;
3212     }
3213 
3214     if (!nsc_init) {
3215         return CKR_OK;
3216     }
3217 
3218     crv = nsc_CommonFinalize(pReserved, PR_FALSE);
3219 
3220     nsc_init = (PRBool) !(crv == CKR_OK);
3221 
3222     return crv;
3223 }
3224 
3225 extern const char __nss_softokn_version[];
3226 
3227 /* NSC_GetInfo returns general information about Cryptoki. */
3228 CK_RV
NSC_GetInfo(CK_INFO_PTR pInfo)3229 NSC_GetInfo(CK_INFO_PTR pInfo)
3230 {
3231 #define NSS_VERSION_VARIABLE __nss_softokn_version
3232 #include "verref.h"
3233 
3234     CHECK_FORK();
3235 
3236     pInfo->cryptokiVersion.major = 2;
3237     pInfo->cryptokiVersion.minor = 20;
3238     PORT_Memcpy(pInfo->manufacturerID, manufacturerID, 32);
3239     pInfo->libraryVersion.major = SOFTOKEN_VMAJOR;
3240     pInfo->libraryVersion.minor = SOFTOKEN_VMINOR;
3241     PORT_Memcpy(pInfo->libraryDescription, libraryDescription, 32);
3242     pInfo->flags = 0;
3243     return CKR_OK;
3244 }
3245 
3246 /* NSC_GetSlotList obtains a list of slots in the system. */
3247 CK_RV
nsc_CommonGetSlotList(CK_BBOOL tokenPresent,CK_SLOT_ID_PTR pSlotList,CK_ULONG_PTR pulCount,int moduleIndex)3248 nsc_CommonGetSlotList(CK_BBOOL tokenPresent,
3249                       CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount, int moduleIndex)
3250 {
3251     *pulCount = nscSlotCount[moduleIndex];
3252     if (pSlotList != NULL) {
3253         PORT_Memcpy(pSlotList, nscSlotList[moduleIndex],
3254                     nscSlotCount[moduleIndex] * sizeof(CK_SLOT_ID));
3255     }
3256     return CKR_OK;
3257 }
3258 
3259 /* NSC_GetSlotList obtains a list of slots in the system. */
3260 CK_RV
NSC_GetSlotList(CK_BBOOL tokenPresent,CK_SLOT_ID_PTR pSlotList,CK_ULONG_PTR pulCount)3261 NSC_GetSlotList(CK_BBOOL tokenPresent,
3262                 CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount)
3263 {
3264     CHECK_FORK();
3265     return nsc_CommonGetSlotList(tokenPresent, pSlotList, pulCount,
3266                                  NSC_NON_FIPS_MODULE);
3267 }
3268 
3269 /* NSC_GetSlotInfo obtains information about a particular slot in the system. */
3270 CK_RV
NSC_GetSlotInfo(CK_SLOT_ID slotID,CK_SLOT_INFO_PTR pInfo)3271 NSC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo)
3272 {
3273     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_TRUE);
3274 
3275     CHECK_FORK();
3276 
3277     if (slot == NULL)
3278         return CKR_SLOT_ID_INVALID;
3279 
3280     PORT_Memcpy(pInfo->manufacturerID, manufacturerID,
3281                 sizeof(pInfo->manufacturerID));
3282     PORT_Memcpy(pInfo->slotDescription, slot->slotDescription,
3283                 sizeof(pInfo->slotDescription));
3284     pInfo->flags = (slot->present) ? CKF_TOKEN_PRESENT : 0;
3285 
3286     /* all user defined slots are defined as removable */
3287     if (slotID >= SFTK_MIN_USER_SLOT_ID) {
3288         pInfo->flags |= CKF_REMOVABLE_DEVICE;
3289     } else {
3290         /* In the case where we are doing a merge update, we need
3291          * the DB slot to be removable so the token name can change
3292          * appropriately. */
3293         SFTKDBHandle *handle = sftk_getKeyDB(slot);
3294         if (handle) {
3295             if (sftkdb_InUpdateMerge(handle)) {
3296                 pInfo->flags |= CKF_REMOVABLE_DEVICE;
3297             }
3298             sftk_freeDB(handle);
3299         }
3300     }
3301 
3302     /* ok we really should read it out of the keydb file. */
3303     /* pInfo->hardwareVersion.major = NSSLOWKEY_DB_FILE_VERSION; */
3304     pInfo->hardwareVersion.major = SOFTOKEN_VMAJOR;
3305     pInfo->hardwareVersion.minor = SOFTOKEN_VMINOR;
3306     pInfo->firmwareVersion.major = SOFTOKEN_VPATCH;
3307     pInfo->firmwareVersion.minor = SOFTOKEN_VBUILD;
3308     return CKR_OK;
3309 }
3310 
3311 /*
3312  * check the current state of the 'needLogin' flag in case the database has
3313  * been changed underneath us.
3314  */
3315 static PRBool
sftk_checkNeedLogin(SFTKSlot * slot,SFTKDBHandle * keyHandle)3316 sftk_checkNeedLogin(SFTKSlot *slot, SFTKDBHandle *keyHandle)
3317 {
3318     if (sftkdb_PWCached(keyHandle) == SECSuccess) {
3319         return slot->needLogin;
3320     }
3321     slot->needLogin = (PRBool)!sftk_hasNullPassword(slot, keyHandle);
3322     return (slot->needLogin);
3323 }
3324 
3325 static PRBool
sftk_isBlank(const char * s,int len)3326 sftk_isBlank(const char *s, int len)
3327 {
3328     int i;
3329     for (i = 0; i < len; i++) {
3330         if (s[i] != ' ') {
3331             return PR_FALSE;
3332         }
3333     }
3334     return PR_TRUE;
3335 }
3336 
3337 /* NSC_GetTokenInfo obtains information about a particular token in
3338  * the system. */
3339 CK_RV
NSC_GetTokenInfo(CK_SLOT_ID slotID,CK_TOKEN_INFO_PTR pInfo)3340 NSC_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo)
3341 {
3342     SFTKSlot *slot;
3343     SFTKDBHandle *handle;
3344 
3345     CHECK_FORK();
3346 
3347     if (!nsc_init && !nsf_init)
3348         return CKR_CRYPTOKI_NOT_INITIALIZED;
3349     slot = sftk_SlotFromID(slotID, PR_FALSE);
3350     if (slot == NULL)
3351         return CKR_SLOT_ID_INVALID;
3352 
3353     PORT_Memcpy(pInfo->manufacturerID, manufacturerID, 32);
3354     PORT_Memcpy(pInfo->model, "NSS 3           ", 16);
3355     PORT_Memcpy(pInfo->serialNumber, "0000000000000000", 16);
3356     PORT_Memcpy(pInfo->utcTime, "0000000000000000", 16);
3357     pInfo->ulMaxSessionCount = 0; /* arbitrarily large */
3358     pInfo->ulSessionCount = slot->sessionCount;
3359     pInfo->ulMaxRwSessionCount = 0; /* arbitarily large */
3360     pInfo->ulRwSessionCount = slot->rwSessionCount;
3361     pInfo->firmwareVersion.major = 0;
3362     pInfo->firmwareVersion.minor = 0;
3363     PORT_Memcpy(pInfo->label, slot->tokDescription, sizeof(pInfo->label));
3364     handle = sftk_getKeyDB(slot);
3365     pInfo->flags = CKF_RNG | CKF_DUAL_CRYPTO_OPERATIONS;
3366     if (handle == NULL) {
3367         pInfo->flags |= CKF_WRITE_PROTECTED;
3368         pInfo->ulMaxPinLen = 0;
3369         pInfo->ulMinPinLen = 0;
3370         pInfo->ulTotalPublicMemory = 0;
3371         pInfo->ulFreePublicMemory = 0;
3372         pInfo->ulTotalPrivateMemory = 0;
3373         pInfo->ulFreePrivateMemory = 0;
3374         pInfo->hardwareVersion.major = 4;
3375         pInfo->hardwareVersion.minor = 0;
3376     } else {
3377         /*
3378          * we have three possible states which we may be in:
3379          *   (1) No DB password has been initialized. This also means we
3380          *   have no keys in the key db.
3381          *   (2) Password initialized to NULL. This means we have keys, but
3382          *   the user has chosen not use a password.
3383          *   (3) Finally we have an initialized password whicn is not NULL, and
3384          *   we will need to prompt for it.
3385          */
3386         if (sftkdb_HasPasswordSet(handle) == SECFailure) {
3387             pInfo->flags |= CKF_LOGIN_REQUIRED;
3388         } else if (!sftk_checkNeedLogin(slot, handle)) {
3389             pInfo->flags |= CKF_USER_PIN_INITIALIZED;
3390         } else {
3391             pInfo->flags |= CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED;
3392             /*
3393              * if we are doing a merge style update, and we need to get the password
3394              * of our source database (the database we are updating from), make sure we
3395              * return a token name that will match the database we are prompting for.
3396              */
3397             if (sftkdb_NeedUpdateDBPassword(handle)) {
3398                 /* if we have an update tok description, use it. otherwise
3399                  * use the updateID for this database */
3400                 if (!sftk_isBlank(slot->updateTokDescription,
3401                                   sizeof(pInfo->label))) {
3402                     PORT_Memcpy(pInfo->label, slot->updateTokDescription,
3403                                 sizeof(pInfo->label));
3404                 } else {
3405                     /* build from updateID */
3406                     const char *updateID = sftkdb_GetUpdateID(handle);
3407                     if (updateID) {
3408                         sftk_setStringName(updateID, (char *)pInfo->label,
3409                                            sizeof(pInfo->label), PR_FALSE);
3410                     }
3411                 }
3412             }
3413         }
3414         pInfo->ulMaxPinLen = SFTK_MAX_PIN;
3415         pInfo->ulMinPinLen = (CK_ULONG)slot->minimumPinLen;
3416         pInfo->ulTotalPublicMemory = 1;
3417         pInfo->ulFreePublicMemory = 1;
3418         pInfo->ulTotalPrivateMemory = 1;
3419         pInfo->ulFreePrivateMemory = 1;
3420 #ifdef SHDB_FIXME
3421         pInfo->hardwareVersion.major = CERT_DB_FILE_VERSION;
3422         pInfo->hardwareVersion.minor = handle->version;
3423 #else
3424         pInfo->hardwareVersion.major = 0;
3425         pInfo->hardwareVersion.minor = 0;
3426 #endif
3427         sftk_freeDB(handle);
3428     }
3429     /*
3430      * CKF_LOGIN_REQUIRED CKF_USER_PIN_INITIALIZED  how CKF_TOKEN_INITIALIZED
3431      *                                              should be set
3432      *         0                   0                           1
3433      *         1                   0                           0
3434      *         0                   1                           1
3435      *         1                   1                           1
3436      */
3437     if (!(pInfo->flags & CKF_LOGIN_REQUIRED) ||
3438         (pInfo->flags & CKF_USER_PIN_INITIALIZED)) {
3439         pInfo->flags |= CKF_TOKEN_INITIALIZED;
3440     }
3441     return CKR_OK;
3442 }
3443 
3444 /* NSC_GetMechanismList obtains a list of mechanism types
3445  * supported by a token. */
3446 CK_RV
NSC_GetMechanismList(CK_SLOT_ID slotID,CK_MECHANISM_TYPE_PTR pMechanismList,CK_ULONG_PTR pulCount)3447 NSC_GetMechanismList(CK_SLOT_ID slotID,
3448                      CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount)
3449 {
3450     CK_ULONG i;
3451 
3452     CHECK_FORK();
3453 
3454     switch (slotID) {
3455         /* default: */
3456         case NETSCAPE_SLOT_ID:
3457             *pulCount = mechanismCount;
3458             if (pMechanismList != NULL) {
3459                 for (i = 0; i < mechanismCount; i++) {
3460                     pMechanismList[i] = mechanisms[i].type;
3461                 }
3462             }
3463             break;
3464         default:
3465             *pulCount = 0;
3466             for (i = 0; i < mechanismCount; i++) {
3467                 if (mechanisms[i].privkey) {
3468                     (*pulCount)++;
3469                     if (pMechanismList != NULL) {
3470                         *pMechanismList++ = mechanisms[i].type;
3471                     }
3472                 }
3473             }
3474             break;
3475     }
3476     return CKR_OK;
3477 }
3478 
3479 /* NSC_GetMechanismInfo obtains information about a particular mechanism
3480  * possibly supported by a token. */
3481 CK_RV
NSC_GetMechanismInfo(CK_SLOT_ID slotID,CK_MECHANISM_TYPE type,CK_MECHANISM_INFO_PTR pInfo)3482 NSC_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type,
3483                      CK_MECHANISM_INFO_PTR pInfo)
3484 {
3485     PRBool isPrivateKey;
3486     CK_ULONG i;
3487 
3488     CHECK_FORK();
3489 
3490     switch (slotID) {
3491         case NETSCAPE_SLOT_ID:
3492             isPrivateKey = PR_FALSE;
3493             break;
3494         default:
3495             isPrivateKey = PR_TRUE;
3496             break;
3497     }
3498     for (i = 0; i < mechanismCount; i++) {
3499         if (type == mechanisms[i].type) {
3500             if (isPrivateKey && !mechanisms[i].privkey) {
3501                 return CKR_MECHANISM_INVALID;
3502             }
3503             PORT_Memcpy(pInfo, &mechanisms[i].info, sizeof(CK_MECHANISM_INFO));
3504             return CKR_OK;
3505         }
3506     }
3507     return CKR_MECHANISM_INVALID;
3508 }
3509 
3510 CK_RV
sftk_MechAllowsOperation(CK_MECHANISM_TYPE type,CK_ATTRIBUTE_TYPE op)3511 sftk_MechAllowsOperation(CK_MECHANISM_TYPE type, CK_ATTRIBUTE_TYPE op)
3512 {
3513     CK_ULONG i;
3514     CK_FLAGS flags;
3515 
3516     switch (op) {
3517         case CKA_ENCRYPT:
3518             flags = CKF_ENCRYPT;
3519             break;
3520         case CKA_DECRYPT:
3521             flags = CKF_DECRYPT;
3522             break;
3523         case CKA_WRAP:
3524             flags = CKF_WRAP;
3525             break;
3526         case CKA_UNWRAP:
3527             flags = CKF_UNWRAP;
3528             break;
3529         case CKA_SIGN:
3530             flags = CKF_SIGN;
3531             break;
3532         case CKA_SIGN_RECOVER:
3533             flags = CKF_SIGN_RECOVER;
3534             break;
3535         case CKA_VERIFY:
3536             flags = CKF_VERIFY;
3537             break;
3538         case CKA_VERIFY_RECOVER:
3539             flags = CKF_VERIFY_RECOVER;
3540             break;
3541         case CKA_DERIVE:
3542             flags = CKF_DERIVE;
3543             break;
3544         default:
3545             return CKR_ARGUMENTS_BAD;
3546     }
3547     for (i = 0; i < mechanismCount; i++) {
3548         if (type == mechanisms[i].type) {
3549             return (flags & mechanisms[i].info.flags) ? CKR_OK
3550                                                       : CKR_MECHANISM_INVALID;
3551         }
3552     }
3553     return CKR_MECHANISM_INVALID;
3554 }
3555 
3556 /* NSC_InitToken initializes a token. */
3557 CK_RV
NSC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin,CK_ULONG ulPinLen,CK_CHAR_PTR pLabel)3558 NSC_InitToken(CK_SLOT_ID slotID, CK_CHAR_PTR pPin,
3559               CK_ULONG ulPinLen, CK_CHAR_PTR pLabel)
3560 {
3561     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);
3562     SFTKDBHandle *handle;
3563     SFTKDBHandle *certHandle;
3564     SECStatus rv;
3565     unsigned int i;
3566     SFTKObject *object;
3567 
3568     CHECK_FORK();
3569 
3570     if (slot == NULL)
3571         return CKR_SLOT_ID_INVALID;
3572 
3573     /* don't initialize the database if we aren't talking to a token
3574      * that uses the key database.
3575      */
3576     if (slotID == NETSCAPE_SLOT_ID) {
3577         return CKR_TOKEN_WRITE_PROTECTED;
3578     }
3579 
3580     /* first, delete all our loaded key and cert objects from our
3581      * internal list. */
3582     PZ_Lock(slot->objectLock);
3583     for (i = 0; i < slot->sessObjHashSize; i++) {
3584         do {
3585             object = slot->sessObjHashTable[i];
3586             /* hand deque */
3587             /* this duplicates function of NSC_close session functions, but
3588              * because we know that we are freeing all the sessions, we can
3589              * do more efficient processing */
3590             if (object) {
3591                 slot->sessObjHashTable[i] = object->next;
3592 
3593                 if (object->next)
3594                     object->next->prev = NULL;
3595                 object->next = object->prev = NULL;
3596             }
3597             if (object)
3598                 sftk_FreeObject(object);
3599         } while (object != NULL);
3600     }
3601     slot->DB_loaded = PR_FALSE;
3602     PZ_Unlock(slot->objectLock);
3603 
3604     /* then clear out the key database */
3605     handle = sftk_getKeyDB(slot);
3606     if (handle == NULL) {
3607         return CKR_TOKEN_WRITE_PROTECTED;
3608     }
3609 
3610     rv = sftkdb_ResetKeyDB(handle);
3611     sftk_freeDB(handle);
3612     if (rv != SECSuccess) {
3613         return CKR_DEVICE_ERROR;
3614     }
3615 
3616     /* finally  mark all the user certs as non-user certs */
3617     certHandle = sftk_getCertDB(slot);
3618     if (certHandle == NULL)
3619         return CKR_OK;
3620 
3621     sftk_freeDB(certHandle);
3622 
3623     return CKR_OK; /*is this the right function for not implemented*/
3624 }
3625 
3626 /* NSC_InitPIN initializes the normal user's PIN. */
3627 CK_RV
NSC_InitPIN(CK_SESSION_HANDLE hSession,CK_CHAR_PTR pPin,CK_ULONG ulPinLen)3628 NSC_InitPIN(CK_SESSION_HANDLE hSession,
3629             CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
3630 {
3631     SFTKSession *sp = NULL;
3632     SFTKSlot *slot;
3633     SFTKDBHandle *handle = NULL;
3634     char newPinStr[SFTK_MAX_PIN + 1];
3635     SECStatus rv;
3636     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
3637     PRBool tokenRemoved = PR_FALSE;
3638 
3639     CHECK_FORK();
3640 
3641     sp = sftk_SessionFromHandle(hSession);
3642     if (sp == NULL) {
3643         goto loser;
3644     }
3645 
3646     slot = sftk_SlotFromSession(sp);
3647     if (slot == NULL) {
3648         goto loser;
3649     }
3650 
3651     handle = sftk_getKeyDB(slot);
3652     if (handle == NULL) {
3653         crv = CKR_PIN_LEN_RANGE;
3654         goto loser;
3655     }
3656 
3657     if (sp->info.state != CKS_RW_SO_FUNCTIONS) {
3658         crv = CKR_USER_NOT_LOGGED_IN;
3659         goto loser;
3660     }
3661 
3662     sftk_FreeSession(sp);
3663     sp = NULL;
3664 
3665     /* make sure the pins aren't too long */
3666     if (ulPinLen > SFTK_MAX_PIN) {
3667         crv = CKR_PIN_LEN_RANGE;
3668         goto loser;
3669     }
3670     if (ulPinLen < (CK_ULONG)slot->minimumPinLen) {
3671         crv = CKR_PIN_LEN_RANGE;
3672         goto loser;
3673     }
3674 
3675     if (sftkdb_HasPasswordSet(handle) != SECFailure) {
3676         crv = CKR_DEVICE_ERROR;
3677         goto loser;
3678     }
3679 
3680     /* convert to null terminated string */
3681     PORT_Memcpy(newPinStr, pPin, ulPinLen);
3682     newPinStr[ulPinLen] = 0;
3683 
3684     /* build the hashed pins which we pass around */
3685 
3686     /* change the data base */
3687     rv = sftkdb_ChangePassword(handle, NULL, newPinStr, &tokenRemoved);
3688     if (tokenRemoved) {
3689         sftk_CloseAllSessions(slot, PR_FALSE);
3690     }
3691     sftk_freeDB(handle);
3692     handle = NULL;
3693 
3694     /* Now update our local copy of the pin */
3695     if (rv == SECSuccess) {
3696         if (ulPinLen == 0)
3697             slot->needLogin = PR_FALSE;
3698         /* database has been initialized, now force min password in FIPS
3699          * mode. NOTE: if we are in level1, we may not have a password, but
3700          * forcing it now will prevent an insufficient password from being set.
3701          */
3702         if ((sftk_GetModuleIndex(slot->slotID) == NSC_FIPS_MODULE) &&
3703             (slot->minimumPinLen < FIPS_MIN_PIN)) {
3704             slot->minimumPinLen = FIPS_MIN_PIN;
3705         }
3706         return CKR_OK;
3707     }
3708     crv = CKR_PIN_INCORRECT;
3709 
3710 loser:
3711     if (sp) {
3712         sftk_FreeSession(sp);
3713     }
3714     if (handle) {
3715         sftk_freeDB(handle);
3716     }
3717     return crv;
3718 }
3719 
3720 /* NSC_SetPIN modifies the PIN of user that is currently logged in. */
3721 /* NOTE: This is only valid for the PRIVATE_KEY_SLOT */
3722 CK_RV
NSC_SetPIN(CK_SESSION_HANDLE hSession,CK_CHAR_PTR pOldPin,CK_ULONG ulOldLen,CK_CHAR_PTR pNewPin,CK_ULONG ulNewLen)3723 NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin,
3724            CK_ULONG ulOldLen, CK_CHAR_PTR pNewPin, CK_ULONG ulNewLen)
3725 {
3726     SFTKSession *sp = NULL;
3727     SFTKSlot *slot;
3728     SFTKDBHandle *handle = NULL;
3729     char newPinStr[SFTK_MAX_PIN + 1], oldPinStr[SFTK_MAX_PIN + 1];
3730     SECStatus rv;
3731     CK_RV crv = CKR_SESSION_HANDLE_INVALID;
3732     PRBool tokenRemoved = PR_FALSE;
3733 
3734     CHECK_FORK();
3735 
3736     sp = sftk_SessionFromHandle(hSession);
3737     if (sp == NULL) {
3738         goto loser;
3739     }
3740 
3741     slot = sftk_SlotFromSession(sp);
3742     if (!slot) {
3743         goto loser;
3744     }
3745 
3746     handle = sftk_getKeyDB(slot);
3747     if (handle == NULL) {
3748         sftk_FreeSession(sp);
3749         return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */
3750     }
3751 
3752     if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) {
3753         crv = CKR_USER_NOT_LOGGED_IN;
3754         goto loser;
3755     }
3756 
3757     sftk_FreeSession(sp);
3758     sp = NULL;
3759 
3760     /* make sure the pins aren't too long */
3761     if ((ulNewLen > SFTK_MAX_PIN) || (ulOldLen > SFTK_MAX_PIN)) {
3762         crv = CKR_PIN_LEN_RANGE;
3763         goto loser;
3764     }
3765     if (ulNewLen < (CK_ULONG)slot->minimumPinLen) {
3766         crv = CKR_PIN_LEN_RANGE;
3767         goto loser;
3768     }
3769 
3770     /* convert to null terminated string */
3771     PORT_Memcpy(newPinStr, pNewPin, ulNewLen);
3772     newPinStr[ulNewLen] = 0;
3773     PORT_Memcpy(oldPinStr, pOldPin, ulOldLen);
3774     oldPinStr[ulOldLen] = 0;
3775 
3776     /* change the data base password */
3777     PR_Lock(slot->pwCheckLock);
3778     rv = sftkdb_ChangePassword(handle, oldPinStr, newPinStr, &tokenRemoved);
3779     if (tokenRemoved) {
3780         sftk_CloseAllSessions(slot, PR_FALSE);
3781     }
3782     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
3783         PR_Sleep(loginWaitTime);
3784     }
3785     PR_Unlock(slot->pwCheckLock);
3786 
3787     /* Now update our local copy of the pin */
3788     if (rv == SECSuccess) {
3789         slot->needLogin = (PRBool)(ulNewLen != 0);
3790         /* Reset login flags. */
3791         if (ulNewLen == 0) {
3792             PRBool tokenRemoved = PR_FALSE;
3793             PZ_Lock(slot->slotLock);
3794             slot->isLoggedIn = PR_FALSE;
3795             slot->ssoLoggedIn = PR_FALSE;
3796             PZ_Unlock(slot->slotLock);
3797 
3798             rv = sftkdb_CheckPassword(handle, "", &tokenRemoved);
3799             if (tokenRemoved) {
3800                 sftk_CloseAllSessions(slot, PR_FALSE);
3801             }
3802         }
3803         sftk_update_all_states(slot);
3804         sftk_freeDB(handle);
3805         return CKR_OK;
3806     }
3807     crv = CKR_PIN_INCORRECT;
3808 loser:
3809     if (sp) {
3810         sftk_FreeSession(sp);
3811     }
3812     if (handle) {
3813         sftk_freeDB(handle);
3814     }
3815     return crv;
3816 }
3817 
3818 /* NSC_OpenSession opens a session between an application and a token. */
3819 CK_RV
NSC_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE_PTR phSession)3820 NSC_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags,
3821                 CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
3822 {
3823     SFTKSlot *slot;
3824     CK_SESSION_HANDLE sessionID;
3825     SFTKSession *session;
3826     SFTKSession *sameID;
3827 
3828     CHECK_FORK();
3829 
3830     slot = sftk_SlotFromID(slotID, PR_FALSE);
3831     if (slot == NULL)
3832         return CKR_SLOT_ID_INVALID;
3833 
3834     /* new session (we only have serial sessions) */
3835     session = sftk_NewSession(slotID, Notify, pApplication,
3836                               flags | CKF_SERIAL_SESSION);
3837     if (session == NULL)
3838         return CKR_HOST_MEMORY;
3839 
3840     if (slot->readOnly && (flags & CKF_RW_SESSION)) {
3841         /* NETSCAPE_SLOT_ID is Read ONLY */
3842         session->info.flags &= ~CKF_RW_SESSION;
3843     }
3844     PZ_Lock(slot->slotLock);
3845     ++slot->sessionCount;
3846     PZ_Unlock(slot->slotLock);
3847     if (session->info.flags & CKF_RW_SESSION) {
3848         (void)PR_ATOMIC_INCREMENT(&slot->rwSessionCount);
3849     }
3850 
3851     do {
3852         PZLock *lock;
3853         do {
3854             sessionID = (PR_ATOMIC_INCREMENT(&slot->sessionIDCount) & 0xffffff) | (slot->index << 24);
3855         } while (sessionID == CK_INVALID_HANDLE);
3856         lock = SFTK_SESSION_LOCK(slot, sessionID);
3857         PZ_Lock(lock);
3858         sftkqueue_find(sameID, sessionID, slot->head, slot->sessHashSize);
3859         if (sameID == NULL) {
3860             session->handle = sessionID;
3861             sftk_update_state(slot, session);
3862             sftkqueue_add(session, sessionID, slot->head, slot->sessHashSize);
3863         } else {
3864             slot->sessionIDConflict++; /* for debugging */
3865         }
3866         PZ_Unlock(lock);
3867     } while (sameID != NULL);
3868 
3869     *phSession = sessionID;
3870     return CKR_OK;
3871 }
3872 
3873 /* NSC_CloseSession closes a session between an application and a token. */
3874 CK_RV
NSC_CloseSession(CK_SESSION_HANDLE hSession)3875 NSC_CloseSession(CK_SESSION_HANDLE hSession)
3876 {
3877     SFTKSlot *slot;
3878     SFTKSession *session;
3879     PRBool sessionFound;
3880     PZLock *lock;
3881 
3882     CHECK_FORK();
3883 
3884     session = sftk_SessionFromHandle(hSession);
3885     if (session == NULL)
3886         return CKR_SESSION_HANDLE_INVALID;
3887     slot = sftk_SlotFromSession(session);
3888     sessionFound = PR_FALSE;
3889 
3890     /* lock */
3891     lock = SFTK_SESSION_LOCK(slot, hSession);
3892     PZ_Lock(lock);
3893     if (sftkqueue_is_queued(session, hSession, slot->head, slot->sessHashSize)) {
3894         sessionFound = PR_TRUE;
3895         sftkqueue_delete(session, hSession, slot->head, slot->sessHashSize);
3896         session->refCount--; /* can't go to zero while we hold the reference */
3897         PORT_Assert(session->refCount > 0);
3898     }
3899     PZ_Unlock(lock);
3900 
3901     if (sessionFound) {
3902         SFTKDBHandle *handle;
3903         handle = sftk_getKeyDB(slot);
3904         PZ_Lock(slot->slotLock);
3905         if (--slot->sessionCount == 0) {
3906             slot->isLoggedIn = PR_FALSE;
3907             if (slot->needLogin && handle) {
3908                 sftkdb_ClearPassword(handle);
3909             }
3910         }
3911         PZ_Unlock(slot->slotLock);
3912         if (handle) {
3913             sftk_freeDB(handle);
3914         }
3915         if (session->info.flags & CKF_RW_SESSION) {
3916             (void)PR_ATOMIC_DECREMENT(&slot->rwSessionCount);
3917         }
3918     }
3919 
3920     sftk_FreeSession(session);
3921     return CKR_OK;
3922 }
3923 
3924 /* NSC_CloseAllSessions closes all sessions with a token. */
3925 CK_RV
NSC_CloseAllSessions(CK_SLOT_ID slotID)3926 NSC_CloseAllSessions(CK_SLOT_ID slotID)
3927 {
3928     SFTKSlot *slot;
3929 
3930 #ifndef NO_FORK_CHECK
3931     /* skip fork check if we are being called from C_Initialize or C_Finalize */
3932     if (!parentForkedAfterC_Initialize) {
3933         CHECK_FORK();
3934     }
3935 #endif
3936 
3937     slot = sftk_SlotFromID(slotID, PR_FALSE);
3938     if (slot == NULL)
3939         return CKR_SLOT_ID_INVALID;
3940 
3941     return sftk_CloseAllSessions(slot, PR_TRUE);
3942 }
3943 
3944 /* NSC_GetSessionInfo obtains information about the session. */
3945 CK_RV
NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,CK_SESSION_INFO_PTR pInfo)3946 NSC_GetSessionInfo(CK_SESSION_HANDLE hSession,
3947                    CK_SESSION_INFO_PTR pInfo)
3948 {
3949     SFTKSession *session;
3950 
3951     CHECK_FORK();
3952 
3953     session = sftk_SessionFromHandle(hSession);
3954     if (session == NULL)
3955         return CKR_SESSION_HANDLE_INVALID;
3956 
3957     PORT_Memcpy(pInfo, &session->info, sizeof(CK_SESSION_INFO));
3958     sftk_FreeSession(session);
3959     return CKR_OK;
3960 }
3961 
3962 /* NSC_Login logs a user into a token. */
3963 CK_RV
NSC_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,CK_CHAR_PTR pPin,CK_ULONG ulPinLen)3964 NSC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
3965           CK_CHAR_PTR pPin, CK_ULONG ulPinLen)
3966 {
3967     SFTKSlot *slot;
3968     SFTKSession *session;
3969     SFTKDBHandle *handle;
3970     CK_FLAGS sessionFlags;
3971     SECStatus rv;
3972     CK_RV crv;
3973     char pinStr[SFTK_MAX_PIN + 1];
3974     PRBool tokenRemoved = PR_FALSE;
3975 
3976     CHECK_FORK();
3977 
3978     /* get the slot */
3979     slot = sftk_SlotFromSessionHandle(hSession);
3980     if (slot == NULL) {
3981         return CKR_SESSION_HANDLE_INVALID;
3982     }
3983 
3984     /* make sure the session is valid */
3985     session = sftk_SessionFromHandle(hSession);
3986     if (session == NULL) {
3987         return CKR_SESSION_HANDLE_INVALID;
3988     }
3989     sessionFlags = session->info.flags;
3990     sftk_FreeSession(session);
3991     session = NULL;
3992 
3993     /* can't log into the Netscape Slot */
3994     if (slot->slotID == NETSCAPE_SLOT_ID) {
3995         return CKR_USER_TYPE_INVALID;
3996     }
3997 
3998     if (slot->isLoggedIn)
3999         return CKR_USER_ALREADY_LOGGED_IN;
4000     if (!slot->needLogin) {
4001         return ulPinLen ? CKR_PIN_INCORRECT : CKR_OK;
4002     }
4003     slot->ssoLoggedIn = PR_FALSE;
4004 
4005     if (ulPinLen > SFTK_MAX_PIN)
4006         return CKR_PIN_LEN_RANGE;
4007 
4008     /* convert to null terminated string */
4009     if (ulPinLen) {
4010         PORT_Memcpy(pinStr, pPin, ulPinLen);
4011     }
4012     pinStr[ulPinLen] = 0;
4013 
4014     handle = sftk_getKeyDB(slot);
4015     if (handle == NULL) {
4016         return CKR_USER_TYPE_INVALID;
4017     }
4018 
4019     /*
4020      * Deal with bootstrap. We allow the SSO to login in with a NULL
4021      * password if and only if we haven't initialized the KEY DB yet.
4022      * We only allow this on a RW session.
4023      */
4024     rv = sftkdb_HasPasswordSet(handle);
4025     if (rv == SECFailure) {
4026         /* allow SSO's to log in only if there is not password on the
4027          * key database */
4028         if (((userType == CKU_SO) && (sessionFlags & CKF_RW_SESSION))
4029             /* fips always needs to authenticate, even if there isn't a db */
4030             || (slot->slotID == FIPS_SLOT_ID)) {
4031             /* should this be a fixed password? */
4032             if (ulPinLen == 0) {
4033                 sftkdb_ClearPassword(handle);
4034                 PZ_Lock(slot->slotLock);
4035                 slot->isLoggedIn = PR_TRUE;
4036                 slot->ssoLoggedIn = (PRBool)(userType == CKU_SO);
4037                 PZ_Unlock(slot->slotLock);
4038                 sftk_update_all_states(slot);
4039                 crv = CKR_OK;
4040                 goto done;
4041             }
4042             crv = CKR_PIN_INCORRECT;
4043             goto done;
4044         }
4045         crv = CKR_USER_TYPE_INVALID;
4046         goto done;
4047     }
4048 
4049     /* don't allow the SSO to log in if the user is already initialized */
4050     if (userType != CKU_USER) {
4051         crv = CKR_USER_TYPE_INVALID;
4052         goto done;
4053     }
4054 
4055     /* build the hashed pins which we pass around */
4056     PR_Lock(slot->pwCheckLock);
4057     rv = sftkdb_CheckPassword(handle, pinStr, &tokenRemoved);
4058     if (tokenRemoved) {
4059         sftk_CloseAllSessions(slot, PR_FALSE);
4060     }
4061     if ((rv != SECSuccess) && (slot->slotID == FIPS_SLOT_ID)) {
4062         PR_Sleep(loginWaitTime);
4063     }
4064     PR_Unlock(slot->pwCheckLock);
4065     if (rv == SECSuccess) {
4066         PZ_Lock(slot->slotLock);
4067         /* make sure the login state matches the underlying
4068          * database state */
4069         slot->isLoggedIn = sftkdb_PWCached(handle) == SECSuccess ? PR_TRUE : PR_FALSE;
4070         PZ_Unlock(slot->slotLock);
4071 
4072         sftk_freeDB(handle);
4073         handle = NULL;
4074 
4075         /* update all sessions */
4076         sftk_update_all_states(slot);
4077         return CKR_OK;
4078     }
4079 
4080     crv = CKR_PIN_INCORRECT;
4081 done:
4082     if (handle) {
4083         sftk_freeDB(handle);
4084     }
4085     return crv;
4086 }
4087 
4088 /* NSC_Logout logs a user out from a token. */
4089 CK_RV
NSC_Logout(CK_SESSION_HANDLE hSession)4090 NSC_Logout(CK_SESSION_HANDLE hSession)
4091 {
4092     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4093     SFTKSession *session;
4094     SFTKDBHandle *handle;
4095 
4096     CHECK_FORK();
4097 
4098     if (slot == NULL) {
4099         return CKR_SESSION_HANDLE_INVALID;
4100     }
4101     session = sftk_SessionFromHandle(hSession);
4102     if (session == NULL)
4103         return CKR_SESSION_HANDLE_INVALID;
4104     sftk_FreeSession(session);
4105     session = NULL;
4106 
4107     if (!slot->isLoggedIn)
4108         return CKR_USER_NOT_LOGGED_IN;
4109 
4110     handle = sftk_getKeyDB(slot);
4111     PZ_Lock(slot->slotLock);
4112     slot->isLoggedIn = PR_FALSE;
4113     slot->ssoLoggedIn = PR_FALSE;
4114     if (slot->needLogin && handle) {
4115         sftkdb_ClearPassword(handle);
4116     }
4117     PZ_Unlock(slot->slotLock);
4118     if (handle) {
4119         sftk_freeDB(handle);
4120     }
4121 
4122     sftk_update_all_states(slot);
4123     return CKR_OK;
4124 }
4125 
4126 /*
4127  * Create or remove a new slot on the fly.
4128  * When creating a slot, "slot" is the slot that the request came from. The
4129  * resulting slot will live in the same module as "slot".
4130  * When removing a slot, "slot" is the slot to be removed.
4131  * "object" is the creation object that specifies the module spec for the slot
4132  * to add or remove.
4133  */
4134 static CK_RV
sftk_CreateNewSlot(SFTKSlot * slot,CK_OBJECT_CLASS class,SFTKObject * object)4135 sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class,
4136                    SFTKObject *object)
4137 {
4138     PRBool isValidUserSlot = PR_FALSE;
4139     PRBool isValidFIPSUserSlot = PR_FALSE;
4140     PRBool isValidSlot = PR_FALSE;
4141     PRBool isFIPS = PR_FALSE;
4142     unsigned long moduleIndex = NSC_NON_FIPS_MODULE;
4143     SFTKAttribute *attribute;
4144     sftk_parameters paramStrings;
4145     char *paramString;
4146     CK_SLOT_ID slotID = 0;
4147     SFTKSlot *newSlot = NULL;
4148     CK_RV crv = CKR_OK;
4149 
4150     if (class != CKO_NETSCAPE_DELSLOT && class != CKO_NETSCAPE_NEWSLOT) {
4151         return CKR_ATTRIBUTE_VALUE_INVALID;
4152     }
4153     if (class == CKO_NETSCAPE_NEWSLOT && slot->slotID == FIPS_SLOT_ID) {
4154         isFIPS = PR_TRUE;
4155     }
4156     attribute = sftk_FindAttribute(object, CKA_NETSCAPE_MODULE_SPEC);
4157     if (attribute == NULL) {
4158         return CKR_TEMPLATE_INCOMPLETE;
4159     }
4160     paramString = (char *)attribute->attrib.pValue;
4161     crv = sftk_parseParameters(paramString, &paramStrings, isFIPS);
4162     if (crv != CKR_OK) {
4163         goto loser;
4164     }
4165 
4166     /* enforce only one at a time */
4167     if (paramStrings.token_count != 1) {
4168         crv = CKR_ATTRIBUTE_VALUE_INVALID;
4169         goto loser;
4170     }
4171 
4172     slotID = paramStrings.tokens[0].slotID;
4173 
4174     /* stay within the valid ID space */
4175     isValidUserSlot = (slotID >= SFTK_MIN_USER_SLOT_ID &&
4176                        slotID <= SFTK_MAX_USER_SLOT_ID);
4177     isValidFIPSUserSlot = (slotID >= SFTK_MIN_FIPS_USER_SLOT_ID &&
4178                            slotID <= SFTK_MAX_FIPS_USER_SLOT_ID);
4179 
4180     if (class == CKO_NETSCAPE_DELSLOT) {
4181         if (slot->slotID == slotID) {
4182             isValidSlot = isValidUserSlot || isValidFIPSUserSlot;
4183         }
4184     } else {
4185         /* only the crypto or FIPS slots can create new slot objects */
4186         if (slot->slotID == NETSCAPE_SLOT_ID) {
4187             isValidSlot = isValidUserSlot;
4188             moduleIndex = NSC_NON_FIPS_MODULE;
4189         } else if (slot->slotID == FIPS_SLOT_ID) {
4190             isValidSlot = isValidFIPSUserSlot;
4191             moduleIndex = NSC_FIPS_MODULE;
4192         }
4193     }
4194 
4195     if (!isValidSlot) {
4196         crv = CKR_ATTRIBUTE_VALUE_INVALID;
4197         goto loser;
4198     }
4199 
4200     /* unload any existing slot at this id */
4201     newSlot = sftk_SlotFromID(slotID, PR_TRUE);
4202     if (newSlot && newSlot->present) {
4203         crv = SFTK_ShutdownSlot(newSlot);
4204         if (crv != CKR_OK) {
4205             goto loser;
4206         }
4207     }
4208 
4209     /* if we were just planning on deleting the slot, then do so now */
4210     if (class == CKO_NETSCAPE_DELSLOT) {
4211         /* sort of a unconventional use of this error code, be we are
4212          * overusing CKR_ATTRIBUTE_VALUE_INVALID, and it does apply */
4213         crv = newSlot ? CKR_OK : CKR_SLOT_ID_INVALID;
4214         goto loser; /* really exit */
4215     }
4216 
4217     if (newSlot) {
4218         crv = SFTK_SlotReInit(newSlot, paramStrings.configdir,
4219                               paramStrings.updatedir, paramStrings.updateID,
4220                               &paramStrings.tokens[0], moduleIndex);
4221     } else {
4222         crv = SFTK_SlotInit(paramStrings.configdir,
4223                             paramStrings.updatedir, paramStrings.updateID,
4224                             &paramStrings.tokens[0], moduleIndex);
4225     }
4226 
4227 loser:
4228     sftk_freeParams(&paramStrings);
4229     sftk_FreeAttribute(attribute);
4230 
4231     return crv;
4232 }
4233 
4234 /* NSC_CreateObject creates a new object. */
4235 CK_RV
NSC_CreateObject(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phObject)4236 NSC_CreateObject(CK_SESSION_HANDLE hSession,
4237                  CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
4238                  CK_OBJECT_HANDLE_PTR phObject)
4239 {
4240     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4241     SFTKSession *session;
4242     SFTKObject *object;
4243     /* make sure class isn't randomly CKO_NETSCAPE_NEWSLOT or
4244      * CKO_NETSCPE_DELSLOT. */
4245     CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED;
4246     CK_RV crv;
4247     int i;
4248 
4249     CHECK_FORK();
4250 
4251     *phObject = CK_INVALID_HANDLE;
4252 
4253     if (slot == NULL) {
4254         return CKR_SESSION_HANDLE_INVALID;
4255     }
4256     /*
4257      * now lets create an object to hang the attributes off of
4258      */
4259     object = sftk_NewObject(slot); /* fill in the handle later */
4260     if (object == NULL) {
4261         return CKR_HOST_MEMORY;
4262     }
4263 
4264     /*
4265      * load the template values into the object
4266      */
4267     for (i = 0; i < (int)ulCount; i++) {
4268         crv = sftk_AddAttributeType(object, sftk_attr_expand(&pTemplate[i]));
4269         if (crv != CKR_OK) {
4270             sftk_FreeObject(object);
4271             return crv;
4272         }
4273         if ((pTemplate[i].type == CKA_CLASS) && pTemplate[i].pValue) {
4274             class = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
4275         }
4276     }
4277 
4278     /* get the session */
4279     session = sftk_SessionFromHandle(hSession);
4280     if (session == NULL) {
4281         sftk_FreeObject(object);
4282         return CKR_SESSION_HANDLE_INVALID;
4283     }
4284 
4285     /*
4286      * handle pseudo objects (CKO_NEWSLOT)
4287      */
4288     if ((class == CKO_NETSCAPE_NEWSLOT) || (class == CKO_NETSCAPE_DELSLOT)) {
4289         crv = sftk_CreateNewSlot(slot, class, object);
4290         goto done;
4291     }
4292 
4293     /*
4294      * handle the base object stuff
4295      */
4296     crv = sftk_handleObject(object, session);
4297     *phObject = object->handle;
4298 done:
4299     sftk_FreeSession(session);
4300     sftk_FreeObject(object);
4301 
4302     return crv;
4303 }
4304 
4305 /* NSC_CopyObject copies an object, creating a new object for the copy. */
4306 CK_RV
NSC_CopyObject(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount,CK_OBJECT_HANDLE_PTR phNewObject)4307 NSC_CopyObject(CK_SESSION_HANDLE hSession,
4308                CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
4309                CK_OBJECT_HANDLE_PTR phNewObject)
4310 {
4311     SFTKObject *destObject, *srcObject;
4312     SFTKSession *session;
4313     CK_RV crv = CKR_OK;
4314     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4315     int i;
4316 
4317     CHECK_FORK();
4318 
4319     if (slot == NULL) {
4320         return CKR_SESSION_HANDLE_INVALID;
4321     }
4322     /* Get srcObject so we can find the class */
4323     session = sftk_SessionFromHandle(hSession);
4324     if (session == NULL) {
4325         return CKR_SESSION_HANDLE_INVALID;
4326     }
4327     srcObject = sftk_ObjectFromHandle(hObject, session);
4328     if (srcObject == NULL) {
4329         sftk_FreeSession(session);
4330         return CKR_OBJECT_HANDLE_INVALID;
4331     }
4332     /*
4333      * create an object to hang the attributes off of
4334      */
4335     destObject = sftk_NewObject(slot); /* fill in the handle later */
4336     if (destObject == NULL) {
4337         sftk_FreeSession(session);
4338         sftk_FreeObject(srcObject);
4339         return CKR_HOST_MEMORY;
4340     }
4341 
4342     /*
4343      * load the template values into the object
4344      */
4345     for (i = 0; i < (int)ulCount; i++) {
4346         if (sftk_modifyType(pTemplate[i].type, srcObject->objclass) == SFTK_NEVER) {
4347             crv = CKR_ATTRIBUTE_READ_ONLY;
4348             break;
4349         }
4350         crv = sftk_AddAttributeType(destObject, sftk_attr_expand(&pTemplate[i]));
4351         if (crv != CKR_OK) {
4352             break;
4353         }
4354     }
4355     if (crv != CKR_OK) {
4356         sftk_FreeSession(session);
4357         sftk_FreeObject(srcObject);
4358         sftk_FreeObject(destObject);
4359         return crv;
4360     }
4361 
4362     /* sensitive can only be changed to CK_TRUE */
4363     if (sftk_hasAttribute(destObject, CKA_SENSITIVE)) {
4364         if (!sftk_isTrue(destObject, CKA_SENSITIVE)) {
4365             sftk_FreeSession(session);
4366             sftk_FreeObject(srcObject);
4367             sftk_FreeObject(destObject);
4368             return CKR_ATTRIBUTE_READ_ONLY;
4369         }
4370     }
4371 
4372     /*
4373      * now copy the old attributes from the new attributes
4374      */
4375     /* don't create a token object if we aren't in a rw session */
4376     /* we need to hold the lock to copy a consistant version of
4377      * the object. */
4378     crv = sftk_CopyObject(destObject, srcObject);
4379 
4380     destObject->objclass = srcObject->objclass;
4381     sftk_FreeObject(srcObject);
4382     if (crv != CKR_OK) {
4383         sftk_FreeObject(destObject);
4384         sftk_FreeSession(session);
4385         return crv;
4386     }
4387 
4388     crv = sftk_handleObject(destObject, session);
4389     *phNewObject = destObject->handle;
4390     sftk_FreeSession(session);
4391     sftk_FreeObject(destObject);
4392 
4393     return crv;
4394 }
4395 
4396 /* NSC_GetObjectSize gets the size of an object in bytes. */
4397 CK_RV
NSC_GetObjectSize(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ULONG_PTR pulSize)4398 NSC_GetObjectSize(CK_SESSION_HANDLE hSession,
4399                   CK_OBJECT_HANDLE hObject, CK_ULONG_PTR pulSize)
4400 {
4401     CHECK_FORK();
4402 
4403     *pulSize = 0;
4404     return CKR_OK;
4405 }
4406 
4407 /* NSC_GetAttributeValue obtains the value of one or more object attributes. */
4408 CK_RV
NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)4409 NSC_GetAttributeValue(CK_SESSION_HANDLE hSession,
4410                       CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
4411 {
4412     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4413     SFTKSession *session;
4414     SFTKObject *object;
4415     SFTKAttribute *attribute;
4416     PRBool sensitive;
4417     CK_RV crv;
4418     int i;
4419 
4420     CHECK_FORK();
4421 
4422     if (slot == NULL) {
4423         return CKR_SESSION_HANDLE_INVALID;
4424     }
4425     /*
4426      * make sure we're allowed
4427      */
4428     session = sftk_SessionFromHandle(hSession);
4429     if (session == NULL) {
4430         return CKR_SESSION_HANDLE_INVALID;
4431     }
4432 
4433     /* short circuit everything for token objects */
4434     if (sftk_isToken(hObject)) {
4435         SFTKSlot *slot = sftk_SlotFromSession(session);
4436         SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, hObject);
4437         SFTKDBHandle *keydb = NULL;
4438 
4439         if (dbHandle == NULL) {
4440             sftk_FreeSession(session);
4441             return CKR_OBJECT_HANDLE_INVALID;
4442         }
4443 
4444         crv = sftkdb_GetAttributeValue(dbHandle, hObject, pTemplate, ulCount);
4445 
4446         /* make sure we don't export any sensitive information */
4447         keydb = sftk_getKeyDB(slot);
4448         if (dbHandle == keydb) {
4449             for (i = 0; i < (int)ulCount; i++) {
4450                 if (sftk_isSensitive(pTemplate[i].type, CKO_PRIVATE_KEY)) {
4451                     crv = CKR_ATTRIBUTE_SENSITIVE;
4452                     if (pTemplate[i].pValue && (pTemplate[i].ulValueLen != -1)) {
4453                         PORT_Memset(pTemplate[i].pValue, 0,
4454                                     pTemplate[i].ulValueLen);
4455                     }
4456                     pTemplate[i].ulValueLen = -1;
4457                 }
4458             }
4459         }
4460 
4461         sftk_FreeSession(session);
4462         sftk_freeDB(dbHandle);
4463         if (keydb) {
4464             sftk_freeDB(keydb);
4465         }
4466         return crv;
4467     }
4468 
4469     /* handle the session object */
4470     object = sftk_ObjectFromHandle(hObject, session);
4471     sftk_FreeSession(session);
4472     if (object == NULL) {
4473         return CKR_OBJECT_HANDLE_INVALID;
4474     }
4475 
4476     /* don't read a private object if we aren't logged in */
4477     if ((!slot->isLoggedIn) && (slot->needLogin) &&
4478         (sftk_isTrue(object, CKA_PRIVATE))) {
4479         sftk_FreeObject(object);
4480         return CKR_USER_NOT_LOGGED_IN;
4481     }
4482 
4483     crv = CKR_OK;
4484     sensitive = sftk_isTrue(object, CKA_SENSITIVE);
4485     for (i = 0; i < (int)ulCount; i++) {
4486         /* Make sure that this attribute is retrievable */
4487         if (sensitive && sftk_isSensitive(pTemplate[i].type, object->objclass)) {
4488             crv = CKR_ATTRIBUTE_SENSITIVE;
4489             pTemplate[i].ulValueLen = -1;
4490             continue;
4491         }
4492         attribute = sftk_FindAttribute(object, pTemplate[i].type);
4493         if (attribute == NULL) {
4494             crv = CKR_ATTRIBUTE_TYPE_INVALID;
4495             pTemplate[i].ulValueLen = -1;
4496             continue;
4497         }
4498         if (pTemplate[i].pValue != NULL) {
4499             PORT_Memcpy(pTemplate[i].pValue, attribute->attrib.pValue,
4500                         attribute->attrib.ulValueLen);
4501         }
4502         pTemplate[i].ulValueLen = attribute->attrib.ulValueLen;
4503         sftk_FreeAttribute(attribute);
4504     }
4505 
4506     sftk_FreeObject(object);
4507     return crv;
4508 }
4509 
4510 /* NSC_SetAttributeValue modifies the value of one or more object attributes */
4511 CK_RV
NSC_SetAttributeValue(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hObject,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)4512 NSC_SetAttributeValue(CK_SESSION_HANDLE hSession,
4513                       CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
4514 {
4515     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4516     SFTKSession *session;
4517     SFTKAttribute *attribute;
4518     SFTKObject *object;
4519     PRBool isToken;
4520     CK_RV crv = CKR_OK;
4521     CK_BBOOL legal;
4522     int i;
4523 
4524     CHECK_FORK();
4525 
4526     if (slot == NULL) {
4527         return CKR_SESSION_HANDLE_INVALID;
4528     }
4529     /*
4530      * make sure we're allowed
4531      */
4532     session = sftk_SessionFromHandle(hSession);
4533     if (session == NULL) {
4534         return CKR_SESSION_HANDLE_INVALID;
4535     }
4536 
4537     object = sftk_ObjectFromHandle(hObject, session);
4538     if (object == NULL) {
4539         sftk_FreeSession(session);
4540         return CKR_OBJECT_HANDLE_INVALID;
4541     }
4542 
4543     /* don't modify a private object if we aren't logged in */
4544     if ((!slot->isLoggedIn) && (slot->needLogin) &&
4545         (sftk_isTrue(object, CKA_PRIVATE))) {
4546         sftk_FreeSession(session);
4547         sftk_FreeObject(object);
4548         return CKR_USER_NOT_LOGGED_IN;
4549     }
4550 
4551     /* don't modify a token object if we aren't in a rw session */
4552     isToken = sftk_isTrue(object, CKA_TOKEN);
4553     if (((session->info.flags & CKF_RW_SESSION) == 0) && isToken) {
4554         sftk_FreeSession(session);
4555         sftk_FreeObject(object);
4556         return CKR_SESSION_READ_ONLY;
4557     }
4558     sftk_FreeSession(session);
4559 
4560     /* only change modifiable objects */
4561     if (!sftk_isTrue(object, CKA_MODIFIABLE)) {
4562         sftk_FreeObject(object);
4563         return CKR_ATTRIBUTE_READ_ONLY;
4564     }
4565 
4566     for (i = 0; i < (int)ulCount; i++) {
4567         /* Make sure that this attribute is changeable */
4568         switch (sftk_modifyType(pTemplate[i].type, object->objclass)) {
4569             case SFTK_NEVER:
4570             case SFTK_ONCOPY:
4571             default:
4572                 crv = CKR_ATTRIBUTE_READ_ONLY;
4573                 break;
4574 
4575             case SFTK_SENSITIVE:
4576                 legal = (pTemplate[i].type == CKA_EXTRACTABLE) ? CK_FALSE : CK_TRUE;
4577                 if ((*(CK_BBOOL *)pTemplate[i].pValue) != legal) {
4578                     crv = CKR_ATTRIBUTE_READ_ONLY;
4579                 }
4580                 break;
4581             case SFTK_ALWAYS:
4582                 break;
4583         }
4584         if (crv != CKR_OK)
4585             break;
4586 
4587         /* find the old attribute */
4588         attribute = sftk_FindAttribute(object, pTemplate[i].type);
4589         if (attribute == NULL) {
4590             crv = CKR_ATTRIBUTE_TYPE_INVALID;
4591             break;
4592         }
4593         sftk_FreeAttribute(attribute);
4594         crv = sftk_forceAttribute(object, sftk_attr_expand(&pTemplate[i]));
4595         if (crv != CKR_OK)
4596             break;
4597     }
4598 
4599     sftk_FreeObject(object);
4600     return crv;
4601 }
4602 
4603 static CK_RV
sftk_expandSearchList(SFTKSearchResults * search,int count)4604 sftk_expandSearchList(SFTKSearchResults *search, int count)
4605 {
4606     search->array_size += count;
4607     search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,
4608                                                        sizeof(CK_OBJECT_HANDLE) * search->array_size);
4609     return search->handles ? CKR_OK : CKR_HOST_MEMORY;
4610 }
4611 
4612 static CK_RV
sftk_searchDatabase(SFTKDBHandle * handle,SFTKSearchResults * search,const CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount)4613 sftk_searchDatabase(SFTKDBHandle *handle, SFTKSearchResults *search,
4614                     const CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
4615 {
4616     CK_RV crv;
4617     int objectListSize = search->array_size - search->size;
4618     CK_OBJECT_HANDLE *array = &search->handles[search->size];
4619     SDBFind *find;
4620     CK_ULONG count;
4621 
4622     crv = sftkdb_FindObjectsInit(handle, pTemplate, ulCount, &find);
4623     if (crv != CKR_OK)
4624         return crv;
4625     do {
4626         crv = sftkdb_FindObjects(handle, find, array, objectListSize, &count);
4627         if ((crv != CKR_OK) || (count == 0))
4628             break;
4629         search->size += count;
4630         objectListSize -= count;
4631         if (objectListSize > 0)
4632             break;
4633         crv = sftk_expandSearchList(search, NSC_SEARCH_BLOCK_SIZE);
4634         objectListSize = NSC_SEARCH_BLOCK_SIZE;
4635         array = &search->handles[search->size];
4636     } while (crv == CKR_OK);
4637     sftkdb_FindObjectsFinal(handle, find);
4638 
4639     return crv;
4640 }
4641 
4642 /* softoken used to search the SMimeEntries automatically instead of
4643  * doing this in pk11wrap. This code should really be up in
4644  * pk11wrap so that it will work with other tokens other than softoken.
4645  */
4646 CK_RV
sftk_emailhack(SFTKSlot * slot,SFTKDBHandle * handle,SFTKSearchResults * search,CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount)4647 sftk_emailhack(SFTKSlot *slot, SFTKDBHandle *handle,
4648                SFTKSearchResults *search, CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount)
4649 {
4650     PRBool isCert = PR_FALSE;
4651     int emailIndex = -1;
4652     unsigned int i;
4653     SFTKSearchResults smime_search;
4654     CK_ATTRIBUTE smime_template[2];
4655     CK_OBJECT_CLASS smime_class = CKO_NETSCAPE_SMIME;
4656     SFTKAttribute *attribute = NULL;
4657     SFTKObject *object = NULL;
4658     CK_RV crv = CKR_OK;
4659 
4660     smime_search.handles = NULL; /* paranoia, some one is bound to add a goto
4661                                   * loser before this gets initialized */
4662 
4663     /* see if we are looking for email certs */
4664     for (i = 0; i < ulCount; i++) {
4665         if (pTemplate[i].type == CKA_CLASS) {
4666             if ((pTemplate[i].ulValueLen != sizeof(CK_OBJECT_CLASS) ||
4667                  (*(CK_OBJECT_CLASS *)pTemplate[i].pValue) != CKO_CERTIFICATE)) {
4668                 /* not a cert, skip out */
4669                 break;
4670             }
4671             isCert = PR_TRUE;
4672         } else if (pTemplate[i].type == CKA_NETSCAPE_EMAIL) {
4673             emailIndex = i;
4674         }
4675         if (isCert && (emailIndex != -1))
4676             break;
4677     }
4678 
4679     if (!isCert || (emailIndex == -1)) {
4680         return CKR_OK;
4681     }
4682 
4683     /* we are doing a cert and email search, find the SMimeEntry */
4684     smime_template[0].type = CKA_CLASS;
4685     smime_template[0].pValue = &smime_class;
4686     smime_template[0].ulValueLen = sizeof(smime_class);
4687     smime_template[1] = pTemplate[emailIndex];
4688 
4689     smime_search.handles = (CK_OBJECT_HANDLE *)
4690         PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
4691     if (smime_search.handles == NULL) {
4692         crv = CKR_HOST_MEMORY;
4693         goto loser;
4694     }
4695     smime_search.index = 0;
4696     smime_search.size = 0;
4697     smime_search.array_size = NSC_SEARCH_BLOCK_SIZE;
4698 
4699     crv = sftk_searchDatabase(handle, &smime_search, smime_template, 2);
4700     if (crv != CKR_OK || smime_search.size == 0) {
4701         goto loser;
4702     }
4703 
4704     /* get the SMime subject */
4705     object = sftk_NewTokenObject(slot, NULL, smime_search.handles[0]);
4706     if (object == NULL) {
4707         crv = CKR_HOST_MEMORY; /* is there any other reason for this failure? */
4708         goto loser;
4709     }
4710     attribute = sftk_FindAttribute(object, CKA_SUBJECT);
4711     if (attribute == NULL) {
4712         crv = CKR_ATTRIBUTE_TYPE_INVALID;
4713         goto loser;
4714     }
4715 
4716     /* now find the certs with that subject */
4717     pTemplate[emailIndex] = attribute->attrib;
4718     /* now add the appropriate certs to the search list */
4719     crv = sftk_searchDatabase(handle, search, pTemplate, ulCount);
4720     pTemplate[emailIndex] = smime_template[1]; /* restore the user's template*/
4721 
4722 loser:
4723     if (attribute) {
4724         sftk_FreeAttribute(attribute);
4725     }
4726     if (object) {
4727         sftk_FreeObject(object);
4728     }
4729     if (smime_search.handles) {
4730         PORT_Free(smime_search.handles);
4731     }
4732 
4733     return crv;
4734 }
4735 
4736 static void
sftk_pruneSearch(CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount,PRBool * searchCertDB,PRBool * searchKeyDB)4737 sftk_pruneSearch(CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
4738                  PRBool *searchCertDB, PRBool *searchKeyDB)
4739 {
4740     CK_ULONG i;
4741 
4742     *searchCertDB = PR_TRUE;
4743     *searchKeyDB = PR_TRUE;
4744     for (i = 0; i < ulCount; i++) {
4745         if (pTemplate[i].type == CKA_CLASS && pTemplate[i].pValue != NULL) {
4746             CK_OBJECT_CLASS class = *((CK_OBJECT_CLASS *)pTemplate[i].pValue);
4747             if (class == CKO_PRIVATE_KEY || class == CKO_SECRET_KEY) {
4748                 *searchCertDB = PR_FALSE;
4749             } else {
4750                 *searchKeyDB = PR_FALSE;
4751             }
4752             break;
4753         }
4754     }
4755 }
4756 
4757 static CK_RV
sftk_searchTokenList(SFTKSlot * slot,SFTKSearchResults * search,CK_ATTRIBUTE * pTemplate,CK_ULONG ulCount,PRBool * tokenOnly,PRBool isLoggedIn)4758 sftk_searchTokenList(SFTKSlot *slot, SFTKSearchResults *search,
4759                      CK_ATTRIBUTE *pTemplate, CK_ULONG ulCount,
4760                      PRBool *tokenOnly, PRBool isLoggedIn)
4761 {
4762     CK_RV crv = CKR_OK;
4763     CK_RV crv2;
4764     PRBool searchCertDB;
4765     PRBool searchKeyDB;
4766 
4767     sftk_pruneSearch(pTemplate, ulCount, &searchCertDB, &searchKeyDB);
4768 
4769     if (searchCertDB) {
4770         SFTKDBHandle *certHandle = sftk_getCertDB(slot);
4771         crv = sftk_searchDatabase(certHandle, search, pTemplate, ulCount);
4772         crv2 = sftk_emailhack(slot, certHandle, search, pTemplate, ulCount);
4773         if (crv == CKR_OK)
4774             crv = crv2;
4775         sftk_freeDB(certHandle);
4776     }
4777 
4778     if (crv == CKR_OK && isLoggedIn && searchKeyDB) {
4779         SFTKDBHandle *keyHandle = sftk_getKeyDB(slot);
4780         crv = sftk_searchDatabase(keyHandle, search, pTemplate, ulCount);
4781         sftk_freeDB(keyHandle);
4782     }
4783     return crv;
4784 }
4785 
4786 /* NSC_FindObjectsInit initializes a search for token and session objects
4787  * that match a template. */
4788 CK_RV
NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulCount)4789 NSC_FindObjectsInit(CK_SESSION_HANDLE hSession,
4790                     CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
4791 {
4792     SFTKSearchResults *search = NULL, *freeSearch = NULL;
4793     SFTKSession *session = NULL;
4794     SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession);
4795     PRBool tokenOnly = PR_FALSE;
4796     CK_RV crv = CKR_OK;
4797     PRBool isLoggedIn;
4798 
4799     CHECK_FORK();
4800 
4801     if (slot == NULL) {
4802         return CKR_SESSION_HANDLE_INVALID;
4803     }
4804     session = sftk_SessionFromHandle(hSession);
4805     if (session == NULL) {
4806         crv = CKR_SESSION_HANDLE_INVALID;
4807         goto loser;
4808     }
4809 
4810     search = (SFTKSearchResults *)PORT_Alloc(sizeof(SFTKSearchResults));
4811     if (search == NULL) {
4812         crv = CKR_HOST_MEMORY;
4813         goto loser;
4814     }
4815     search->handles = (CK_OBJECT_HANDLE *)
4816         PORT_Alloc(sizeof(CK_OBJECT_HANDLE) * NSC_SEARCH_BLOCK_SIZE);
4817     if (search->handles == NULL) {
4818         crv = CKR_HOST_MEMORY;
4819         goto loser;
4820     }
4821     search->index = 0;
4822     search->size = 0;
4823     search->array_size = NSC_SEARCH_BLOCK_SIZE;
4824     isLoggedIn = (PRBool)((!slot->needLogin) || slot->isLoggedIn);
4825 
4826     crv = sftk_searchTokenList(slot, search, pTemplate, ulCount, &tokenOnly,
4827                                isLoggedIn);
4828     if (crv != CKR_OK) {
4829         goto loser;
4830     }
4831 
4832     /* build list of found objects in the session */
4833     if (!tokenOnly) {
4834         crv = sftk_searchObjectList(search, slot->sessObjHashTable,
4835                                     slot->sessObjHashSize, slot->objectLock,
4836                                     pTemplate, ulCount, isLoggedIn);
4837     }
4838     if (crv != CKR_OK) {
4839         goto loser;
4840     }
4841 
4842     if ((freeSearch = session->search) != NULL) {
4843         session->search = NULL;
4844         sftk_FreeSearch(freeSearch);
4845     }
4846     session->search = search;
4847     sftk_FreeSession(session);
4848     return CKR_OK;
4849 
4850 loser:
4851     if (search) {
4852         sftk_FreeSearch(search);
4853     }
4854     if (session) {
4855         sftk_FreeSession(session);
4856     }
4857     return crv;
4858 }
4859 
4860 /* NSC_FindObjects continues a search for token and session objects
4861  * that match a template, obtaining additional object handles. */
4862 CK_RV
NSC_FindObjects(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE_PTR phObject,CK_ULONG ulMaxObjectCount,CK_ULONG_PTR pulObjectCount)4863 NSC_FindObjects(CK_SESSION_HANDLE hSession,
4864                 CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount,
4865                 CK_ULONG_PTR pulObjectCount)
4866 {
4867     SFTKSession *session;
4868     SFTKSearchResults *search;
4869     int transfer;
4870     int left;
4871 
4872     CHECK_FORK();
4873 
4874     *pulObjectCount = 0;
4875     session = sftk_SessionFromHandle(hSession);
4876     if (session == NULL)
4877         return CKR_SESSION_HANDLE_INVALID;
4878     if (session->search == NULL) {
4879         sftk_FreeSession(session);
4880         return CKR_OK;
4881     }
4882     search = session->search;
4883     left = session->search->size - session->search->index;
4884     transfer = ((int)ulMaxObjectCount > left) ? left : ulMaxObjectCount;
4885     if (transfer > 0) {
4886         PORT_Memcpy(phObject, &search->handles[search->index],
4887                     transfer * sizeof(CK_OBJECT_HANDLE));
4888     } else {
4889         *phObject = CK_INVALID_HANDLE;
4890     }
4891 
4892     search->index += transfer;
4893     if (search->index == search->size) {
4894         session->search = NULL;
4895         sftk_FreeSearch(search);
4896     }
4897     *pulObjectCount = transfer;
4898     sftk_FreeSession(session);
4899     return CKR_OK;
4900 }
4901 
4902 /* NSC_FindObjectsFinal finishes a search for token and session objects. */
4903 CK_RV
NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)4904 NSC_FindObjectsFinal(CK_SESSION_HANDLE hSession)
4905 {
4906     SFTKSession *session;
4907     SFTKSearchResults *search;
4908 
4909     CHECK_FORK();
4910 
4911     session = sftk_SessionFromHandle(hSession);
4912     if (session == NULL)
4913         return CKR_SESSION_HANDLE_INVALID;
4914     search = session->search;
4915     session->search = NULL;
4916     sftk_FreeSession(session);
4917     if (search != NULL) {
4918         sftk_FreeSearch(search);
4919     }
4920     return CKR_OK;
4921 }
4922 
4923 CK_RV
NSC_WaitForSlotEvent(CK_FLAGS flags,CK_SLOT_ID_PTR pSlot,CK_VOID_PTR pReserved)4924 NSC_WaitForSlotEvent(CK_FLAGS flags, CK_SLOT_ID_PTR pSlot,
4925                      CK_VOID_PTR pReserved)
4926 {
4927     CHECK_FORK();
4928 
4929     return CKR_FUNCTION_NOT_SUPPORTED;
4930 }
4931