Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(132)

Side by Side Diff: mozilla/security/nss/lib/softoken/pkcs11.c

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

Powered by Google App Engine
This is Rietveld 408576698