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