/src/nss/lib/softoken/pkcs11u.c
Line  | Count  | Source (jump to first uncovered line)  | 
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  |  |  * Internal PKCS #11 functions. Should only be called by pkcs11.c  | 
6  |  |  */  | 
7  |  | #include "pkcs11.h"  | 
8  |  | #include "pkcs11i.h"  | 
9  |  | #include "lowkeyi.h"  | 
10  |  | #include "secasn1.h"  | 
11  |  | #include "blapi.h"  | 
12  |  | #include "secerr.h"  | 
13  |  | #include "prnetdb.h" /* for PR_ntohl */  | 
14  |  | #include "sftkdb.h"  | 
15  |  | #include "softoken.h"  | 
16  |  | #include "secoid.h"  | 
17  |  | #include "softkver.h"  | 
18  |  |  | 
19  |  | #if !defined(NSS_FIPS_DISABLED) && defined(NSS_ENABLE_FIPS_INDICATORS)  | 
20  |  | /* this file should be supplied by the vendor and include all the  | 
21  |  |  * algorithms which have Algorithm certs and have been reviewed by  | 
22  |  |  * the lab. A blank file is included for the base so that FIPS mode  | 
23  |  |  * will still be compiled and run, but FIPS indicators will always  | 
24  |  |  * return PR_FALSE  | 
25  |  |  */  | 
26  |  | #include "fips_algorithms.h"  | 
27  |  | #define NSS_HAS_FIPS_INDICATORS 1  | 
28  |  | #endif  | 
29  |  |  | 
30  |  | /*  | 
31  |  |  * ******************** Error mapping *******************************  | 
32  |  |  */  | 
33  |  | /*  | 
34  |  |  * map all the SEC_ERROR_xxx error codes that may be returned by freebl  | 
35  |  |  * functions to CKR_xxx.  return CKR_DEVICE_ERROR by default for backward  | 
36  |  |  * compatibility.  | 
37  |  |  */  | 
38  |  | CK_RV  | 
39  |  | sftk_MapCryptError(int error)  | 
40  | 63  | { | 
41  | 63  |     switch (error) { | 
42  | 14  |         case SEC_ERROR_INVALID_ARGS:  | 
43  | 14  |         case SEC_ERROR_BAD_DATA: /* MP_RANGE gets mapped to this */  | 
44  | 14  |             return CKR_ARGUMENTS_BAD;  | 
45  | 0  |         case SEC_ERROR_INPUT_LEN:  | 
46  | 0  |             return CKR_DATA_LEN_RANGE;  | 
47  | 0  |         case SEC_ERROR_OUTPUT_LEN:  | 
48  | 0  |             return CKR_BUFFER_TOO_SMALL;  | 
49  | 0  |         case SEC_ERROR_LIBRARY_FAILURE:  | 
50  | 0  |             return CKR_GENERAL_ERROR;  | 
51  | 0  |         case SEC_ERROR_NO_MEMORY:  | 
52  | 0  |             return CKR_HOST_MEMORY;  | 
53  | 0  |         case SEC_ERROR_BAD_SIGNATURE:  | 
54  | 0  |             return CKR_SIGNATURE_INVALID;  | 
55  | 0  |         case SEC_ERROR_INVALID_KEY:  | 
56  | 0  |             return CKR_KEY_SIZE_RANGE;  | 
57  | 5  |         case SEC_ERROR_BAD_KEY:        /* an EC public key that fails validation */  | 
58  | 5  |             return CKR_KEY_SIZE_RANGE; /* the closest error code */  | 
59  | 0  |         case SEC_ERROR_UNSUPPORTED_EC_POINT_FORM:  | 
60  | 0  |             return CKR_TEMPLATE_INCONSISTENT;  | 
61  | 0  |         case SEC_ERROR_UNSUPPORTED_KEYALG:  | 
62  | 0  |             return CKR_MECHANISM_INVALID;  | 
63  | 44  |         case SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE:  | 
64  | 44  |             return CKR_DOMAIN_PARAMS_INVALID;  | 
65  |  |         /* key pair generation failed after max number of attempts */  | 
66  | 0  |         case SEC_ERROR_NEED_RANDOM:  | 
67  | 0  |             return CKR_FUNCTION_FAILED;  | 
68  | 63  |     }  | 
69  | 0  |     return CKR_DEVICE_ERROR;  | 
70  | 63  | }  | 
71  |  |  | 
72  |  | /*  | 
73  |  |  * functions which adjust the mapping based on different contexts  | 
74  |  |  * (Decrypt or Verify).  | 
75  |  |  */  | 
76  |  |  | 
77  |  | /* used by Decrypt and UnwrapKey (indirectly) and Decrypt message */  | 
78  |  | CK_RV  | 
79  |  | sftk_MapDecryptError(int error)  | 
80  | 8.85k  | { | 
81  | 8.85k  |     switch (error) { | 
82  |  |         /* usually a padding error, or aead tag mismatch */  | 
83  | 8.84k  |         case SEC_ERROR_BAD_DATA:  | 
84  | 8.84k  |             return CKR_ENCRYPTED_DATA_INVALID;  | 
85  | 14  |         default:  | 
86  | 14  |             return sftk_MapCryptError(error);  | 
87  | 8.85k  |     }  | 
88  | 8.85k  | }  | 
89  |  |  | 
90  |  | /*  | 
91  |  |  * return CKR_SIGNATURE_INVALID instead of CKR_DEVICE_ERROR by default for  | 
92  |  |  * backward compatibilty.  | 
93  |  |  */  | 
94  |  | CK_RV  | 
95  |  | sftk_MapVerifyError(int error)  | 
96  | 0  | { | 
97  | 0  |     CK_RV crv = sftk_MapCryptError(error);  | 
98  | 0  |     if (crv == CKR_DEVICE_ERROR)  | 
99  | 0  |         crv = CKR_SIGNATURE_INVALID;  | 
100  | 0  |     return crv;  | 
101  | 0  | }  | 
102  |  |  | 
103  |  | /*  | 
104  |  |  * ******************** Attribute Utilities *******************************  | 
105  |  |  */  | 
106  |  |  | 
107  |  | /*  | 
108  |  |  * create a new attribute with type, value, and length. Space is allocated  | 
109  |  |  * to hold value.  | 
110  |  |  */  | 
111  |  | static SFTKAttribute *  | 
112  |  | sftk_NewAttribute(SFTKObject *object,  | 
113  |  |                   CK_ATTRIBUTE_TYPE type, const void *value, CK_ULONG len)  | 
114  | 271k  | { | 
115  | 271k  |     SFTKAttribute *attribute;  | 
116  |  |  | 
117  | 271k  |     SFTKSessionObject *so = sftk_narrowToSessionObject(object);  | 
118  | 271k  |     int index;  | 
119  |  |  | 
120  | 271k  |     if (so == NULL) { | 
121  |  |         /* allocate new attribute in a buffer */  | 
122  | 0  |         PORT_Assert(0);  | 
123  | 0  |         return NULL;  | 
124  | 0  |     }  | 
125  |  |     /*  | 
126  |  |      * We attempt to keep down contention on Malloc and Arena locks by  | 
127  |  |      * limiting the number of these calls on high traversed paths. This  | 
128  |  |      * is done for attributes by 'allocating' them from a pool already  | 
129  |  |      * allocated by the parent object.  | 
130  |  |      */  | 
131  | 271k  |     PZ_Lock(so->attributeLock);  | 
132  | 271k  |     index = so->nextAttr++;  | 
133  | 271k  |     PZ_Unlock(so->attributeLock);  | 
134  | 271k  |     PORT_Assert(index < MAX_OBJS_ATTRS);  | 
135  | 271k  |     if (index >= MAX_OBJS_ATTRS)  | 
136  | 0  |         return NULL;  | 
137  |  |  | 
138  | 271k  |     attribute = &so->attrList[index];  | 
139  | 271k  |     attribute->attrib.type = type;  | 
140  | 271k  |     attribute->freeAttr = PR_FALSE;  | 
141  | 271k  |     attribute->freeData = PR_FALSE;  | 
142  | 271k  |     if (value) { | 
143  | 217k  |         if (len <= ATTR_SPACE) { | 
144  | 210k  |             attribute->attrib.pValue = attribute->space;  | 
145  | 210k  |         } else { | 
146  | 7.06k  |             attribute->attrib.pValue = PORT_Alloc(len);  | 
147  | 7.06k  |             attribute->freeData = PR_TRUE;  | 
148  | 7.06k  |         }  | 
149  | 217k  |         if (attribute->attrib.pValue == NULL) { | 
150  | 0  |             return NULL;  | 
151  | 0  |         }  | 
152  | 217k  |         PORT_Memcpy(attribute->attrib.pValue, value, len);  | 
153  | 217k  |         attribute->attrib.ulValueLen = len;  | 
154  | 217k  |     } else { | 
155  | 53.6k  |         attribute->attrib.pValue = NULL;  | 
156  | 53.6k  |         attribute->attrib.ulValueLen = 0;  | 
157  | 53.6k  |     }  | 
158  | 271k  |     attribute->attrib.type = type;  | 
159  | 271k  |     attribute->handle = type;  | 
160  | 271k  |     attribute->next = attribute->prev = NULL;  | 
161  | 271k  |     return attribute;  | 
162  | 271k  | }  | 
163  |  |  | 
164  |  | /*  | 
165  |  |  * Free up all the memory associated with an attribute. Reference count  | 
166  |  |  * must be zero to call this.  | 
167  |  |  */  | 
168  |  | static void  | 
169  |  | sftk_DestroyAttribute(SFTKAttribute *attribute)  | 
170  | 0  | { | 
171  | 0  |     if (attribute->attrib.pValue) { | 
172  |  |         /* clear out the data in the attribute value... it may have been  | 
173  |  |          * sensitive data */  | 
174  | 0  |         PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen);  | 
175  | 0  |         if (attribute->freeData) { | 
176  | 0  |             PORT_Free(attribute->attrib.pValue);  | 
177  | 0  |             attribute->attrib.pValue = NULL;  | 
178  | 0  |             attribute->freeData = PR_FALSE;  | 
179  | 0  |         }  | 
180  | 0  |     }  | 
181  | 0  |     if (attribute->freeAttr) { | 
182  | 0  |         PORT_Free(attribute);  | 
183  | 0  |     }  | 
184  | 0  | }  | 
185  |  |  | 
186  |  | /*  | 
187  |  |  * release a reference to an attribute structure  | 
188  |  |  */  | 
189  |  | void  | 
190  |  | sftk_FreeAttribute(SFTKAttribute *attribute)  | 
191  | 199k  | { | 
192  | 199k  |     if (attribute && attribute->freeAttr) { | 
193  | 0  |         sftk_DestroyAttribute(attribute);  | 
194  | 0  |         return;  | 
195  | 0  |     }  | 
196  | 199k  | }  | 
197  |  |  | 
198  |  | static SFTKAttribute *  | 
199  |  | sftk_FindTokenAttribute(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)  | 
200  | 0  | { | 
201  | 0  |     SFTKAttribute *myattribute = NULL;  | 
202  | 0  |     SFTKDBHandle *dbHandle = NULL;  | 
203  | 0  |     CK_RV crv = CKR_HOST_MEMORY;  | 
204  |  | 
  | 
205  | 0  |     myattribute = (SFTKAttribute *)PORT_Alloc(sizeof(SFTKAttribute));  | 
206  | 0  |     if (myattribute == NULL) { | 
207  | 0  |         goto loser;  | 
208  | 0  |     }  | 
209  |  |  | 
210  | 0  |     dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);  | 
211  |  | 
  | 
212  | 0  |     myattribute->handle = type;  | 
213  | 0  |     myattribute->attrib.type = type;  | 
214  | 0  |     myattribute->attrib.pValue = myattribute->space;  | 
215  | 0  |     myattribute->attrib.ulValueLen = ATTR_SPACE;  | 
216  | 0  |     myattribute->next = myattribute->prev = NULL;  | 
217  | 0  |     myattribute->freeAttr = PR_TRUE;  | 
218  | 0  |     myattribute->freeData = PR_FALSE;  | 
219  |  | 
  | 
220  | 0  |     crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,  | 
221  | 0  |                                    &myattribute->attrib, 1);  | 
222  |  |  | 
223  |  |     /* attribute is bigger than our attribute space buffer, malloc it */  | 
224  | 0  |     if (crv == CKR_BUFFER_TOO_SMALL) { | 
225  | 0  |         myattribute->attrib.pValue = NULL;  | 
226  | 0  |         crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,  | 
227  | 0  |                                        &myattribute->attrib, 1);  | 
228  | 0  |         if (crv != CKR_OK) { | 
229  | 0  |             goto loser;  | 
230  | 0  |         }  | 
231  | 0  |         myattribute->attrib.pValue = PORT_Alloc(myattribute->attrib.ulValueLen);  | 
232  | 0  |         if (myattribute->attrib.pValue == NULL) { | 
233  | 0  |             crv = CKR_HOST_MEMORY;  | 
234  | 0  |             goto loser;  | 
235  | 0  |         }  | 
236  | 0  |         myattribute->freeData = PR_TRUE;  | 
237  | 0  |         crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle,  | 
238  | 0  |                                        &myattribute->attrib, 1);  | 
239  | 0  |     }  | 
240  | 0  | loser:  | 
241  | 0  |     if (dbHandle) { | 
242  | 0  |         sftk_freeDB(dbHandle);  | 
243  | 0  |     }  | 
244  | 0  |     if (crv != CKR_OK) { | 
245  | 0  |         if (myattribute) { | 
246  | 0  |             myattribute->attrib.ulValueLen = 0;  | 
247  | 0  |             sftk_FreeAttribute(myattribute);  | 
248  | 0  |             myattribute = NULL;  | 
249  | 0  |         }  | 
250  | 0  |     }  | 
251  | 0  |     return myattribute;  | 
252  | 0  | }  | 
253  |  |  | 
254  |  | /*  | 
255  |  |  * look up and attribute structure from a type and Object structure.  | 
256  |  |  * The returned attribute is referenced and needs to be freed when  | 
257  |  |  * it is no longer needed.  | 
258  |  |  */  | 
259  |  | SFTKAttribute *  | 
260  |  | sftk_FindAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)  | 
261  | 276k  | { | 
262  | 276k  |     SFTKAttribute *attribute;  | 
263  | 276k  |     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);  | 
264  |  |  | 
265  | 276k  |     if (sessObject == NULL) { | 
266  | 0  |         return sftk_FindTokenAttribute(sftk_narrowToTokenObject(object), type);  | 
267  | 0  |     }  | 
268  |  |  | 
269  | 276k  |     PZ_Lock(sessObject->attributeLock);  | 
270  | 276k  |     sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize);  | 
271  | 276k  |     PZ_Unlock(sessObject->attributeLock);  | 
272  |  |  | 
273  | 276k  |     return (attribute);  | 
274  | 276k  | }  | 
275  |  |  | 
276  |  | /*  | 
277  |  |  * Take a buffer and it's length and return it's true size in bits;  | 
278  |  |  */  | 
279  |  | unsigned int  | 
280  |  | sftk_GetLengthInBits(unsigned char *buf, unsigned int bufLen)  | 
281  | 3.36k  | { | 
282  | 3.36k  |     unsigned int size = bufLen * 8;  | 
283  | 3.36k  |     unsigned int i;  | 
284  |  |  | 
285  |  |     /* Get the real length in bytes */  | 
286  | 3.36k  |     for (i = 0; i < bufLen; i++) { | 
287  | 3.36k  |         unsigned char c = *buf++;  | 
288  | 3.36k  |         if (c != 0) { | 
289  | 3.36k  |             unsigned char m;  | 
290  | 12.0k  |             for (m = 0x80; m > 0; m = m >> 1) { | 
291  | 12.0k  |                 if ((c & m) != 0) { | 
292  | 3.36k  |                     break;  | 
293  | 3.36k  |                 }  | 
294  | 8.71k  |                 size--;  | 
295  | 8.71k  |             }  | 
296  | 3.36k  |             break;  | 
297  | 3.36k  |         }  | 
298  | 0  |         size -= 8;  | 
299  | 0  |     }  | 
300  | 3.36k  |     return size;  | 
301  | 3.36k  | }  | 
302  |  |  | 
303  |  | /*  | 
304  |  |  * Constrain a big num attribute. to size and padding  | 
305  |  |  * minLength means length of the object must be greater than equal to minLength  | 
306  |  |  * maxLength means length of the object must be less than equal to maxLength  | 
307  |  |  * minMultiple means that object length mod minMultiple must equal 0.  | 
308  |  |  * all input sizes are in bits.  | 
309  |  |  * if any constraint is '0' that constraint is not checked.  | 
310  |  |  */  | 
311  |  | CK_RV  | 
312  |  | sftk_ConstrainAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,  | 
313  |  |                         int minLength, int maxLength, int minMultiple)  | 
314  | 2.01k  | { | 
315  | 2.01k  |     SFTKAttribute *attribute;  | 
316  | 2.01k  |     int size;  | 
317  | 2.01k  |     unsigned char *ptr;  | 
318  |  |  | 
319  | 2.01k  |     attribute = sftk_FindAttribute(object, type);  | 
320  | 2.01k  |     if (!attribute) { | 
321  | 0  |         return CKR_TEMPLATE_INCOMPLETE;  | 
322  | 0  |     }  | 
323  | 2.01k  |     ptr = (unsigned char *)attribute->attrib.pValue;  | 
324  | 2.01k  |     if (ptr == NULL) { | 
325  | 0  |         sftk_FreeAttribute(attribute);  | 
326  | 0  |         return CKR_ATTRIBUTE_VALUE_INVALID;  | 
327  | 0  |     }  | 
328  | 2.01k  |     size = sftk_GetLengthInBits(ptr, attribute->attrib.ulValueLen);  | 
329  | 2.01k  |     sftk_FreeAttribute(attribute);  | 
330  |  |  | 
331  | 2.01k  |     if ((minLength != 0) && (size < minLength)) { | 
332  | 0  |         return CKR_ATTRIBUTE_VALUE_INVALID;  | 
333  | 0  |     }  | 
334  | 2.01k  |     if ((maxLength != 0) && (size > maxLength)) { | 
335  | 0  |         return CKR_ATTRIBUTE_VALUE_INVALID;  | 
336  | 0  |     }  | 
337  | 2.01k  |     if ((minMultiple != 0) && ((size % minMultiple) != 0)) { | 
338  | 0  |         return CKR_ATTRIBUTE_VALUE_INVALID;  | 
339  | 0  |     }  | 
340  | 2.01k  |     return CKR_OK;  | 
341  | 2.01k  | }  | 
342  |  |  | 
343  |  | PRBool  | 
344  |  | sftk_hasAttributeToken(SFTKTokenObject *object, CK_ATTRIBUTE_TYPE type)  | 
345  | 0  | { | 
346  | 0  |     CK_ATTRIBUTE template;  | 
347  | 0  |     CK_RV crv;  | 
348  | 0  |     SFTKDBHandle *dbHandle;  | 
349  |  | 
  | 
350  | 0  |     dbHandle = sftk_getDBForTokenObject(object->obj.slot, object->obj.handle);  | 
351  | 0  |     template.type = type;  | 
352  | 0  |     template.pValue = NULL;  | 
353  | 0  |     template.ulValueLen = 0;  | 
354  |  | 
  | 
355  | 0  |     crv = sftkdb_GetAttributeValue(dbHandle, object->obj.handle, &template, 1);  | 
356  | 0  |     sftk_freeDB(dbHandle);  | 
357  |  |  | 
358  |  |     /* attribute is bigger than our attribute space buffer, malloc it */  | 
359  | 0  |     return (crv == CKR_OK) ? PR_TRUE : PR_FALSE;  | 
360  | 0  | }  | 
361  |  |  | 
362  |  | /*  | 
363  |  |  * return true if object has attribute  | 
364  |  |  */  | 
365  |  | PRBool  | 
366  |  | sftk_hasAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)  | 
367  | 225k  | { | 
368  | 225k  |     SFTKAttribute *attribute;  | 
369  | 225k  |     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);  | 
370  |  |  | 
371  | 225k  |     if (sessObject == NULL) { | 
372  | 0  |         return sftk_hasAttributeToken(sftk_narrowToTokenObject(object), type);  | 
373  | 0  |     }  | 
374  |  |  | 
375  | 225k  |     PZ_Lock(sessObject->attributeLock);  | 
376  | 225k  |     sftkqueue_find(attribute, type, sessObject->head, sessObject->hashSize);  | 
377  | 225k  |     PZ_Unlock(sessObject->attributeLock);  | 
378  |  |  | 
379  | 225k  |     return (PRBool)(attribute != NULL);  | 
380  | 225k  | }  | 
381  |  |  | 
382  |  | /*  | 
383  |  |  * add an attribute to an object  | 
384  |  |  */  | 
385  |  | static void  | 
386  |  | sftk_AddAttribute(SFTKObject *object, SFTKAttribute *attribute)  | 
387  | 271k  | { | 
388  | 271k  |     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);  | 
389  |  |  | 
390  | 271k  |     if (sessObject == NULL)  | 
391  | 0  |         return;  | 
392  | 271k  |     PZ_Lock(sessObject->attributeLock);  | 
393  | 271k  |     sftkqueue_add(attribute, attribute->handle,  | 
394  | 271k  |                   sessObject->head, sessObject->hashSize);  | 
395  | 271k  |     PZ_Unlock(sessObject->attributeLock);  | 
396  | 271k  | }  | 
397  |  |  | 
398  |  | /*  | 
399  |  |  * copy an unsigned attribute into a SECItem. Secitem is allocated in  | 
400  |  |  * the specified arena.  | 
401  |  |  */  | 
402  |  | CK_RV  | 
403  |  | sftk_Attribute2SSecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object,  | 
404  |  |                         CK_ATTRIBUTE_TYPE type)  | 
405  | 11.9k  | { | 
406  | 11.9k  |     SFTKAttribute *attribute;  | 
407  |  |  | 
408  | 11.9k  |     item->data = NULL;  | 
409  |  |  | 
410  | 11.9k  |     attribute = sftk_FindAttribute(object, type);  | 
411  | 11.9k  |     if (attribute == NULL)  | 
412  | 0  |         return CKR_TEMPLATE_INCOMPLETE;  | 
413  |  |  | 
414  | 11.9k  |     (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);  | 
415  | 11.9k  |     if (item->data == NULL) { | 
416  | 0  |         sftk_FreeAttribute(attribute);  | 
417  | 0  |         return CKR_HOST_MEMORY;  | 
418  | 0  |     }  | 
419  | 11.9k  |     PORT_Memcpy(item->data, attribute->attrib.pValue, item->len);  | 
420  | 11.9k  |     sftk_FreeAttribute(attribute);  | 
421  | 11.9k  |     return CKR_OK;  | 
422  | 11.9k  | }  | 
423  |  |  | 
424  |  | /*  | 
425  |  |  * fetch multiple attributes into  SECItems. Secitem data is allocated in  | 
426  |  |  * the specified arena.  | 
427  |  |  */  | 
428  |  | CK_RV  | 
429  |  | sftk_MultipleAttribute2SecItem(PLArenaPool *arena, SFTKObject *object,  | 
430  |  |                                SFTKItemTemplate *itemTemplate, int itemTemplateCount)  | 
431  | 676  | { | 
432  |  |  | 
433  | 676  |     CK_RV crv = CKR_OK;  | 
434  | 676  |     CK_ATTRIBUTE templateSpace[SFTK_MAX_ITEM_TEMPLATE];  | 
435  | 676  |     CK_ATTRIBUTE *template;  | 
436  | 676  |     SFTKTokenObject *tokObject;  | 
437  | 676  |     SFTKDBHandle *dbHandle = NULL;  | 
438  | 676  |     int i;  | 
439  |  |  | 
440  | 676  |     tokObject = sftk_narrowToTokenObject(object);  | 
441  |  |  | 
442  |  |     /* session objects, just loop through the list */  | 
443  | 676  |     if (tokObject == NULL) { | 
444  | 2.72k  |         for (i = 0; i < itemTemplateCount; i++) { | 
445  | 2.04k  |             crv = sftk_Attribute2SecItem(arena, itemTemplate[i].item, object,  | 
446  | 2.04k  |                                          itemTemplate[i].type);  | 
447  | 2.04k  |             if (crv != CKR_OK) { | 
448  | 0  |                 return crv;  | 
449  | 0  |             }  | 
450  | 2.04k  |         }  | 
451  | 676  |         return CKR_OK;  | 
452  | 676  |     }  | 
453  |  |  | 
454  |  |     /* don't do any work if none is required */  | 
455  | 0  |     if (itemTemplateCount == 0) { | 
456  | 0  |         return CKR_OK;  | 
457  | 0  |     }  | 
458  |  |  | 
459  |  |     /* don't allocate the template unless we need it */  | 
460  | 0  |     if (itemTemplateCount > SFTK_MAX_ITEM_TEMPLATE) { | 
461  | 0  |         template = PORT_NewArray(CK_ATTRIBUTE, itemTemplateCount);  | 
462  | 0  |     } else { | 
463  | 0  |         template = templateSpace;  | 
464  | 0  |     }  | 
465  |  | 
  | 
466  | 0  |     if (template == NULL) { | 
467  | 0  |         crv = CKR_HOST_MEMORY;  | 
468  | 0  |         goto loser;  | 
469  | 0  |     }  | 
470  |  |  | 
471  | 0  |     dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);  | 
472  | 0  |     if (dbHandle == NULL) { | 
473  | 0  |         crv = CKR_OBJECT_HANDLE_INVALID;  | 
474  | 0  |         goto loser;  | 
475  | 0  |     }  | 
476  |  |  | 
477  |  |     /* set up the PKCS #11 template */  | 
478  | 0  |     for (i = 0; i < itemTemplateCount; i++) { | 
479  | 0  |         template[i].type = itemTemplate[i].type;  | 
480  | 0  |         template[i].pValue = NULL;  | 
481  | 0  |         template[i].ulValueLen = 0;  | 
482  | 0  |     }  | 
483  |  |  | 
484  |  |     /* fetch the attribute lengths */  | 
485  | 0  |     crv = sftkdb_GetAttributeValue(dbHandle, object->handle,  | 
486  | 0  |                                    template, itemTemplateCount);  | 
487  | 0  |     if (crv != CKR_OK) { | 
488  | 0  |         goto loser;  | 
489  | 0  |     }  | 
490  |  |  | 
491  |  |     /* allocate space for the attributes */  | 
492  | 0  |     for (i = 0; i < itemTemplateCount; i++) { | 
493  | 0  |         template[i].pValue = PORT_ArenaAlloc(arena, template[i].ulValueLen);  | 
494  | 0  |         if (template[i].pValue == NULL) { | 
495  | 0  |             crv = CKR_HOST_MEMORY;  | 
496  | 0  |             goto loser;  | 
497  | 0  |         }  | 
498  | 0  |     }  | 
499  |  |  | 
500  |  |     /* fetch the attributes */  | 
501  | 0  |     crv = sftkdb_GetAttributeValue(dbHandle, object->handle,  | 
502  | 0  |                                    template, itemTemplateCount);  | 
503  | 0  |     if (crv != CKR_OK) { | 
504  | 0  |         goto loser;  | 
505  | 0  |     }  | 
506  |  |  | 
507  |  |     /* Fill in the items */  | 
508  | 0  |     for (i = 0; i < itemTemplateCount; i++) { | 
509  | 0  |         itemTemplate[i].item->data = template[i].pValue;  | 
510  | 0  |         itemTemplate[i].item->len = template[i].ulValueLen;  | 
511  | 0  |     }  | 
512  |  | 
  | 
513  | 0  | loser:  | 
514  | 0  |     if (template != templateSpace) { | 
515  | 0  |         PORT_Free(template);  | 
516  | 0  |     }  | 
517  | 0  |     if (dbHandle) { | 
518  | 0  |         sftk_freeDB(dbHandle);  | 
519  | 0  |     }  | 
520  |  | 
  | 
521  | 0  |     return crv;  | 
522  | 0  | }  | 
523  |  |  | 
524  |  | /*  | 
525  |  |  * delete an attribute from an object  | 
526  |  |  */  | 
527  |  | static void  | 
528  |  | sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute)  | 
529  | 0  | { | 
530  | 0  |     SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);  | 
531  |  | 
  | 
532  | 0  |     if (sessObject == NULL) { | 
533  | 0  |         return;  | 
534  | 0  |     }  | 
535  | 0  |     PZ_Lock(sessObject->attributeLock);  | 
536  | 0  |     if (sftkqueue_is_queued(attribute, attribute->handle,  | 
537  | 0  |                             sessObject->head, sessObject->hashSize)) { | 
538  | 0  |         sftkqueue_delete(attribute, attribute->handle,  | 
539  | 0  |                          sessObject->head, sessObject->hashSize);  | 
540  | 0  |     }  | 
541  | 0  |     PZ_Unlock(sessObject->attributeLock);  | 
542  | 0  | }  | 
543  |  |  | 
544  |  | /*  | 
545  |  |  * this is only valid for CK_BBOOL type attributes. Return the state  | 
546  |  |  * of that attribute.  | 
547  |  |  */  | 
548  |  | PRBool  | 
549  |  | sftk_isTrue(SFTKObject *object, CK_ATTRIBUTE_TYPE type)  | 
550  | 91.2k  | { | 
551  | 91.2k  |     SFTKAttribute *attribute;  | 
552  | 91.2k  |     PRBool tok = PR_FALSE;  | 
553  |  |  | 
554  | 91.2k  |     attribute = sftk_FindAttribute(object, type);  | 
555  | 91.2k  |     if (attribute == NULL) { | 
556  | 17.8k  |         return PR_FALSE;  | 
557  | 17.8k  |     }  | 
558  | 73.4k  |     tok = (PRBool)(*(CK_BBOOL *)attribute->attrib.pValue);  | 
559  | 73.4k  |     sftk_FreeAttribute(attribute);  | 
560  |  |  | 
561  | 73.4k  |     return tok;  | 
562  | 91.2k  | }  | 
563  |  |  | 
564  |  | /*  | 
565  |  |  * force an attribute to null.  | 
566  |  |  * this is for sensitive keys which are stored in the database, we don't  | 
567  |  |  * want to keep this info around in memory in the clear.  | 
568  |  |  */  | 
569  |  | void  | 
570  |  | sftk_nullAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type)  | 
571  | 0  | { | 
572  | 0  |     SFTKAttribute *attribute;  | 
573  |  | 
  | 
574  | 0  |     attribute = sftk_FindAttribute(object, type);  | 
575  | 0  |     if (attribute == NULL)  | 
576  | 0  |         return;  | 
577  |  |  | 
578  | 0  |     if (attribute->attrib.pValue != NULL) { | 
579  | 0  |         PORT_Memset(attribute->attrib.pValue, 0, attribute->attrib.ulValueLen);  | 
580  | 0  |         if (attribute->freeData) { | 
581  | 0  |             PORT_Free(attribute->attrib.pValue);  | 
582  | 0  |         }  | 
583  | 0  |         attribute->freeData = PR_FALSE;  | 
584  | 0  |         attribute->attrib.pValue = NULL;  | 
585  | 0  |         attribute->attrib.ulValueLen = 0;  | 
586  | 0  |     }  | 
587  | 0  |     sftk_FreeAttribute(attribute);  | 
588  | 0  | }  | 
589  |  |  | 
590  |  | static CK_RV  | 
591  |  | sftk_forceTokenAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,  | 
592  |  |                          const void *value, unsigned int len)  | 
593  | 0  | { | 
594  | 0  |     CK_ATTRIBUTE attribute;  | 
595  | 0  |     SFTKDBHandle *dbHandle = NULL;  | 
596  | 0  |     SFTKTokenObject *to = sftk_narrowToTokenObject(object);  | 
597  | 0  |     CK_RV crv;  | 
598  |  | 
  | 
599  | 0  |     PORT_Assert(to);  | 
600  | 0  |     if (to == NULL) { | 
601  | 0  |         return CKR_DEVICE_ERROR;  | 
602  | 0  |     }  | 
603  |  |  | 
604  | 0  |     dbHandle = sftk_getDBForTokenObject(object->slot, object->handle);  | 
605  |  | 
  | 
606  | 0  |     attribute.type = type;  | 
607  | 0  |     attribute.pValue = (void *)value;  | 
608  | 0  |     attribute.ulValueLen = len;  | 
609  |  | 
  | 
610  | 0  |     crv = sftkdb_SetAttributeValue(dbHandle, object, &attribute, 1);  | 
611  | 0  |     sftk_freeDB(dbHandle);  | 
612  | 0  |     return crv;  | 
613  | 0  | }  | 
614  |  |  | 
615  |  | /*  | 
616  |  |  * force an attribute to a specifc value.  | 
617  |  |  */  | 
618  |  | CK_RV  | 
619  |  | sftk_forceAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,  | 
620  |  |                     const void *value, unsigned int len)  | 
621  | 41.7k  | { | 
622  | 41.7k  |     SFTKAttribute *attribute;  | 
623  | 41.7k  |     void *att_val = NULL;  | 
624  | 41.7k  |     PRBool freeData = PR_FALSE;  | 
625  |  |  | 
626  | 41.7k  |     PORT_Assert(object);  | 
627  | 41.7k  |     PORT_Assert(object->refCount);  | 
628  | 41.7k  |     PORT_Assert(object->slot);  | 
629  | 41.7k  |     if (!object ||  | 
630  | 41.7k  |         !object->refCount ||  | 
631  | 41.7k  |         !object->slot) { | 
632  | 0  |         return CKR_DEVICE_ERROR;  | 
633  | 0  |     }  | 
634  | 41.7k  |     if (sftk_isToken(object->handle)) { | 
635  | 0  |         return sftk_forceTokenAttribute(object, type, value, len);  | 
636  | 0  |     }  | 
637  | 41.7k  |     attribute = sftk_FindAttribute(object, type);  | 
638  | 41.7k  |     if (attribute == NULL)  | 
639  | 28.6k  |         return sftk_AddAttributeType(object, type, value, len);  | 
640  |  |  | 
641  | 13.0k  |     if (value) { | 
642  | 13.0k  |         if (len <= ATTR_SPACE) { | 
643  | 13.0k  |             att_val = attribute->space;  | 
644  | 13.0k  |         } else { | 
645  | 3  |             att_val = PORT_Alloc(len);  | 
646  | 3  |             freeData = PR_TRUE;  | 
647  | 3  |         }  | 
648  | 13.0k  |         if (att_val == NULL) { | 
649  | 0  |             return CKR_HOST_MEMORY;  | 
650  | 0  |         }  | 
651  | 13.0k  |         if (attribute->attrib.pValue == att_val) { | 
652  | 10.9k  |             PORT_Memset(attribute->attrib.pValue, 0,  | 
653  | 10.9k  |                         attribute->attrib.ulValueLen);  | 
654  | 10.9k  |         }  | 
655  | 13.0k  |         PORT_Memcpy(att_val, value, len);  | 
656  | 13.0k  |     }  | 
657  | 13.0k  |     if (attribute->attrib.pValue != NULL) { | 
658  | 10.9k  |         if (attribute->attrib.pValue != att_val) { | 
659  | 3  |             PORT_Memset(attribute->attrib.pValue, 0,  | 
660  | 3  |                         attribute->attrib.ulValueLen);  | 
661  | 3  |         }  | 
662  | 10.9k  |         if (attribute->freeData) { | 
663  | 3  |             PORT_Free(attribute->attrib.pValue);  | 
664  | 3  |         }  | 
665  | 10.9k  |         attribute->freeData = PR_FALSE;  | 
666  | 10.9k  |         attribute->attrib.pValue = NULL;  | 
667  | 10.9k  |         attribute->attrib.ulValueLen = 0;  | 
668  | 10.9k  |     }  | 
669  | 13.0k  |     if (att_val) { | 
670  | 13.0k  |         attribute->attrib.pValue = att_val;  | 
671  | 13.0k  |         attribute->attrib.ulValueLen = len;  | 
672  | 13.0k  |         attribute->freeData = freeData;  | 
673  | 13.0k  |     }  | 
674  | 13.0k  |     sftk_FreeAttribute(attribute);  | 
675  | 13.0k  |     return CKR_OK;  | 
676  | 13.0k  | }  | 
677  |  |  | 
678  |  | /*  | 
679  |  |  * return a null terminated string from attribute 'type'. This string  | 
680  |  |  * is allocated and needs to be freed with PORT_Free() When complete.  | 
681  |  |  */  | 
682  |  | char *  | 
683  |  | sftk_getString(SFTKObject *object, CK_ATTRIBUTE_TYPE type)  | 
684  | 0  | { | 
685  | 0  |     SFTKAttribute *attribute;  | 
686  | 0  |     char *label = NULL;  | 
687  |  | 
  | 
688  | 0  |     attribute = sftk_FindAttribute(object, type);  | 
689  | 0  |     if (attribute == NULL)  | 
690  | 0  |         return NULL;  | 
691  |  |  | 
692  | 0  |     if (attribute->attrib.pValue != NULL) { | 
693  | 0  |         label = (char *)PORT_Alloc(attribute->attrib.ulValueLen + 1);  | 
694  | 0  |         if (label == NULL) { | 
695  | 0  |             sftk_FreeAttribute(attribute);  | 
696  | 0  |             return NULL;  | 
697  | 0  |         }  | 
698  |  |  | 
699  | 0  |         PORT_Memcpy(label, attribute->attrib.pValue,  | 
700  | 0  |                     attribute->attrib.ulValueLen);  | 
701  | 0  |         label[attribute->attrib.ulValueLen] = 0;  | 
702  | 0  |     }  | 
703  | 0  |     sftk_FreeAttribute(attribute);  | 
704  | 0  |     return label;  | 
705  | 0  | }  | 
706  |  |  | 
707  |  | /*  | 
708  |  |  * decode when a particular attribute may be modified  | 
709  |  |  *  SFTK_NEVER: This attribute must be set at object creation time and  | 
710  |  |  *  can never be modified.  | 
711  |  |  *  SFTK_ONCOPY: This attribute may be modified only when you copy the  | 
712  |  |  *  object.  | 
713  |  |  *  SFTK_SENSITIVE: The CKA_SENSITIVE attribute can only be changed from  | 
714  |  |  *  CK_FALSE to CK_TRUE.  | 
715  |  |  *  SFTK_ALWAYS: This attribute can always be modified.  | 
716  |  |  * Some attributes vary their modification type based on the class of the  | 
717  |  |  *   object.  | 
718  |  |  */  | 
719  |  | SFTKModifyType  | 
720  |  | sftk_modifyType(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)  | 
721  | 2.09k  | { | 
722  |  |     /* if we don't know about it, user user defined, always allow modify */  | 
723  | 2.09k  |     SFTKModifyType mtype = SFTK_ALWAYS;  | 
724  |  |  | 
725  | 2.09k  |     switch (type) { | 
726  |  |         /* NEVER */  | 
727  | 0  |         case CKA_CLASS:  | 
728  | 0  |         case CKA_CERTIFICATE_TYPE:  | 
729  | 0  |         case CKA_KEY_TYPE:  | 
730  | 0  |         case CKA_MODULUS:  | 
731  | 0  |         case CKA_MODULUS_BITS:  | 
732  | 0  |         case CKA_PUBLIC_EXPONENT:  | 
733  | 0  |         case CKA_PRIVATE_EXPONENT:  | 
734  | 0  |         case CKA_PRIME:  | 
735  | 0  |         case CKA_BASE:  | 
736  | 0  |         case CKA_PRIME_1:  | 
737  | 0  |         case CKA_PRIME_2:  | 
738  | 0  |         case CKA_EXPONENT_1:  | 
739  | 0  |         case CKA_EXPONENT_2:  | 
740  | 0  |         case CKA_COEFFICIENT:  | 
741  | 0  |         case CKA_VALUE_LEN:  | 
742  | 0  |         case CKA_ALWAYS_SENSITIVE:  | 
743  | 0  |         case CKA_NEVER_EXTRACTABLE:  | 
744  | 0  |         case CKA_NSS_DB:  | 
745  | 0  |             mtype = SFTK_NEVER;  | 
746  | 0  |             break;  | 
747  |  |  | 
748  |  |         /* ONCOPY */  | 
749  | 2  |         case CKA_TOKEN:  | 
750  | 2  |         case CKA_PRIVATE:  | 
751  | 2  |         case CKA_MODIFIABLE:  | 
752  | 2  |             mtype = SFTK_ONCOPY;  | 
753  | 2  |             break;  | 
754  |  |  | 
755  |  |         /* SENSITIVE */  | 
756  | 0  |         case CKA_SENSITIVE:  | 
757  | 0  |         case CKA_EXTRACTABLE:  | 
758  | 0  |             mtype = SFTK_SENSITIVE;  | 
759  | 0  |             break;  | 
760  |  |  | 
761  |  |         /* ALWAYS */  | 
762  | 0  |         case CKA_LABEL:  | 
763  | 0  |         case CKA_APPLICATION:  | 
764  | 2.09k  |         case CKA_ID:  | 
765  | 2.09k  |         case CKA_SERIAL_NUMBER:  | 
766  | 2.09k  |         case CKA_START_DATE:  | 
767  | 2.09k  |         case CKA_END_DATE:  | 
768  | 2.09k  |         case CKA_DERIVE:  | 
769  | 2.09k  |         case CKA_ENCRYPT:  | 
770  | 2.09k  |         case CKA_DECRYPT:  | 
771  | 2.09k  |         case CKA_SIGN:  | 
772  | 2.09k  |         case CKA_VERIFY:  | 
773  | 2.09k  |         case CKA_SIGN_RECOVER:  | 
774  | 2.09k  |         case CKA_VERIFY_RECOVER:  | 
775  | 2.09k  |         case CKA_WRAP:  | 
776  | 2.09k  |         case CKA_UNWRAP:  | 
777  | 2.09k  |             mtype = SFTK_ALWAYS;  | 
778  | 2.09k  |             break;  | 
779  |  |  | 
780  |  |         /* DEPENDS ON CLASS */  | 
781  | 0  |         case CKA_VALUE:  | 
782  | 0  |             mtype = (inClass == CKO_DATA) ? SFTK_ALWAYS : SFTK_NEVER;  | 
783  | 0  |             break;  | 
784  |  |  | 
785  | 0  |         case CKA_SUBPRIME:  | 
786  |  |             /* allow the CKA_SUBPRIME to be added to dh private keys */  | 
787  | 0  |             mtype = (inClass == CKO_PRIVATE_KEY) ? SFTK_ALWAYS : SFTK_NEVER;  | 
788  | 0  |             break;  | 
789  |  |  | 
790  | 0  |         case CKA_SUBJECT:  | 
791  | 0  |             mtype = (inClass == CKO_CERTIFICATE) ? SFTK_NEVER : SFTK_ALWAYS;  | 
792  | 0  |             break;  | 
793  | 0  |         default:  | 
794  | 0  |             break;  | 
795  | 2.09k  |     }  | 
796  | 2.09k  |     return mtype;  | 
797  | 2.09k  | }  | 
798  |  |  | 
799  |  | /* decode if a particular attribute is sensitive (cannot be read  | 
800  |  |  * back to the user of if the object is set to SENSITIVE) */  | 
801  |  | PRBool  | 
802  |  | sftk_isSensitive(CK_ATTRIBUTE_TYPE type, CK_OBJECT_CLASS inClass)  | 
803  | 0  | { | 
804  | 0  |     switch (type) { | 
805  |  |         /* ALWAYS */  | 
806  | 0  |         case CKA_PRIVATE_EXPONENT:  | 
807  | 0  |         case CKA_PRIME_1:  | 
808  | 0  |         case CKA_PRIME_2:  | 
809  | 0  |         case CKA_EXPONENT_1:  | 
810  | 0  |         case CKA_EXPONENT_2:  | 
811  | 0  |         case CKA_COEFFICIENT:  | 
812  | 0  |             return PR_TRUE;  | 
813  |  |  | 
814  |  |         /* DEPENDS ON CLASS */  | 
815  | 0  |         case CKA_VALUE:  | 
816  |  |             /* PRIVATE and SECRET KEYS have SENSITIVE values */  | 
817  | 0  |             return (PRBool)((inClass == CKO_PRIVATE_KEY) || (inClass == CKO_SECRET_KEY));  | 
818  |  |  | 
819  | 0  |         default:  | 
820  | 0  |             break;  | 
821  | 0  |     }  | 
822  | 0  |     return PR_FALSE;  | 
823  | 0  | }  | 
824  |  |  | 
825  |  | /*  | 
826  |  |  * copy an attribute into a SECItem. Secitem is allocated in the specified  | 
827  |  |  * arena.  | 
828  |  |  */  | 
829  |  | CK_RV  | 
830  |  | sftk_Attribute2SecItem(PLArenaPool *arena, SECItem *item, SFTKObject *object,  | 
831  |  |                        CK_ATTRIBUTE_TYPE type)  | 
832  | 3.45k  | { | 
833  | 3.45k  |     int len;  | 
834  | 3.45k  |     SFTKAttribute *attribute;  | 
835  |  |  | 
836  | 3.45k  |     attribute = sftk_FindAttribute(object, type);  | 
837  | 3.45k  |     if (attribute == NULL)  | 
838  | 0  |         return CKR_TEMPLATE_INCOMPLETE;  | 
839  | 3.45k  |     len = attribute->attrib.ulValueLen;  | 
840  |  |  | 
841  | 3.45k  |     if (arena) { | 
842  | 2.04k  |         item->data = (unsigned char *)PORT_ArenaAlloc(arena, len);  | 
843  | 2.04k  |     } else { | 
844  | 1.41k  |         item->data = (unsigned char *)PORT_Alloc(len);  | 
845  | 1.41k  |     }  | 
846  | 3.45k  |     if (item->data == NULL) { | 
847  | 0  |         sftk_FreeAttribute(attribute);  | 
848  | 0  |         return CKR_HOST_MEMORY;  | 
849  | 0  |     }  | 
850  | 3.45k  |     item->len = len;  | 
851  | 3.45k  |     PORT_Memcpy(item->data, attribute->attrib.pValue, len);  | 
852  | 3.45k  |     sftk_FreeAttribute(attribute);  | 
853  | 3.45k  |     return CKR_OK;  | 
854  | 3.45k  | }  | 
855  |  |  | 
856  |  | CK_RV  | 
857  |  | sftk_GetULongAttribute(SFTKObject *object, CK_ATTRIBUTE_TYPE type,  | 
858  |  |                        CK_ULONG *longData)  | 
859  | 9.79k  | { | 
860  | 9.79k  |     SFTKAttribute *attribute;  | 
861  |  |  | 
862  | 9.79k  |     attribute = sftk_FindAttribute(object, type);  | 
863  | 9.79k  |     if (attribute == NULL)  | 
864  | 0  |         return CKR_TEMPLATE_INCOMPLETE;  | 
865  |  |  | 
866  | 9.79k  |     if (attribute->attrib.ulValueLen != sizeof(CK_ULONG)) { | 
867  | 0  |         return CKR_ATTRIBUTE_VALUE_INVALID;  | 
868  | 0  |     }  | 
869  |  |  | 
870  | 9.79k  |     *longData = *(CK_ULONG *)attribute->attrib.pValue;  | 
871  | 9.79k  |     sftk_FreeAttribute(attribute);  | 
872  | 9.79k  |     return CKR_OK;  | 
873  | 9.79k  | }  | 
874  |  |  | 
875  |  | void  | 
876  |  | sftk_DeleteAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type)  | 
877  | 19.9k  | { | 
878  | 19.9k  |     SFTKAttribute *attribute;  | 
879  | 19.9k  |     attribute = sftk_FindAttribute(object, type);  | 
880  | 19.9k  |     if (attribute == NULL)  | 
881  | 19.9k  |         return;  | 
882  | 0  |     sftk_DeleteAttribute(object, attribute);  | 
883  | 0  |     sftk_DestroyAttribute(attribute);  | 
884  | 0  | }  | 
885  |  |  | 
886  |  | CK_RV  | 
887  |  | sftk_AddAttributeType(SFTKObject *object, CK_ATTRIBUTE_TYPE type,  | 
888  |  |                       const void *valPtr, CK_ULONG length)  | 
889  | 271k  | { | 
890  | 271k  |     SFTKAttribute *attribute;  | 
891  | 271k  |     attribute = sftk_NewAttribute(object, type, valPtr, length);  | 
892  | 271k  |     if (attribute == NULL) { | 
893  | 0  |         return CKR_HOST_MEMORY;  | 
894  | 0  |     }  | 
895  | 271k  |     sftk_AddAttribute(object, attribute);  | 
896  | 271k  |     return CKR_OK;  | 
897  | 271k  | }  | 
898  |  |  | 
899  |  | /*  | 
900  |  |  * ******************** Object Utilities *******************************  | 
901  |  |  */  | 
902  |  |  | 
903  |  | /* must be called holding sftk_tokenKeyLock(slot) */  | 
904  |  | static SECItem *  | 
905  |  | sftk_lookupTokenKeyByHandle(SFTKSlot *slot, CK_OBJECT_HANDLE handle)  | 
906  | 0  | { | 
907  | 0  |     return (SECItem *)PL_HashTableLookup(slot->tokObjHashTable, (void *)(uintptr_t)handle);  | 
908  | 0  | }  | 
909  |  |  | 
910  |  | /*  | 
911  |  |  * use the refLock. This operations should be very rare, so the added  | 
912  |  |  * contention on the ref lock should be lower than the overhead of adding  | 
913  |  |  * a new lock. We use separate functions for this just in case I'm wrong.  | 
914  |  |  */  | 
915  |  | static void  | 
916  |  | sftk_tokenKeyLock(SFTKSlot *slot)  | 
917  | 2  | { | 
918  | 2  |     SKIP_AFTER_FORK(PZ_Lock(slot->objectLock));  | 
919  | 2  | }  | 
920  |  |  | 
921  |  | static void  | 
922  |  | sftk_tokenKeyUnlock(SFTKSlot *slot)  | 
923  | 2  | { | 
924  | 2  |     SKIP_AFTER_FORK(PZ_Unlock(slot->objectLock));  | 
925  | 2  | }  | 
926  |  |  | 
927  |  | static PRIntn  | 
928  |  | sftk_freeHashItem(PLHashEntry *entry, PRIntn index, void *arg)  | 
929  | 0  | { | 
930  | 0  |     SECItem *item = (SECItem *)entry->value;  | 
931  |  | 
  | 
932  | 0  |     SECITEM_FreeItem(item, PR_TRUE);  | 
933  | 0  |     return HT_ENUMERATE_NEXT;  | 
934  | 0  | }  | 
935  |  |  | 
936  |  | CK_RV  | 
937  |  | SFTK_ClearTokenKeyHashTable(SFTKSlot *slot)  | 
938  | 2  | { | 
939  | 2  |     sftk_tokenKeyLock(slot);  | 
940  | 2  |     PORT_Assert(!slot->present);  | 
941  | 2  |     PL_HashTableEnumerateEntries(slot->tokObjHashTable, sftk_freeHashItem, NULL);  | 
942  | 2  |     sftk_tokenKeyUnlock(slot);  | 
943  | 2  |     return CKR_OK;  | 
944  | 2  | }  | 
945  |  |  | 
946  |  | /* allocation hooks that allow us to recycle old object structures */  | 
947  |  | static SFTKObjectFreeList sessionObjectList = { NULL, NULL, 0 }; | 
948  |  | static SFTKObjectFreeList tokenObjectList = { NULL, NULL, 0 }; | 
949  |  |  | 
950  |  | SFTKObject *  | 
951  |  | sftk_GetObjectFromList(PRBool *hasLocks, PRBool optimizeSpace,  | 
952  |  |                        SFTKObjectFreeList *list, unsigned int hashSize, PRBool isSessionObject)  | 
953  | 13.1k  | { | 
954  | 13.1k  |     SFTKObject *object;  | 
955  | 13.1k  |     int size = 0;  | 
956  |  |  | 
957  | 13.1k  |     if (!optimizeSpace) { | 
958  | 0  |         PZ_Lock(list->lock);  | 
959  | 0  |         object = list->head;  | 
960  | 0  |         if (object) { | 
961  | 0  |             list->head = object->next;  | 
962  | 0  |             list->count--;  | 
963  | 0  |         }  | 
964  | 0  |         PZ_Unlock(list->lock);  | 
965  | 0  |         if (object) { | 
966  | 0  |             object->next = object->prev = NULL;  | 
967  | 0  |             *hasLocks = PR_TRUE;  | 
968  | 0  |             return object;  | 
969  | 0  |         }  | 
970  | 0  |     }  | 
971  | 13.1k  |     size = isSessionObject ? sizeof(SFTKSessionObject) + hashSize * sizeof(SFTKAttribute *) : sizeof(SFTKTokenObject);  | 
972  |  |  | 
973  | 13.1k  |     object = (SFTKObject *)PORT_ZAlloc(size);  | 
974  | 13.1k  |     if (isSessionObject && object) { | 
975  | 13.1k  |         ((SFTKSessionObject *)object)->hashSize = hashSize;  | 
976  | 13.1k  |     }  | 
977  | 13.1k  |     *hasLocks = PR_FALSE;  | 
978  | 13.1k  |     return object;  | 
979  | 13.1k  | }  | 
980  |  |  | 
981  |  | static void  | 
982  |  | sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list,  | 
983  |  |                      PRBool isSessionObject)  | 
984  | 13.1k  | { | 
985  |  |  | 
986  |  |     /* the code below is equivalent to :  | 
987  |  |      *     optimizeSpace = isSessionObject ? object->optimizeSpace : PR_FALSE;  | 
988  |  |      * just faster.  | 
989  |  |      */  | 
990  | 13.1k  |     PRBool optimizeSpace = isSessionObject &&  | 
991  | 13.1k  |                            ((SFTKSessionObject *)object)->optimizeSpace;  | 
992  | 13.1k  |     if (object->refLock && !optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) { | 
993  | 0  |         PZ_Lock(list->lock);  | 
994  | 0  |         object->next = list->head;  | 
995  | 0  |         list->head = object;  | 
996  | 0  |         list->count++;  | 
997  | 0  |         PZ_Unlock(list->lock);  | 
998  | 0  |         return;  | 
999  | 0  |     }  | 
1000  | 13.1k  |     if (isSessionObject) { | 
1001  | 13.1k  |         SFTKSessionObject *so = (SFTKSessionObject *)object;  | 
1002  | 13.1k  |         PZ_DestroyLock(so->attributeLock);  | 
1003  | 13.1k  |         so->attributeLock = NULL;  | 
1004  | 13.1k  |     }  | 
1005  | 13.1k  |     if (object->refLock) { | 
1006  | 13.1k  |         PZ_DestroyLock(object->refLock);  | 
1007  | 13.1k  |         object->refLock = NULL;  | 
1008  | 13.1k  |     }  | 
1009  | 13.1k  |     PORT_Free(object);  | 
1010  | 13.1k  | }  | 
1011  |  |  | 
1012  |  | static SFTKObject *  | 
1013  |  | sftk_freeObjectData(SFTKObject *object)  | 
1014  | 0  | { | 
1015  | 0  |     SFTKObject *next = object->next;  | 
1016  |  | 
  | 
1017  | 0  |     PORT_Free(object);  | 
1018  | 0  |     return next;  | 
1019  | 0  | }  | 
1020  |  |  | 
1021  |  | static void  | 
1022  |  | sftk_InitFreeList(SFTKObjectFreeList *list)  | 
1023  | 2  | { | 
1024  | 2  |     if (!list->lock) { | 
1025  | 2  |         list->lock = PZ_NewLock(nssILockObject);  | 
1026  | 2  |     }  | 
1027  | 2  | }  | 
1028  |  |  | 
1029  |  | void  | 
1030  |  | sftk_InitFreeLists(void)  | 
1031  | 1  | { | 
1032  | 1  |     sftk_InitFreeList(&sessionObjectList);  | 
1033  | 1  |     sftk_InitFreeList(&tokenObjectList);  | 
1034  | 1  | }  | 
1035  |  |  | 
1036  |  | static void  | 
1037  |  | sftk_CleanupFreeList(SFTKObjectFreeList *list, PRBool isSessionList)  | 
1038  | 2  | { | 
1039  | 2  |     SFTKObject *object;  | 
1040  |  |  | 
1041  | 2  |     if (!list->lock) { | 
1042  | 0  |         return;  | 
1043  | 0  |     }  | 
1044  | 2  |     SKIP_AFTER_FORK(PZ_Lock(list->lock));  | 
1045  | 2  |     for (object = list->head; object != NULL;  | 
1046  | 2  |          object = sftk_freeObjectData(object)) { | 
1047  | 0  |         PZ_DestroyLock(object->refLock);  | 
1048  | 0  |         if (isSessionList) { | 
1049  | 0  |             PZ_DestroyLock(((SFTKSessionObject *)object)->attributeLock);  | 
1050  | 0  |         }  | 
1051  | 0  |     }  | 
1052  | 2  |     list->count = 0;  | 
1053  | 2  |     list->head = NULL;  | 
1054  | 2  |     SKIP_AFTER_FORK(PZ_Unlock(list->lock));  | 
1055  | 2  |     SKIP_AFTER_FORK(PZ_DestroyLock(list->lock));  | 
1056  | 2  |     list->lock = NULL;  | 
1057  | 2  | }  | 
1058  |  |  | 
1059  |  | void  | 
1060  |  | sftk_CleanupFreeLists(void)  | 
1061  | 1  | { | 
1062  | 1  |     sftk_CleanupFreeList(&sessionObjectList, PR_TRUE);  | 
1063  | 1  |     sftk_CleanupFreeList(&tokenObjectList, PR_FALSE);  | 
1064  | 1  | }  | 
1065  |  |  | 
1066  |  | /*  | 
1067  |  |  * Create a new object  | 
1068  |  |  */  | 
1069  |  | SFTKObject *  | 
1070  |  | sftk_NewObject(SFTKSlot *slot)  | 
1071  | 13.1k  | { | 
1072  | 13.1k  |     SFTKObject *object;  | 
1073  | 13.1k  |     SFTKSessionObject *sessObject;  | 
1074  | 13.1k  |     PRBool hasLocks = PR_FALSE;  | 
1075  | 13.1k  |     unsigned int i;  | 
1076  | 13.1k  |     unsigned int hashSize = 0;  | 
1077  |  |  | 
1078  | 13.1k  |     hashSize = (slot->optimizeSpace) ? SPACE_ATTRIBUTE_HASH_SIZE : TIME_ATTRIBUTE_HASH_SIZE;  | 
1079  |  |  | 
1080  | 13.1k  |     object = sftk_GetObjectFromList(&hasLocks, slot->optimizeSpace,  | 
1081  | 13.1k  |                                     &sessionObjectList, hashSize, PR_TRUE);  | 
1082  | 13.1k  |     if (object == NULL) { | 
1083  | 0  |         return NULL;  | 
1084  | 0  |     }  | 
1085  | 13.1k  |     sessObject = (SFTKSessionObject *)object;  | 
1086  | 13.1k  |     sessObject->nextAttr = 0;  | 
1087  |  |  | 
1088  | 602k  |     for (i = 0; i < MAX_OBJS_ATTRS; i++) { | 
1089  | 589k  |         sessObject->attrList[i].attrib.pValue = NULL;  | 
1090  | 589k  |         sessObject->attrList[i].freeData = PR_FALSE;  | 
1091  | 589k  |     }  | 
1092  | 13.1k  |     sessObject->optimizeSpace = slot->optimizeSpace;  | 
1093  |  |  | 
1094  | 13.1k  |     object->handle = 0;  | 
1095  | 13.1k  |     object->next = object->prev = NULL;  | 
1096  | 13.1k  |     object->slot = slot;  | 
1097  | 13.1k  |     object->isFIPS = sftk_isFIPS(slot->slotID);  | 
1098  |  |  | 
1099  | 13.1k  |     object->refCount = 1;  | 
1100  | 13.1k  |     sessObject->sessionList.next = NULL;  | 
1101  | 13.1k  |     sessObject->sessionList.prev = NULL;  | 
1102  | 13.1k  |     sessObject->sessionList.parent = object;  | 
1103  | 13.1k  |     sessObject->session = NULL;  | 
1104  | 13.1k  |     sessObject->wasDerived = PR_FALSE;  | 
1105  | 13.1k  |     if (!hasLocks)  | 
1106  | 13.1k  |         object->refLock = PZ_NewLock(nssILockRefLock);  | 
1107  | 13.1k  |     if (object->refLock == NULL) { | 
1108  | 0  |         PORT_Free(object);  | 
1109  | 0  |         return NULL;  | 
1110  | 0  |     }  | 
1111  | 13.1k  |     if (!hasLocks)  | 
1112  | 13.1k  |         sessObject->attributeLock = PZ_NewLock(nssILockAttribute);  | 
1113  | 13.1k  |     if (sessObject->attributeLock == NULL) { | 
1114  | 0  |         PZ_DestroyLock(object->refLock);  | 
1115  | 0  |         PORT_Free(object);  | 
1116  | 0  |         return NULL;  | 
1117  | 0  |     }  | 
1118  | 432k  |     for (i = 0; i < sessObject->hashSize; i++) { | 
1119  | 419k  |         sessObject->head[i] = NULL;  | 
1120  | 419k  |     }  | 
1121  | 13.1k  |     object->objectInfo = NULL;  | 
1122  | 13.1k  |     object->infoFree = NULL;  | 
1123  | 13.1k  |     return object;  | 
1124  | 13.1k  | }  | 
1125  |  |  | 
1126  |  | static CK_RV  | 
1127  |  | sftk_DestroySessionObjectData(SFTKSessionObject *so)  | 
1128  | 13.1k  | { | 
1129  | 13.1k  |     int i;  | 
1130  |  |  | 
1131  | 602k  |     for (i = 0; i < MAX_OBJS_ATTRS; i++) { | 
1132  | 589k  |         unsigned char *value = so->attrList[i].attrib.pValue;  | 
1133  | 589k  |         if (value) { | 
1134  | 219k  |             PORT_Memset(value, 0, so->attrList[i].attrib.ulValueLen);  | 
1135  | 219k  |             if (so->attrList[i].freeData) { | 
1136  | 7.06k  |                 PORT_Free(value);  | 
1137  | 7.06k  |             }  | 
1138  | 219k  |             so->attrList[i].attrib.pValue = NULL;  | 
1139  | 219k  |             so->attrList[i].freeData = PR_FALSE;  | 
1140  | 219k  |         }  | 
1141  | 589k  |     }  | 
1142  |  |     /*  PZ_DestroyLock(so->attributeLock);*/  | 
1143  | 13.1k  |     return CKR_OK;  | 
1144  | 13.1k  | }  | 
1145  |  |  | 
1146  |  | /*  | 
1147  |  |  * free all the data associated with an object. Object reference count must  | 
1148  |  |  * be 'zero'.  | 
1149  |  |  */  | 
1150  |  | static CK_RV  | 
1151  |  | sftk_DestroyObject(SFTKObject *object)  | 
1152  | 13.1k  | { | 
1153  | 13.1k  |     CK_RV crv = CKR_OK;  | 
1154  | 13.1k  |     SFTKSessionObject *so = sftk_narrowToSessionObject(object);  | 
1155  | 13.1k  |     SFTKTokenObject *to = sftk_narrowToTokenObject(object);  | 
1156  |  |  | 
1157  | 13.1k  |     PORT_Assert(object->refCount == 0);  | 
1158  |  |  | 
1159  |  |     /* delete the database value */  | 
1160  | 13.1k  |     if (to) { | 
1161  | 0  |         if (to->dbKey.data) { | 
1162  | 0  |             PORT_Free(to->dbKey.data);  | 
1163  | 0  |             to->dbKey.data = NULL;  | 
1164  | 0  |         }  | 
1165  | 0  |     }  | 
1166  | 13.1k  |     if (so) { | 
1167  | 13.1k  |         sftk_DestroySessionObjectData(so);  | 
1168  | 13.1k  |     }  | 
1169  | 13.1k  |     if (object->objectInfo) { | 
1170  | 4.19k  |         (*object->infoFree)(object->objectInfo);  | 
1171  | 4.19k  |         object->objectInfo = NULL;  | 
1172  | 4.19k  |         object->infoFree = NULL;  | 
1173  | 4.19k  |     }  | 
1174  | 13.1k  |     if (so) { | 
1175  | 13.1k  |         sftk_PutObjectToList(object, &sessionObjectList, PR_TRUE);  | 
1176  | 13.1k  |     } else { | 
1177  | 0  |         sftk_PutObjectToList(object, &tokenObjectList, PR_FALSE);  | 
1178  | 0  |     }  | 
1179  | 13.1k  |     return crv;  | 
1180  | 13.1k  | }  | 
1181  |  |  | 
1182  |  | void  | 
1183  |  | sftk_ReferenceObject(SFTKObject *object)  | 
1184  | 59.5k  | { | 
1185  | 59.5k  |     PZ_Lock(object->refLock);  | 
1186  | 59.5k  |     object->refCount++;  | 
1187  | 59.5k  |     PZ_Unlock(object->refLock);  | 
1188  | 59.5k  | }  | 
1189  |  |  | 
1190  |  | static SFTKObject *  | 
1191  |  | sftk_ObjectFromHandleOnSlot(CK_OBJECT_HANDLE handle, SFTKSlot *slot)  | 
1192  | 46.5k  | { | 
1193  | 46.5k  |     SFTKObject *object;  | 
1194  | 46.5k  |     PRUint32 index = sftk_hash(handle, slot->sessObjHashSize);  | 
1195  |  |  | 
1196  | 46.5k  |     if (sftk_isToken(handle)) { | 
1197  | 0  |         return sftk_NewTokenObject(slot, NULL, handle);  | 
1198  | 0  |     }  | 
1199  |  |  | 
1200  | 46.5k  |     PZ_Lock(slot->objectLock);  | 
1201  | 46.5k  |     sftkqueue_find2(object, handle, index, slot->sessObjHashTable);  | 
1202  | 46.5k  |     if (object) { | 
1203  | 46.5k  |         sftk_ReferenceObject(object);  | 
1204  | 46.5k  |     }  | 
1205  | 46.5k  |     PZ_Unlock(slot->objectLock);  | 
1206  |  |  | 
1207  | 46.5k  |     return (object);  | 
1208  | 46.5k  | }  | 
1209  |  | /*  | 
1210  |  |  * look up and object structure from a handle. OBJECT_Handles only make  | 
1211  |  |  * sense in terms of a given session.  make a reference to that object  | 
1212  |  |  * structure returned.  | 
1213  |  |  */  | 
1214  |  | SFTKObject *  | 
1215  |  | sftk_ObjectFromHandle(CK_OBJECT_HANDLE handle, SFTKSession *session)  | 
1216  | 46.5k  | { | 
1217  | 46.5k  |     SFTKSlot *slot = sftk_SlotFromSession(session);  | 
1218  |  |  | 
1219  | 46.5k  |     return sftk_ObjectFromHandleOnSlot(handle, slot);  | 
1220  | 46.5k  | }  | 
1221  |  |  | 
1222  |  | /*  | 
1223  |  |  * release a reference to an object handle  | 
1224  |  |  */  | 
1225  |  | SFTKFreeStatus  | 
1226  |  | sftk_FreeObject(SFTKObject *object)  | 
1227  | 72.6k  | { | 
1228  | 72.6k  |     PRBool destroy = PR_FALSE;  | 
1229  | 72.6k  |     CK_RV crv;  | 
1230  |  |  | 
1231  | 72.6k  |     PZ_Lock(object->refLock);  | 
1232  | 72.6k  |     if (object->refCount == 1)  | 
1233  | 13.1k  |         destroy = PR_TRUE;  | 
1234  | 72.6k  |     object->refCount--;  | 
1235  | 72.6k  |     PZ_Unlock(object->refLock);  | 
1236  |  |  | 
1237  | 72.6k  |     if (destroy) { | 
1238  | 13.1k  |         crv = sftk_DestroyObject(object);  | 
1239  | 13.1k  |         if (crv != CKR_OK) { | 
1240  | 0  |             return SFTK_DestroyFailure;  | 
1241  | 0  |         }  | 
1242  | 13.1k  |         return SFTK_Destroyed;  | 
1243  | 13.1k  |     }  | 
1244  | 59.5k  |     return SFTK_Busy;  | 
1245  | 72.6k  | }  | 
1246  |  |  | 
1247  |  | /* find the next available object handle that isn't currently in use */  | 
1248  |  | /* NOTE: This function could loop forever if we've exhausted all  | 
1249  |  |  * 3^31-1 handles. This is highly unlikely (NSS has been running for  | 
1250  |  |  * decades with this code) uless we start increasing the size of the  | 
1251  |  |  * SFTK_TOKEN_MASK (which is just the high bit currently). */  | 
1252  |  | CK_OBJECT_HANDLE  | 
1253  |  | sftk_getNextHandle(SFTKSlot *slot)  | 
1254  | 12.9k  | { | 
1255  | 12.9k  |     CK_OBJECT_HANDLE handle;  | 
1256  | 12.9k  |     SFTKObject *duplicateObject = NULL;  | 
1257  | 12.9k  |     do { | 
1258  | 12.9k  |         PRUint32 wrappedAround;  | 
1259  |  |  | 
1260  | 12.9k  |         duplicateObject = NULL;  | 
1261  | 12.9k  |         PZ_Lock(slot->objectLock);  | 
1262  | 12.9k  |         wrappedAround = slot->sessionObjectHandleCount & SFTK_TOKEN_MASK;  | 
1263  | 12.9k  |         handle = slot->sessionObjectHandleCount & ~SFTK_TOKEN_MASK;  | 
1264  | 12.9k  |         if (!handle) /* don't allow zero handle */  | 
1265  | 0  |             handle = NSC_MIN_SESSION_OBJECT_HANDLE;  | 
1266  | 12.9k  |         slot->sessionObjectHandleCount = (handle + 1U) | wrappedAround;  | 
1267  |  |         /* Is there already a session object with this handle? */  | 
1268  | 12.9k  |         if (wrappedAround) { | 
1269  | 0  |             sftkqueue_find(duplicateObject, handle, slot->sessObjHashTable,  | 
1270  | 0  |                            slot->sessObjHashSize);  | 
1271  | 0  |         }  | 
1272  | 12.9k  |         PZ_Unlock(slot->objectLock);  | 
1273  | 12.9k  |     } while (duplicateObject != NULL);  | 
1274  | 12.9k  |     return handle;  | 
1275  | 12.9k  | }  | 
1276  |  |  | 
1277  |  | /*  | 
1278  |  |  * add an object to a slot and session queue. These two functions  | 
1279  |  |  * adopt the object.  | 
1280  |  |  */  | 
1281  |  | void  | 
1282  |  | sftk_AddSlotObject(SFTKSlot *slot, SFTKObject *object)  | 
1283  | 12.9k  | { | 
1284  | 12.9k  |     PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);  | 
1285  | 12.9k  |     sftkqueue_init_element(object);  | 
1286  | 12.9k  |     PZ_Lock(slot->objectLock);  | 
1287  | 12.9k  |     sftkqueue_add2(object, object->handle, index, slot->sessObjHashTable);  | 
1288  | 12.9k  |     PZ_Unlock(slot->objectLock);  | 
1289  | 12.9k  | }  | 
1290  |  |  | 
1291  |  | void  | 
1292  |  | sftk_AddObject(SFTKSession *session, SFTKObject *object)  | 
1293  | 12.9k  | { | 
1294  | 12.9k  |     SFTKSlot *slot = sftk_SlotFromSession(session);  | 
1295  | 12.9k  |     SFTKSessionObject *so = sftk_narrowToSessionObject(object);  | 
1296  |  |  | 
1297  | 12.9k  |     if (so) { | 
1298  | 12.9k  |         PZ_Lock(session->objectLock);  | 
1299  | 12.9k  |         sftkqueue_add(&so->sessionList, 0, session->objects, 0);  | 
1300  | 12.9k  |         so->session = session;  | 
1301  | 12.9k  |         PZ_Unlock(session->objectLock);  | 
1302  | 12.9k  |     }  | 
1303  | 12.9k  |     sftk_AddSlotObject(slot, object);  | 
1304  | 12.9k  |     sftk_ReferenceObject(object);  | 
1305  | 12.9k  | }  | 
1306  |  |  | 
1307  |  | /*  | 
1308  |  |  * delete an object from a slot and session queue  | 
1309  |  |  */  | 
1310  |  | CK_RV  | 
1311  |  | sftk_DeleteObject(SFTKSession *session, SFTKObject *object)  | 
1312  | 12.9k  | { | 
1313  | 12.9k  |     SFTKSlot *slot = sftk_SlotFromSession(session);  | 
1314  | 12.9k  |     SFTKSessionObject *so = sftk_narrowToSessionObject(object);  | 
1315  | 12.9k  |     CK_RV crv = CKR_OK;  | 
1316  | 12.9k  |     PRUint32 index = sftk_hash(object->handle, slot->sessObjHashSize);  | 
1317  |  |  | 
1318  |  |     /* Handle Token case */  | 
1319  | 12.9k  |     if (so && so->session) { | 
1320  | 12.9k  |         session = so->session;  | 
1321  | 12.9k  |         PZ_Lock(session->objectLock);  | 
1322  | 12.9k  |         sftkqueue_delete(&so->sessionList, 0, session->objects, 0);  | 
1323  | 12.9k  |         PZ_Unlock(session->objectLock);  | 
1324  | 12.9k  |         PZ_Lock(slot->objectLock);  | 
1325  | 12.9k  |         sftkqueue_delete2(object, object->handle, index, slot->sessObjHashTable);  | 
1326  | 12.9k  |         PZ_Unlock(slot->objectLock);  | 
1327  | 12.9k  |         sftkqueue_clear_deleted_element(object);  | 
1328  | 12.9k  |         sftk_FreeObject(object); /* free the reference owned by the queue */  | 
1329  | 12.9k  |     } else { | 
1330  | 0  |         SFTKDBHandle *handle = sftk_getDBForTokenObject(slot, object->handle);  | 
1331  | 0  | #ifdef DEBUG  | 
1332  | 0  |         SFTKTokenObject *to = sftk_narrowToTokenObject(object);  | 
1333  | 0  |         PORT_Assert(to);  | 
1334  | 0  | #endif  | 
1335  | 0  |         crv = sftkdb_DestroyObject(handle, object->handle, object->objclass);  | 
1336  | 0  |         sftk_freeDB(handle);  | 
1337  | 0  |     }  | 
1338  | 12.9k  |     return crv;  | 
1339  | 12.9k  | }  | 
1340  |  |  | 
1341  |  | /*  | 
1342  |  |  * Token objects don't explicitly store their attributes, so we need to know  | 
1343  |  |  * what attributes make up a particular token object before we can copy it.  | 
1344  |  |  * below are the tables by object type.  | 
1345  |  |  */  | 
1346  |  | static const CK_ATTRIBUTE_TYPE commonAttrs[] = { | 
1347  |  |     CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_MODIFIABLE  | 
1348  |  | };  | 
1349  |  | static const CK_ULONG commonAttrsCount =  | 
1350  |  |     sizeof(commonAttrs) / sizeof(commonAttrs[0]);  | 
1351  |  |  | 
1352  |  | static const CK_ATTRIBUTE_TYPE commonKeyAttrs[] = { | 
1353  |  |     CKA_ID, CKA_START_DATE, CKA_END_DATE, CKA_DERIVE, CKA_LOCAL, CKA_KEY_TYPE  | 
1354  |  | };  | 
1355  |  | static const CK_ULONG commonKeyAttrsCount =  | 
1356  |  |     sizeof(commonKeyAttrs) / sizeof(commonKeyAttrs[0]);  | 
1357  |  |  | 
1358  |  | static const CK_ATTRIBUTE_TYPE secretKeyAttrs[] = { | 
1359  |  |     CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_ENCRYPT, CKA_DECRYPT, CKA_SIGN,  | 
1360  |  |     CKA_VERIFY, CKA_WRAP, CKA_UNWRAP, CKA_VALUE  | 
1361  |  | };  | 
1362  |  | static const CK_ULONG secretKeyAttrsCount =  | 
1363  |  |     sizeof(secretKeyAttrs) / sizeof(secretKeyAttrs[0]);  | 
1364  |  |  | 
1365  |  | static const CK_ATTRIBUTE_TYPE commonPubKeyAttrs[] = { | 
1366  |  |     CKA_ENCRYPT, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_SUBJECT  | 
1367  |  | };  | 
1368  |  | static const CK_ULONG commonPubKeyAttrsCount =  | 
1369  |  |     sizeof(commonPubKeyAttrs) / sizeof(commonPubKeyAttrs[0]);  | 
1370  |  |  | 
1371  |  | static const CK_ATTRIBUTE_TYPE rsaPubKeyAttrs[] = { | 
1372  |  |     CKA_MODULUS, CKA_PUBLIC_EXPONENT  | 
1373  |  | };  | 
1374  |  | static const CK_ULONG rsaPubKeyAttrsCount =  | 
1375  |  |     sizeof(rsaPubKeyAttrs) / sizeof(rsaPubKeyAttrs[0]);  | 
1376  |  |  | 
1377  |  | static const CK_ATTRIBUTE_TYPE dsaPubKeyAttrs[] = { | 
1378  |  |     CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE  | 
1379  |  | };  | 
1380  |  | static const CK_ULONG dsaPubKeyAttrsCount =  | 
1381  |  |     sizeof(dsaPubKeyAttrs) / sizeof(dsaPubKeyAttrs[0]);  | 
1382  |  |  | 
1383  |  | static const CK_ATTRIBUTE_TYPE dhPubKeyAttrs[] = { | 
1384  |  |     CKA_PRIME, CKA_BASE, CKA_VALUE  | 
1385  |  | };  | 
1386  |  | static const CK_ULONG dhPubKeyAttrsCount =  | 
1387  |  |     sizeof(dhPubKeyAttrs) / sizeof(dhPubKeyAttrs[0]);  | 
1388  |  | static const CK_ATTRIBUTE_TYPE ecPubKeyAttrs[] = { | 
1389  |  |     CKA_EC_PARAMS, CKA_EC_POINT  | 
1390  |  | };  | 
1391  |  | static const CK_ULONG ecPubKeyAttrsCount =  | 
1392  |  |     sizeof(ecPubKeyAttrs) / sizeof(ecPubKeyAttrs[0]);  | 
1393  |  |  | 
1394  |  | static const CK_ATTRIBUTE_TYPE commonPrivKeyAttrs[] = { | 
1395  |  |     CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_SUBJECT,  | 
1396  |  |     CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NSS_DB, CKA_PUBLIC_KEY_INFO  | 
1397  |  | };  | 
1398  |  | static const CK_ULONG commonPrivKeyAttrsCount =  | 
1399  |  |     sizeof(commonPrivKeyAttrs) / sizeof(commonPrivKeyAttrs[0]);  | 
1400  |  |  | 
1401  |  | static const CK_ATTRIBUTE_TYPE rsaPrivKeyAttrs[] = { | 
1402  |  |     CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,  | 
1403  |  |     CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT  | 
1404  |  | };  | 
1405  |  | static const CK_ULONG rsaPrivKeyAttrsCount =  | 
1406  |  |     sizeof(rsaPrivKeyAttrs) / sizeof(rsaPrivKeyAttrs[0]);  | 
1407  |  |  | 
1408  |  | static const CK_ATTRIBUTE_TYPE dsaPrivKeyAttrs[] = { | 
1409  |  |     CKA_SUBPRIME, CKA_PRIME, CKA_BASE, CKA_VALUE  | 
1410  |  | };  | 
1411  |  | static const CK_ULONG dsaPrivKeyAttrsCount =  | 
1412  |  |     sizeof(dsaPrivKeyAttrs) / sizeof(dsaPrivKeyAttrs[0]);  | 
1413  |  |  | 
1414  |  | static const CK_ATTRIBUTE_TYPE dhPrivKeyAttrs[] = { | 
1415  |  |     CKA_PRIME, CKA_BASE, CKA_VALUE  | 
1416  |  | };  | 
1417  |  | static const CK_ULONG dhPrivKeyAttrsCount =  | 
1418  |  |     sizeof(dhPrivKeyAttrs) / sizeof(dhPrivKeyAttrs[0]);  | 
1419  |  | static const CK_ATTRIBUTE_TYPE ecPrivKeyAttrs[] = { | 
1420  |  |     CKA_EC_PARAMS, CKA_VALUE  | 
1421  |  | };  | 
1422  |  | static const CK_ULONG ecPrivKeyAttrsCount =  | 
1423  |  |     sizeof(ecPrivKeyAttrs) / sizeof(ecPrivKeyAttrs[0]);  | 
1424  |  |  | 
1425  |  | static const CK_ATTRIBUTE_TYPE certAttrs[] = { | 
1426  |  |     CKA_CERTIFICATE_TYPE, CKA_VALUE, CKA_SUBJECT, CKA_ISSUER, CKA_SERIAL_NUMBER  | 
1427  |  | };  | 
1428  |  | static const CK_ULONG certAttrsCount =  | 
1429  |  |     sizeof(certAttrs) / sizeof(certAttrs[0]);  | 
1430  |  |  | 
1431  |  | static const CK_ATTRIBUTE_TYPE trustAttrs[] = { | 
1432  |  |     CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,  | 
1433  |  |     CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_EMAIL_PROTECTION,  | 
1434  |  |     CKA_TRUST_CODE_SIGNING, CKA_TRUST_STEP_UP_APPROVED  | 
1435  |  | };  | 
1436  |  | static const CK_ULONG trustAttrsCount =  | 
1437  |  |     sizeof(trustAttrs) / sizeof(trustAttrs[0]);  | 
1438  |  |  | 
1439  |  | static const CK_ATTRIBUTE_TYPE smimeAttrs[] = { | 
1440  |  |     CKA_SUBJECT, CKA_NSS_EMAIL, CKA_NSS_SMIME_TIMESTAMP, CKA_VALUE  | 
1441  |  | };  | 
1442  |  | static const CK_ULONG smimeAttrsCount =  | 
1443  |  |     sizeof(smimeAttrs) / sizeof(smimeAttrs[0]);  | 
1444  |  |  | 
1445  |  | static const CK_ATTRIBUTE_TYPE crlAttrs[] = { | 
1446  |  |     CKA_SUBJECT, CKA_VALUE, CKA_NSS_URL, CKA_NSS_KRL  | 
1447  |  | };  | 
1448  |  | static const CK_ULONG crlAttrsCount =  | 
1449  |  |     sizeof(crlAttrs) / sizeof(crlAttrs[0]);  | 
1450  |  |  | 
1451  |  | /* copy an object based on it's table */  | 
1452  |  | CK_RV  | 
1453  |  | stfk_CopyTokenAttributes(SFTKObject *destObject, SFTKTokenObject *src_to,  | 
1454  |  |                          const CK_ATTRIBUTE_TYPE *attrArray, CK_ULONG attrCount)  | 
1455  | 0  | { | 
1456  | 0  |     SFTKAttribute *attribute;  | 
1457  | 0  |     SFTKAttribute *newAttribute;  | 
1458  | 0  |     CK_RV crv = CKR_OK;  | 
1459  | 0  |     unsigned int i;  | 
1460  |  | 
  | 
1461  | 0  |     for (i = 0; i < attrCount; i++) { | 
1462  | 0  |         if (!sftk_hasAttribute(destObject, attrArray[i])) { | 
1463  | 0  |             attribute = sftk_FindAttribute(&src_to->obj, attrArray[i]);  | 
1464  | 0  |             if (!attribute) { | 
1465  | 0  |                 continue; /* return CKR_ATTRIBUTE_VALUE_INVALID; */  | 
1466  | 0  |             }  | 
1467  |  |             /* we need to copy the attribute since each attribute  | 
1468  |  |              * only has one set of link list pointers */  | 
1469  | 0  |             newAttribute = sftk_NewAttribute(destObject,  | 
1470  | 0  |                                              sftk_attr_expand(&attribute->attrib));  | 
1471  | 0  |             sftk_FreeAttribute(attribute); /* free the old attribute */  | 
1472  | 0  |             if (!newAttribute) { | 
1473  | 0  |                 return CKR_HOST_MEMORY;  | 
1474  | 0  |             }  | 
1475  | 0  |             sftk_AddAttribute(destObject, newAttribute);  | 
1476  | 0  |         }  | 
1477  | 0  |     }  | 
1478  | 0  |     return crv;  | 
1479  | 0  | }  | 
1480  |  |  | 
1481  |  | CK_RV  | 
1482  |  | stfk_CopyTokenPrivateKey(SFTKObject *destObject, SFTKTokenObject *src_to)  | 
1483  | 0  | { | 
1484  | 0  |     CK_RV crv;  | 
1485  | 0  |     CK_KEY_TYPE key_type;  | 
1486  | 0  |     SFTKAttribute *attribute;  | 
1487  |  |  | 
1488  |  |     /* copy the common attributes for all keys first */  | 
1489  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,  | 
1490  | 0  |                                    commonKeyAttrsCount);  | 
1491  | 0  |     if (crv != CKR_OK) { | 
1492  | 0  |         goto fail;  | 
1493  | 0  |     }  | 
1494  |  |     /* copy the common attributes for all private keys next */  | 
1495  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs,  | 
1496  | 0  |                                    commonPrivKeyAttrsCount);  | 
1497  | 0  |     if (crv != CKR_OK) { | 
1498  | 0  |         goto fail;  | 
1499  | 0  |     }  | 
1500  | 0  |     attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);  | 
1501  | 0  |     PORT_Assert(attribute); /* if it wasn't here, ww should have failed  | 
1502  |  |                  * copying the common attributes */  | 
1503  | 0  |     if (!attribute) { | 
1504  |  |         /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but  | 
1505  |  |          * the fact is, the only reason we couldn't get the attribute would  | 
1506  |  |          * be a memory error or database error (an error in the 'device').  | 
1507  |  |          * if we have a database error code, we could return it here */  | 
1508  | 0  |         crv = CKR_DEVICE_ERROR;  | 
1509  | 0  |         goto fail;  | 
1510  | 0  |     }  | 
1511  | 0  |     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;  | 
1512  | 0  |     sftk_FreeAttribute(attribute);  | 
1513  |  |  | 
1514  |  |     /* finally copy the attributes for various private key types */  | 
1515  | 0  |     switch (key_type) { | 
1516  | 0  |         case CKK_RSA:  | 
1517  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPrivKeyAttrs,  | 
1518  | 0  |                                            rsaPrivKeyAttrsCount);  | 
1519  | 0  |             break;  | 
1520  | 0  |         case CKK_DSA:  | 
1521  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPrivKeyAttrs,  | 
1522  | 0  |                                            dsaPrivKeyAttrsCount);  | 
1523  | 0  |             break;  | 
1524  | 0  |         case CKK_DH:  | 
1525  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, dhPrivKeyAttrs,  | 
1526  | 0  |                                            dhPrivKeyAttrsCount);  | 
1527  | 0  |             break;  | 
1528  | 0  |         case CKK_EC:  | 
1529  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, ecPrivKeyAttrs,  | 
1530  | 0  |                                            ecPrivKeyAttrsCount);  | 
1531  | 0  |             break;  | 
1532  | 0  |         default:  | 
1533  | 0  |             crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types  | 
1534  |  |                                      * of token keys into our database. */  | 
1535  | 0  |     }  | 
1536  | 0  | fail:  | 
1537  | 0  |     return crv;  | 
1538  | 0  | }  | 
1539  |  |  | 
1540  |  | CK_RV  | 
1541  |  | stfk_CopyTokenPublicKey(SFTKObject *destObject, SFTKTokenObject *src_to)  | 
1542  | 0  | { | 
1543  | 0  |     CK_RV crv;  | 
1544  | 0  |     CK_KEY_TYPE key_type;  | 
1545  | 0  |     SFTKAttribute *attribute;  | 
1546  |  |  | 
1547  |  |     /* copy the common attributes for all keys first */  | 
1548  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,  | 
1549  | 0  |                                    commonKeyAttrsCount);  | 
1550  | 0  |     if (crv != CKR_OK) { | 
1551  | 0  |         goto fail;  | 
1552  | 0  |     }  | 
1553  |  |  | 
1554  |  |     /* copy the common attributes for all public keys next */  | 
1555  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, commonPubKeyAttrs,  | 
1556  | 0  |                                    commonPubKeyAttrsCount);  | 
1557  | 0  |     if (crv != CKR_OK) { | 
1558  | 0  |         goto fail;  | 
1559  | 0  |     }  | 
1560  | 0  |     attribute = sftk_FindAttribute(&src_to->obj, CKA_KEY_TYPE);  | 
1561  | 0  |     PORT_Assert(attribute); /* if it wasn't here, ww should have failed  | 
1562  |  |                  * copying the common attributes */  | 
1563  | 0  |     if (!attribute) { | 
1564  |  |         /* OK, so CKR_ATTRIBUTE_VALUE_INVALID is the immediate error, but  | 
1565  |  |          * the fact is, the only reason we couldn't get the attribute would  | 
1566  |  |          * be a memory error or database error (an error in the 'device').  | 
1567  |  |          * if we have a database error code, we could return it here */  | 
1568  | 0  |         crv = CKR_DEVICE_ERROR;  | 
1569  | 0  |         goto fail;  | 
1570  | 0  |     }  | 
1571  | 0  |     key_type = *(CK_KEY_TYPE *)attribute->attrib.pValue;  | 
1572  | 0  |     sftk_FreeAttribute(attribute);  | 
1573  |  |  | 
1574  |  |     /* finally copy the attributes for various public key types */  | 
1575  | 0  |     switch (key_type) { | 
1576  | 0  |         case CKK_RSA:  | 
1577  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, rsaPubKeyAttrs,  | 
1578  | 0  |                                            rsaPubKeyAttrsCount);  | 
1579  | 0  |             break;  | 
1580  | 0  |         case CKK_DSA:  | 
1581  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, dsaPubKeyAttrs,  | 
1582  | 0  |                                            dsaPubKeyAttrsCount);  | 
1583  | 0  |             break;  | 
1584  | 0  |         case CKK_DH:  | 
1585  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, dhPubKeyAttrs,  | 
1586  | 0  |                                            dhPubKeyAttrsCount);  | 
1587  | 0  |             break;  | 
1588  | 0  |         case CKK_EC:  | 
1589  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, ecPubKeyAttrs,  | 
1590  | 0  |                                            ecPubKeyAttrsCount);  | 
1591  | 0  |             break;  | 
1592  | 0  |         default:  | 
1593  | 0  |             crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types  | 
1594  |  |                                      * of token keys into our database. */  | 
1595  | 0  |     }  | 
1596  | 0  | fail:  | 
1597  | 0  |     return crv;  | 
1598  | 0  | }  | 
1599  |  | CK_RV  | 
1600  |  | stfk_CopyTokenSecretKey(SFTKObject *destObject, SFTKTokenObject *src_to)  | 
1601  | 0  | { | 
1602  | 0  |     CK_RV crv;  | 
1603  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, commonKeyAttrs,  | 
1604  | 0  |                                    commonKeyAttrsCount);  | 
1605  | 0  |     if (crv != CKR_OK) { | 
1606  | 0  |         goto fail;  | 
1607  | 0  |     }  | 
1608  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, secretKeyAttrs,  | 
1609  | 0  |                                    secretKeyAttrsCount);  | 
1610  | 0  | fail:  | 
1611  | 0  |     return crv;  | 
1612  | 0  | }  | 
1613  |  |  | 
1614  |  | /*  | 
1615  |  |  * Copy a token object. We need to explicitly copy the relevant  | 
1616  |  |  * attributes since token objects don't store those attributes in  | 
1617  |  |  * the token itself.  | 
1618  |  |  */  | 
1619  |  | CK_RV  | 
1620  |  | sftk_CopyTokenObject(SFTKObject *destObject, SFTKObject *srcObject)  | 
1621  | 0  | { | 
1622  | 0  |     SFTKTokenObject *src_to = sftk_narrowToTokenObject(srcObject);  | 
1623  | 0  |     CK_RV crv;  | 
1624  |  | 
  | 
1625  | 0  |     PORT_Assert(src_to);  | 
1626  | 0  |     if (src_to == NULL) { | 
1627  | 0  |         return CKR_DEVICE_ERROR; /* internal state inconsistant */  | 
1628  | 0  |     }  | 
1629  |  |  | 
1630  | 0  |     crv = stfk_CopyTokenAttributes(destObject, src_to, commonAttrs,  | 
1631  | 0  |                                    commonAttrsCount);  | 
1632  | 0  |     if (crv != CKR_OK) { | 
1633  | 0  |         goto fail;  | 
1634  | 0  |     }  | 
1635  | 0  |     switch (src_to->obj.objclass) { | 
1636  | 0  |         case CKO_CERTIFICATE:  | 
1637  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, certAttrs,  | 
1638  | 0  |                                            certAttrsCount);  | 
1639  | 0  |             break;  | 
1640  | 0  |         case CKO_NSS_TRUST:  | 
1641  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, trustAttrs,  | 
1642  | 0  |                                            trustAttrsCount);  | 
1643  | 0  |             break;  | 
1644  | 0  |         case CKO_NSS_SMIME:  | 
1645  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, smimeAttrs,  | 
1646  | 0  |                                            smimeAttrsCount);  | 
1647  | 0  |             break;  | 
1648  | 0  |         case CKO_NSS_CRL:  | 
1649  | 0  |             crv = stfk_CopyTokenAttributes(destObject, src_to, crlAttrs,  | 
1650  | 0  |                                            crlAttrsCount);  | 
1651  | 0  |             break;  | 
1652  | 0  |         case CKO_PRIVATE_KEY:  | 
1653  | 0  |             crv = stfk_CopyTokenPrivateKey(destObject, src_to);  | 
1654  | 0  |             break;  | 
1655  | 0  |         case CKO_PUBLIC_KEY:  | 
1656  | 0  |             crv = stfk_CopyTokenPublicKey(destObject, src_to);  | 
1657  | 0  |             break;  | 
1658  | 0  |         case CKO_SECRET_KEY:  | 
1659  | 0  |             crv = stfk_CopyTokenSecretKey(destObject, src_to);  | 
1660  | 0  |             break;  | 
1661  | 0  |         default:  | 
1662  | 0  |             crv = CKR_DEVICE_ERROR; /* shouldn't happen unless we store more types  | 
1663  |  |                                      * of token keys into our database. */  | 
1664  | 0  |     }  | 
1665  | 0  | fail:  | 
1666  | 0  |     return crv;  | 
1667  | 0  | }  | 
1668  |  |  | 
1669  |  | /*  | 
1670  |  |  * copy the attributes from one object to another. Don't overwrite existing  | 
1671  |  |  * attributes. NOTE: This is a pretty expensive operation since it  | 
1672  |  |  * grabs the attribute locks for the src object for a *long* time.  | 
1673  |  |  */  | 
1674  |  | CK_RV  | 
1675  |  | sftk_CopyObject(SFTKObject *destObject, SFTKObject *srcObject)  | 
1676  | 36  | { | 
1677  | 36  |     SFTKAttribute *attribute;  | 
1678  | 36  |     SFTKSessionObject *src_so = sftk_narrowToSessionObject(srcObject);  | 
1679  | 36  |     unsigned int i;  | 
1680  |  |  | 
1681  | 36  |     destObject->isFIPS = srcObject->isFIPS;  | 
1682  | 36  |     if (src_so == NULL) { | 
1683  | 0  |         return sftk_CopyTokenObject(destObject, srcObject);  | 
1684  | 0  |     }  | 
1685  |  |  | 
1686  | 36  |     PZ_Lock(src_so->attributeLock);  | 
1687  | 1.18k  |     for (i = 0; i < src_so->hashSize; i++) { | 
1688  | 1.15k  |         attribute = src_so->head[i];  | 
1689  | 1.24k  |         do { | 
1690  | 1.24k  |             if (attribute) { | 
1691  | 299  |                 if (!sftk_hasAttribute(destObject, attribute->handle)) { | 
1692  |  |                     /* we need to copy the attribute since each attribute  | 
1693  |  |                      * only has one set of link list pointers */  | 
1694  | 297  |                     SFTKAttribute *newAttribute = sftk_NewAttribute(  | 
1695  | 297  |                         destObject, sftk_attr_expand(&attribute->attrib));  | 
1696  | 297  |                     if (newAttribute == NULL) { | 
1697  | 0  |                         PZ_Unlock(src_so->attributeLock);  | 
1698  | 0  |                         return CKR_HOST_MEMORY;  | 
1699  | 0  |                     }  | 
1700  | 297  |                     sftk_AddAttribute(destObject, newAttribute);  | 
1701  | 297  |                 }  | 
1702  | 299  |                 attribute = attribute->next;  | 
1703  | 299  |             }  | 
1704  | 1.24k  |         } while (attribute != NULL);  | 
1705  | 1.15k  |     }  | 
1706  | 36  |     PZ_Unlock(src_so->attributeLock);  | 
1707  |  |  | 
1708  | 36  |     return CKR_OK;  | 
1709  | 36  | }  | 
1710  |  |  | 
1711  |  | /*  | 
1712  |  |  * ******************** Search Utilities *******************************  | 
1713  |  |  */  | 
1714  |  |  | 
1715  |  | /* add an object to a search list */  | 
1716  |  | CK_RV  | 
1717  |  | AddToList(SFTKObjectListElement **list, SFTKObject *object)  | 
1718  | 0  | { | 
1719  | 0  |     SFTKObjectListElement *newElem =  | 
1720  | 0  |         (SFTKObjectListElement *)PORT_Alloc(sizeof(SFTKObjectListElement));  | 
1721  |  | 
  | 
1722  | 0  |     if (newElem == NULL)  | 
1723  | 0  |         return CKR_HOST_MEMORY;  | 
1724  |  |  | 
1725  | 0  |     newElem->next = *list;  | 
1726  | 0  |     newElem->object = object;  | 
1727  | 0  |     sftk_ReferenceObject(object);  | 
1728  |  | 
  | 
1729  | 0  |     *list = newElem;  | 
1730  | 0  |     return CKR_OK;  | 
1731  | 0  | }  | 
1732  |  |  | 
1733  |  | /* return true if the object matches the template */  | 
1734  |  | PRBool  | 
1735  |  | sftk_objectMatch(SFTKObject *object, CK_ATTRIBUTE_PTR theTemplate, int count)  | 
1736  | 24  | { | 
1737  | 24  |     int i;  | 
1738  |  |  | 
1739  | 24  |     for (i = 0; i < count; i++) { | 
1740  | 24  |         SFTKAttribute *attribute = sftk_FindAttribute(object, theTemplate[i].type);  | 
1741  | 24  |         if (attribute == NULL) { | 
1742  | 0  |             return PR_FALSE;  | 
1743  | 0  |         }  | 
1744  | 24  |         if (attribute->attrib.ulValueLen == theTemplate[i].ulValueLen) { | 
1745  | 24  |             if (PORT_Memcmp(attribute->attrib.pValue, theTemplate[i].pValue,  | 
1746  | 24  |                             theTemplate[i].ulValueLen) == 0) { | 
1747  | 0  |                 sftk_FreeAttribute(attribute);  | 
1748  | 0  |                 continue;  | 
1749  | 0  |             }  | 
1750  | 24  |         }  | 
1751  | 24  |         sftk_FreeAttribute(attribute);  | 
1752  | 24  |         return PR_FALSE;  | 
1753  | 24  |     }  | 
1754  | 0  |     return PR_TRUE;  | 
1755  | 24  | }  | 
1756  |  |  | 
1757  |  | /* search through all the objects in the queue and return the template matches  | 
1758  |  |  * in the object list.  | 
1759  |  |  */  | 
1760  |  | CK_RV  | 
1761  |  | sftk_searchObjectList(SFTKSearchResults *search, SFTKObject **head,  | 
1762  |  |                       unsigned int size, PZLock *lock, CK_ATTRIBUTE_PTR theTemplate,  | 
1763  |  |                       int count, PRBool isLoggedIn)  | 
1764  | 34  | { | 
1765  | 34  |     unsigned int i;  | 
1766  | 34  |     SFTKObject *object;  | 
1767  | 34  |     CK_RV crv = CKR_OK;  | 
1768  |  |  | 
1769  | 34  |     PZ_Lock(lock);  | 
1770  | 1.12k  |     for (i = 0; i < size; i++) { | 
1771  | 1.11k  |         for (object = head[i]; object != NULL; object = object->next) { | 
1772  | 24  |             if (sftk_objectMatch(object, theTemplate, count)) { | 
1773  |  |                 /* don't return objects that aren't yet visible */  | 
1774  | 0  |                 if ((!isLoggedIn) && sftk_isTrue(object, CKA_PRIVATE))  | 
1775  | 0  |                     continue;  | 
1776  | 0  |                 sftk_addHandle(search, object->handle);  | 
1777  | 0  |             }  | 
1778  | 24  |         }  | 
1779  | 1.08k  |     }  | 
1780  | 34  |     PZ_Unlock(lock);  | 
1781  | 34  |     return crv;  | 
1782  | 34  | }  | 
1783  |  |  | 
1784  |  | /*  | 
1785  |  |  * free a single list element. Return the Next object in the list.  | 
1786  |  |  */  | 
1787  |  | SFTKObjectListElement *  | 
1788  |  | sftk_FreeObjectListElement(SFTKObjectListElement *objectList)  | 
1789  | 0  | { | 
1790  | 0  |     SFTKObjectListElement *ol = objectList->next;  | 
1791  |  | 
  | 
1792  | 0  |     sftk_FreeObject(objectList->object);  | 
1793  | 0  |     PORT_Free(objectList);  | 
1794  | 0  |     return ol;  | 
1795  | 0  | }  | 
1796  |  |  | 
1797  |  | /* free an entire object list */  | 
1798  |  | void  | 
1799  |  | sftk_FreeObjectList(SFTKObjectListElement *objectList)  | 
1800  | 0  | { | 
1801  | 0  |     SFTKObjectListElement *ol;  | 
1802  |  | 
  | 
1803  | 0  |     for (ol = objectList; ol != NULL; ol = sftk_FreeObjectListElement(ol)) { | 
1804  | 0  |     }  | 
1805  | 0  | }  | 
1806  |  |  | 
1807  |  | /*  | 
1808  |  |  * free a search structure  | 
1809  |  |  */  | 
1810  |  | void  | 
1811  |  | sftk_FreeSearch(SFTKSearchResults *search)  | 
1812  | 34  | { | 
1813  | 34  |     if (search->handles) { | 
1814  | 34  |         PORT_Free(search->handles);  | 
1815  | 34  |     }  | 
1816  | 34  |     PORT_Free(search);  | 
1817  | 34  | }  | 
1818  |  |  | 
1819  |  | /*  | 
1820  |  |  * ******************** Session Utilities *******************************  | 
1821  |  |  */  | 
1822  |  |  | 
1823  |  | /* update the sessions state based in it's flags and wether or not it's  | 
1824  |  |  * logged in */  | 
1825  |  | void  | 
1826  |  | sftk_update_state(SFTKSlot *slot, SFTKSession *session)  | 
1827  | 22.4k  | { | 
1828  | 22.4k  |     if (slot->isLoggedIn) { | 
1829  | 0  |         if (slot->ssoLoggedIn) { | 
1830  | 0  |             session->info.state = CKS_RW_SO_FUNCTIONS;  | 
1831  | 0  |         } else if (session->info.flags & CKF_RW_SESSION) { | 
1832  | 0  |             session->info.state = CKS_RW_USER_FUNCTIONS;  | 
1833  | 0  |         } else { | 
1834  | 0  |             session->info.state = CKS_RO_USER_FUNCTIONS;  | 
1835  | 0  |         }  | 
1836  | 22.4k  |     } else { | 
1837  | 22.4k  |         if (session->info.flags & CKF_RW_SESSION) { | 
1838  | 0  |             session->info.state = CKS_RW_PUBLIC_SESSION;  | 
1839  | 22.4k  |         } else { | 
1840  | 22.4k  |             session->info.state = CKS_RO_PUBLIC_SESSION;  | 
1841  | 22.4k  |         }  | 
1842  | 22.4k  |     }  | 
1843  | 22.4k  | }  | 
1844  |  |  | 
1845  |  | /* update the state of all the sessions on a slot */  | 
1846  |  | void  | 
1847  |  | sftk_update_all_states(SFTKSlot *slot)  | 
1848  | 0  | { | 
1849  | 0  |     unsigned int i;  | 
1850  | 0  |     SFTKSession *session;  | 
1851  |  | 
  | 
1852  | 0  |     for (i = 0; i < slot->sessHashSize; i++) { | 
1853  | 0  |         PZLock *lock = SFTK_SESSION_LOCK(slot, i);  | 
1854  | 0  |         PZ_Lock(lock);  | 
1855  | 0  |         for (session = slot->head[i]; session; session = session->next) { | 
1856  | 0  |             sftk_update_state(slot, session);  | 
1857  | 0  |         }  | 
1858  | 0  |         PZ_Unlock(lock);  | 
1859  | 0  |     }  | 
1860  | 0  | }  | 
1861  |  |  | 
1862  |  | /*  | 
1863  |  |  * context are cipher and digest contexts that are associated with a session  | 
1864  |  |  */  | 
1865  |  | void  | 
1866  |  | sftk_FreeContext(SFTKSessionContext *context)  | 
1867  | 13.4k  | { | 
1868  | 13.4k  |     if (context->cipherInfo) { | 
1869  | 13.4k  |         (*context->destroy)(context->cipherInfo, PR_TRUE);  | 
1870  | 13.4k  |     }  | 
1871  | 13.4k  |     if (context->hashInfo) { | 
1872  | 491  |         (*context->hashdestroy)(context->hashInfo, PR_TRUE);  | 
1873  | 491  |     }  | 
1874  | 13.4k  |     if (context->key) { | 
1875  | 3.70k  |         sftk_FreeObject(context->key);  | 
1876  | 3.70k  |         context->key = NULL;  | 
1877  | 3.70k  |     }  | 
1878  | 13.4k  |     PORT_Free(context);  | 
1879  | 13.4k  | }  | 
1880  |  |  | 
1881  |  | /*  | 
1882  |  |  * Init a new session. NOTE: The session handle is not set, and the  | 
1883  |  |  * session is not added to the slot's session queue.  | 
1884  |  |  */  | 
1885  |  | CK_RV  | 
1886  |  | sftk_InitSession(SFTKSession *session, SFTKSlot *slot, CK_SLOT_ID slotID,  | 
1887  |  |                  CK_NOTIFY notify, CK_VOID_PTR pApplication, CK_FLAGS flags)  | 
1888  | 11.2k  | { | 
1889  | 11.2k  |     session->next = session->prev = NULL;  | 
1890  | 11.2k  |     session->enc_context = NULL;  | 
1891  | 11.2k  |     session->hash_context = NULL;  | 
1892  | 11.2k  |     session->sign_context = NULL;  | 
1893  | 11.2k  |     session->search = NULL;  | 
1894  | 11.2k  |     session->objectIDCount = 1;  | 
1895  | 11.2k  |     session->objectLock = PZ_NewLock(nssILockObject);  | 
1896  | 11.2k  |     if (session->objectLock == NULL) { | 
1897  | 0  |         return CKR_HOST_MEMORY;  | 
1898  | 0  |     }  | 
1899  | 11.2k  |     session->objects[0] = NULL;  | 
1900  |  |  | 
1901  | 11.2k  |     session->slot = slot;  | 
1902  | 11.2k  |     session->notify = notify;  | 
1903  | 11.2k  |     session->appData = pApplication;  | 
1904  | 11.2k  |     session->info.flags = flags;  | 
1905  | 11.2k  |     session->info.slotID = slotID;  | 
1906  | 11.2k  |     session->info.ulDeviceError = 0;  | 
1907  | 11.2k  |     sftk_update_state(slot, session);  | 
1908  |  |     /* no ops completed yet, so the last one couldn't be a FIPS op */  | 
1909  | 11.2k  |     session->lastOpWasFIPS = PR_FALSE;  | 
1910  | 11.2k  |     return CKR_OK;  | 
1911  | 11.2k  | }  | 
1912  |  |  | 
1913  |  | /*  | 
1914  |  |  * Create a new session and init it.  | 
1915  |  |  */  | 
1916  |  | SFTKSession *  | 
1917  |  | sftk_NewSession(CK_SLOT_ID slotID, CK_NOTIFY notify, CK_VOID_PTR pApplication,  | 
1918  |  |                 CK_FLAGS flags)  | 
1919  | 11.2k  | { | 
1920  | 11.2k  |     SFTKSession *session;  | 
1921  | 11.2k  |     SFTKSlot *slot = sftk_SlotFromID(slotID, PR_FALSE);  | 
1922  | 11.2k  |     CK_RV crv;  | 
1923  |  |  | 
1924  | 11.2k  |     if (slot == NULL)  | 
1925  | 0  |         return NULL;  | 
1926  |  |  | 
1927  | 11.2k  |     session = (SFTKSession *)PORT_Alloc(sizeof(SFTKSession));  | 
1928  | 11.2k  |     if (session == NULL)  | 
1929  | 0  |         return NULL;  | 
1930  |  |  | 
1931  | 11.2k  |     crv = sftk_InitSession(session, slot, slotID, notify, pApplication, flags);  | 
1932  | 11.2k  |     if (crv != CKR_OK) { | 
1933  | 0  |         PORT_Free(session);  | 
1934  | 0  |         return NULL;  | 
1935  | 0  |     }  | 
1936  | 11.2k  |     return session;  | 
1937  | 11.2k  | }  | 
1938  |  |  | 
1939  |  | /* free all the data associated with a session. */  | 
1940  |  | void  | 
1941  |  | sftk_ClearSession(SFTKSession *session)  | 
1942  | 11.2k  | { | 
1943  | 11.2k  |     SFTKObjectList *op, *next;  | 
1944  |  |  | 
1945  |  |     /* clean out the attributes */  | 
1946  |  |     /* since no one is referencing us, it's safe to walk the chain  | 
1947  |  |      * without a lock */  | 
1948  | 11.2k  |     for (op = session->objects[0]; op != NULL; op = next) { | 
1949  | 0  |         next = op->next;  | 
1950  |  |         /* paranoia */  | 
1951  | 0  |         op->next = op->prev = NULL;  | 
1952  | 0  |         sftk_DeleteObject(session, op->parent);  | 
1953  | 0  |     }  | 
1954  | 11.2k  |     PZ_DestroyLock(session->objectLock);  | 
1955  | 11.2k  |     if (session->enc_context) { | 
1956  | 962  |         sftk_FreeContext(session->enc_context);  | 
1957  | 962  |     }  | 
1958  | 11.2k  |     if (session->hash_context) { | 
1959  | 342  |         sftk_FreeContext(session->hash_context);  | 
1960  | 342  |     }  | 
1961  | 11.2k  |     if (session->sign_context) { | 
1962  | 0  |         sftk_FreeContext(session->sign_context);  | 
1963  | 0  |     }  | 
1964  | 11.2k  |     if (session->search) { | 
1965  | 0  |         sftk_FreeSearch(session->search);  | 
1966  | 0  |     }  | 
1967  | 11.2k  | }  | 
1968  |  |  | 
1969  |  | /* free the data associated with the session, and the session */  | 
1970  |  | void  | 
1971  |  | sftk_DestroySession(SFTKSession *session)  | 
1972  | 11.2k  | { | 
1973  | 11.2k  |     sftk_ClearSession(session);  | 
1974  | 11.2k  |     PORT_Free(session);  | 
1975  | 11.2k  | }  | 
1976  |  |  | 
1977  |  | /*  | 
1978  |  |  * look up a session structure from a session handle  | 
1979  |  |  * generate a reference to it.  | 
1980  |  |  */  | 
1981  |  | SFTKSession *  | 
1982  |  | sftk_SessionFromHandle(CK_SESSION_HANDLE handle)  | 
1983  | 121k  | { | 
1984  | 121k  |     SFTKSlot *slot = sftk_SlotFromSessionHandle(handle);  | 
1985  | 121k  |     SFTKSession *session;  | 
1986  | 121k  |     PZLock *lock;  | 
1987  |  |  | 
1988  | 121k  |     if (!slot)  | 
1989  | 0  |         return NULL;  | 
1990  | 121k  |     lock = SFTK_SESSION_LOCK(slot, handle);  | 
1991  |  |  | 
1992  | 121k  |     PZ_Lock(lock);  | 
1993  | 121k  |     sftkqueue_find(session, handle, slot->head, slot->sessHashSize);  | 
1994  | 121k  |     PZ_Unlock(lock);  | 
1995  |  |  | 
1996  | 121k  |     return (session);  | 
1997  | 121k  | }  | 
1998  |  |  | 
1999  |  | /*  | 
2000  |  |  * release a reference to a session handle. This method of using SFTKSessions  | 
2001  |  |  * is deprecated, but the pattern should be retained until a future effort  | 
2002  |  |  * to refactor all SFTKSession users at once is completed.  | 
2003  |  |  */  | 
2004  |  | void  | 
2005  |  | sftk_FreeSession(SFTKSession *session)  | 
2006  | 110k  | { | 
2007  | 110k  |     return;  | 
2008  | 110k  | }  | 
2009  |  |  | 
2010  |  | void  | 
2011  |  | sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle)  | 
2012  | 0  | { | 
2013  | 0  |     if (search->handles == NULL) { | 
2014  | 0  |         return;  | 
2015  | 0  |     }  | 
2016  | 0  |     if (search->size >= search->array_size) { | 
2017  | 0  |         search->array_size += NSC_SEARCH_BLOCK_SIZE;  | 
2018  | 0  |         search->handles = (CK_OBJECT_HANDLE *)PORT_Realloc(search->handles,  | 
2019  | 0  |                                                            sizeof(CK_OBJECT_HANDLE) * search->array_size);  | 
2020  | 0  |         if (search->handles == NULL) { | 
2021  | 0  |             return;  | 
2022  | 0  |         }  | 
2023  | 0  |     }  | 
2024  | 0  |     search->handles[search->size] = handle;  | 
2025  | 0  |     search->size++;  | 
2026  | 0  | }  | 
2027  |  |  | 
2028  |  | static CK_RV  | 
2029  |  | handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle,  | 
2030  |  |               CK_OBJECT_CLASS *objClass)  | 
2031  | 0  | { | 
2032  | 0  |     SFTKDBHandle *dbHandle = sftk_getDBForTokenObject(slot, handle);  | 
2033  | 0  |     CK_ATTRIBUTE objClassTemplate;  | 
2034  | 0  |     CK_RV crv;  | 
2035  |  | 
  | 
2036  | 0  |     *objClass = CKO_DATA;  | 
2037  | 0  |     objClassTemplate.type = CKA_CLASS;  | 
2038  | 0  |     objClassTemplate.pValue = objClass;  | 
2039  | 0  |     objClassTemplate.ulValueLen = sizeof(*objClass);  | 
2040  | 0  |     crv = sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1);  | 
2041  | 0  |     sftk_freeDB(dbHandle);  | 
2042  | 0  |     return crv;  | 
2043  | 0  | }  | 
2044  |  |  | 
2045  |  | SFTKObject *  | 
2046  |  | sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle)  | 
2047  | 0  | { | 
2048  | 0  |     SFTKObject *object = NULL;  | 
2049  | 0  |     PRBool hasLocks = PR_FALSE;  | 
2050  | 0  |     CK_RV crv;  | 
2051  |  | 
  | 
2052  | 0  |     object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0,  | 
2053  | 0  |                                     PR_FALSE);  | 
2054  | 0  |     if (object == NULL) { | 
2055  | 0  |         return NULL;  | 
2056  | 0  |     }  | 
2057  |  |  | 
2058  | 0  |     object->handle = handle;  | 
2059  |  |     /* every object must have a class, if we can't get it, the object  | 
2060  |  |      * doesn't exist */  | 
2061  | 0  |     crv = handleToClass(slot, handle, &object->objclass);  | 
2062  | 0  |     if (crv != CKR_OK) { | 
2063  | 0  |         goto loser;  | 
2064  | 0  |     }  | 
2065  | 0  |     object->slot = slot;  | 
2066  | 0  |     object->isFIPS = sftk_isFIPS(slot->slotID);  | 
2067  | 0  |     object->objectInfo = NULL;  | 
2068  | 0  |     object->infoFree = NULL;  | 
2069  | 0  |     if (!hasLocks) { | 
2070  | 0  |         object->refLock = PZ_NewLock(nssILockRefLock);  | 
2071  | 0  |     }  | 
2072  | 0  |     if (object->refLock == NULL) { | 
2073  | 0  |         goto loser;  | 
2074  | 0  |     }  | 
2075  | 0  |     object->refCount = 1;  | 
2076  |  | 
  | 
2077  | 0  |     return object;  | 
2078  | 0  | loser:  | 
2079  | 0  |     (void)sftk_DestroyObject(object);  | 
2080  | 0  |     return NULL;  | 
2081  | 0  | }  | 
2082  |  |  | 
2083  |  | SFTKTokenObject *  | 
2084  |  | sftk_convertSessionToToken(SFTKObject *obj)  | 
2085  | 0  | { | 
2086  | 0  |     SECItem *key;  | 
2087  | 0  |     SFTKSessionObject *so = (SFTKSessionObject *)obj;  | 
2088  | 0  |     SFTKTokenObject *to = sftk_narrowToTokenObject(obj);  | 
2089  | 0  |     SECStatus rv;  | 
2090  |  | 
  | 
2091  | 0  |     sftk_DestroySessionObjectData(so);  | 
2092  | 0  |     PZ_DestroyLock(so->attributeLock);  | 
2093  | 0  |     if (to == NULL) { | 
2094  | 0  |         return NULL;  | 
2095  | 0  |     }  | 
2096  | 0  |     sftk_tokenKeyLock(so->obj.slot);  | 
2097  | 0  |     key = sftk_lookupTokenKeyByHandle(so->obj.slot, so->obj.handle);  | 
2098  | 0  |     if (key == NULL) { | 
2099  | 0  |         sftk_tokenKeyUnlock(so->obj.slot);  | 
2100  | 0  |         return NULL;  | 
2101  | 0  |     }  | 
2102  | 0  |     rv = SECITEM_CopyItem(NULL, &to->dbKey, key);  | 
2103  | 0  |     sftk_tokenKeyUnlock(so->obj.slot);  | 
2104  | 0  |     if (rv == SECFailure) { | 
2105  | 0  |         return NULL;  | 
2106  | 0  |     }  | 
2107  |  |  | 
2108  | 0  |     return to;  | 
2109  | 0  | }  | 
2110  |  |  | 
2111  |  | SFTKSessionObject *  | 
2112  |  | sftk_narrowToSessionObject(SFTKObject *obj)  | 
2113  | 1.09M  | { | 
2114  | 1.09M  |     return !sftk_isToken(obj->handle) ? (SFTKSessionObject *)obj : NULL;  | 
2115  | 1.09M  | }  | 
2116  |  |  | 
2117  |  | SFTKTokenObject *  | 
2118  |  | sftk_narrowToTokenObject(SFTKObject *obj)  | 
2119  | 13.7k  | { | 
2120  | 13.7k  |     return sftk_isToken(obj->handle) ? (SFTKTokenObject *)obj : NULL;  | 
2121  | 13.7k  | }  | 
2122  |  |  | 
2123  |  | /* Constant time helper functions */  | 
2124  |  |  | 
2125  |  | /* sftk_CKRVToMask returns, in constant time, a mask value of  | 
2126  |  |  * all ones if rv == CKR_OK.  Otherwise it returns zero. */  | 
2127  |  | unsigned int  | 
2128  |  | sftk_CKRVToMask(CK_RV rv)  | 
2129  | 0  | { | 
2130  | 0  |     PR_STATIC_ASSERT(CKR_OK == 0);  | 
2131  | 0  |     return ~PORT_CT_NOT_ZERO(rv);  | 
2132  | 0  | }  | 
2133  |  |  | 
2134  |  | /* sftk_CheckCBCPadding checks, in constant time, the padding validity and  | 
2135  |  |  * accordingly sets the pad length. */  | 
2136  |  | CK_RV  | 
2137  |  | sftk_CheckCBCPadding(CK_BYTE_PTR pBuf, unsigned int bufLen,  | 
2138  |  |                      unsigned int blockSize, unsigned int *outPadSize)  | 
2139  | 0  | { | 
2140  | 0  |     PORT_Assert(outPadSize);  | 
2141  |  | 
  | 
2142  | 0  |     unsigned int padSize = (unsigned int)pBuf[bufLen - 1];  | 
2143  |  |  | 
2144  |  |     /* If padSize <= blockSize, set goodPad to all-1s and all-0s otherwise.*/  | 
2145  | 0  |     unsigned int goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(~(blockSize - padSize));  | 
2146  |  |     /* padSize should not be 0 */  | 
2147  | 0  |     goodPad &= PORT_CT_NOT_ZERO(padSize);  | 
2148  |  | 
  | 
2149  | 0  |     unsigned int i;  | 
2150  | 0  |     for (i = 0; i < blockSize; i++) { | 
2151  |  |         /* If i < padSize, set loopMask to all-1s and all-0s otherwise.*/  | 
2152  | 0  |         unsigned int loopMask = PORT_CT_DUPLICATE_MSB_TO_ALL(~(padSize - 1 - i));  | 
2153  |  |         /* Get the padding value (should be padSize) from buffer */  | 
2154  | 0  |         unsigned int padVal = pBuf[bufLen - 1 - i];  | 
2155  |  |         /* Update goodPad only if i < padSize */  | 
2156  | 0  |         goodPad &= PORT_CT_SEL(loopMask, ~(padVal ^ padSize), goodPad);  | 
2157  | 0  |     }  | 
2158  |  |  | 
2159  |  |     /* If any of the final padding bytes had the wrong value, one or more  | 
2160  |  |      * of the lower eight bits of |goodPad| will be cleared. We AND the  | 
2161  |  |      * bottom 8 bits together and duplicate the result to all the bits. */  | 
2162  | 0  |     goodPad &= goodPad >> 4;  | 
2163  | 0  |     goodPad &= goodPad >> 2;  | 
2164  | 0  |     goodPad &= goodPad >> 1;  | 
2165  | 0  |     goodPad <<= sizeof(goodPad) * 8 - 1;  | 
2166  | 0  |     goodPad = PORT_CT_DUPLICATE_MSB_TO_ALL(goodPad);  | 
2167  |  |  | 
2168  |  |     /* Set outPadSize to padSize or 0 */  | 
2169  | 0  |     *outPadSize = PORT_CT_SEL(goodPad, padSize, 0);  | 
2170  |  |     /* Return OK if the pad is valid */  | 
2171  | 0  |     return PORT_CT_SEL(goodPad, CKR_OK, CKR_ENCRYPTED_DATA_INVALID);  | 
2172  | 0  | }  | 
2173  |  |  | 
2174  |  | void  | 
2175  |  | sftk_EncodeInteger(PRUint64 integer, CK_ULONG num_bits, CK_BBOOL littleEndian,  | 
2176  |  |                    CK_BYTE_PTR output, CK_ULONG_PTR output_len)  | 
2177  | 0  | { | 
2178  | 0  |     if (output_len) { | 
2179  | 0  |         *output_len = (num_bits / 8);  | 
2180  | 0  |     }  | 
2181  |  | 
  | 
2182  | 0  |     PR_ASSERT(num_bits > 0 && num_bits <= 64 && (num_bits % 8) == 0);  | 
2183  |  | 
  | 
2184  | 0  |     if (littleEndian == CK_TRUE) { | 
2185  | 0  |         for (size_t offset = 0; offset < num_bits / 8; offset++) { | 
2186  | 0  |             output[offset] = (unsigned char)((integer >> (offset * 8)) & 0xFF);  | 
2187  | 0  |         }  | 
2188  | 0  |     } else { | 
2189  | 0  |         for (size_t offset = 0; offset < num_bits / 8; offset++) { | 
2190  | 0  |             PRUint64 shift = num_bits - (offset + 1) * 8;  | 
2191  | 0  |             output[offset] = (unsigned char)((integer >> shift) & 0xFF);  | 
2192  | 0  |         }  | 
2193  | 0  |     }  | 
2194  | 0  | }  | 
2195  |  |  | 
2196  |  | CK_FLAGS  | 
2197  |  | sftk_AttributeToFlags(CK_ATTRIBUTE_TYPE op)  | 
2198  | 1.13k  | { | 
2199  | 1.13k  |     CK_FLAGS flags = 0;  | 
2200  |  |  | 
2201  | 1.13k  |     switch (op) { | 
2202  | 158  |         case CKA_ENCRYPT:  | 
2203  | 158  |             flags = CKF_ENCRYPT;  | 
2204  | 158  |             break;  | 
2205  | 12  |         case CKA_DECRYPT:  | 
2206  | 12  |             flags = CKF_DECRYPT;  | 
2207  | 12  |             break;  | 
2208  | 2  |         case CKA_WRAP:  | 
2209  | 2  |             flags = CKF_WRAP;  | 
2210  | 2  |             break;  | 
2211  | 8  |         case CKA_UNWRAP:  | 
2212  | 8  |             flags = CKF_UNWRAP;  | 
2213  | 8  |             break;  | 
2214  | 0  |         case CKA_SIGN:  | 
2215  | 0  |             flags = CKF_SIGN;  | 
2216  | 0  |             break;  | 
2217  | 0  |         case CKA_SIGN_RECOVER:  | 
2218  | 0  |             flags = CKF_SIGN_RECOVER;  | 
2219  | 0  |             break;  | 
2220  | 0  |         case CKA_VERIFY:  | 
2221  | 0  |             flags = CKF_VERIFY;  | 
2222  | 0  |             break;  | 
2223  | 0  |         case CKA_VERIFY_RECOVER:  | 
2224  | 0  |             flags = CKF_VERIFY_RECOVER;  | 
2225  | 0  |             break;  | 
2226  | 0  |         case CKA_DERIVE:  | 
2227  | 0  |             flags = CKF_DERIVE;  | 
2228  | 0  |             break;  | 
2229  |  |         /* fake attribute to select digesting */  | 
2230  | 0  |         case CKA_DIGEST:  | 
2231  | 0  |             flags = CKF_DIGEST;  | 
2232  | 0  |             break;  | 
2233  | 634  |         case CKA_NSS_MESSAGE | CKA_ENCRYPT:  | 
2234  | 634  |             flags = CKF_MESSAGE_ENCRYPT;  | 
2235  | 634  |             break;  | 
2236  | 318  |         case CKA_NSS_MESSAGE | CKA_DECRYPT:  | 
2237  | 318  |             flags = CKF_MESSAGE_DECRYPT;  | 
2238  | 318  |             break;  | 
2239  | 0  |         case CKA_NSS_MESSAGE | CKA_SIGN:  | 
2240  | 0  |             flags = CKF_MESSAGE_SIGN;  | 
2241  | 0  |             break;  | 
2242  | 0  |         case CKA_NSS_MESSAGE | CKA_VERIFY:  | 
2243  | 0  |             flags = CKF_MESSAGE_VERIFY;  | 
2244  | 0  |             break;  | 
2245  | 0  |         default:  | 
2246  | 0  |             break;  | 
2247  | 1.13k  |     }  | 
2248  | 1.13k  |     return flags;  | 
2249  | 1.13k  | }  | 
2250  |  |  | 
2251  |  | /*  | 
2252  |  |  * ******************** Hash Utilities **************************  | 
2253  |  |  */  | 
2254  |  | /*  | 
2255  |  |  * Utility function for converting PSS/OAEP parameter types into  | 
2256  |  |  * HASH_HashTypes. Note: Only SHA family functions are defined in RFC 3447.  | 
2257  |  |  */  | 
2258  |  | HASH_HashType  | 
2259  |  | sftk_GetHashTypeFromMechanism(CK_MECHANISM_TYPE mech)  | 
2260  | 6.55k  | { | 
2261  | 6.55k  |     switch (mech) { | 
2262  | 0  |         case CKM_SHA_1:  | 
2263  | 0  |         case CKG_MGF1_SHA1:  | 
2264  | 0  |             return HASH_AlgSHA1;  | 
2265  | 0  |         case CKM_SHA224:  | 
2266  | 0  |         case CKG_MGF1_SHA224:  | 
2267  | 0  |             return HASH_AlgSHA224;  | 
2268  | 3.09k  |         case CKM_SHA256:  | 
2269  | 3.34k  |         case CKG_MGF1_SHA256:  | 
2270  | 3.34k  |             return HASH_AlgSHA256;  | 
2271  | 2.73k  |         case CKM_SHA384:  | 
2272  | 2.91k  |         case CKG_MGF1_SHA384:  | 
2273  | 2.91k  |             return HASH_AlgSHA384;  | 
2274  | 148  |         case CKM_SHA512:  | 
2275  | 296  |         case CKG_MGF1_SHA512:  | 
2276  | 296  |             return HASH_AlgSHA512;  | 
2277  | 0  |         default:  | 
2278  | 0  |             return HASH_AlgNULL;  | 
2279  | 6.55k  |     }  | 
2280  | 6.55k  | }  | 
2281  |  |  | 
2282  |  | #ifdef NSS_HAS_FIPS_INDICATORS  | 
2283  |  | /**************** FIPS Indicator Utilities *************************/  | 
2284  |  | /* sigh, we probably need a version of this in secutil so that both  | 
2285  |  |  * softoken and NSS can use it */  | 
2286  |  | static SECOidTag  | 
2287  |  | sftk_quickGetECCCurveOid(SFTKObject *source)  | 
2288  |  | { | 
2289  |  |     SFTKAttribute *attribute = sftk_FindAttribute(source, CKA_EC_PARAMS);  | 
2290  |  |     unsigned char *encoded;  | 
2291  |  |     int len;  | 
2292  |  |     SECItem oid;  | 
2293  |  |     SECOidTag tag;  | 
2294  |  |  | 
2295  |  |     if (attribute == NULL) { | 
2296  |  |         return SEC_OID_UNKNOWN;  | 
2297  |  |     }  | 
2298  |  |     encoded = attribute->attrib.pValue;  | 
2299  |  |     len = attribute->attrib.ulValueLen;  | 
2300  |  |     if ((len < 2) || (encoded[0] != SEC_ASN1_OBJECT_ID) ||  | 
2301  |  |         (len != encoded[1] + 2)) { | 
2302  |  |         sftk_FreeAttribute(attribute);  | 
2303  |  |         return SEC_OID_UNKNOWN;  | 
2304  |  |     }  | 
2305  |  |     oid.data = encoded + 2;  | 
2306  |  |     oid.len = len - 2;  | 
2307  |  |     tag = SECOID_FindOIDTag(&oid);  | 
2308  |  |     sftk_FreeAttribute(attribute);  | 
2309  |  |     return tag;  | 
2310  |  | }  | 
2311  |  |  | 
2312  |  | /* This function currently only returns valid lengths for  | 
2313  |  |  * FIPS approved ECC curves. If we want to make this generic  | 
2314  |  |  * in the future, that Curve determination can be done in  | 
2315  |  |  * the sftk_handleSpecial. Since it's currently only used  | 
2316  |  |  * in FIPS indicators, it's currently only compiled with  | 
2317  |  |  * the FIPS indicator code */  | 
2318  |  | static int  | 
2319  |  | sftk_getKeyLength(SFTKObject *source)  | 
2320  |  | { | 
2321  |  |     CK_KEY_TYPE keyType = CK_INVALID_HANDLE;  | 
2322  |  |     CK_ATTRIBUTE_TYPE keyAttribute;  | 
2323  |  |     CK_ULONG keyLength = 0;  | 
2324  |  |     SFTKAttribute *attribute;  | 
2325  |  |     CK_RV crv;  | 
2326  |  |  | 
2327  |  |     /* If we don't have a key, then it doesn't have a length.  | 
2328  |  |      * this may be OK (say we are hashing). The mech info will  | 
2329  |  |      * sort this out because algorithms which expect no keys  | 
2330  |  |      * will accept zero length for the keys */  | 
2331  |  |     if (source == NULL) { | 
2332  |  |         return 0;  | 
2333  |  |     }  | 
2334  |  |  | 
2335  |  |     crv = sftk_GetULongAttribute(source, CKA_KEY_TYPE, &keyType);  | 
2336  |  |     if (crv != CKR_OK) { | 
2337  |  |         /* sometimes we're passed a data object, in that case the  | 
2338  |  |          * key length is CKA_VALUE, which is the default */  | 
2339  |  |         keyType = CKK_INVALID_KEY_TYPE;  | 
2340  |  |     }  | 
2341  |  |     if (keyType == CKK_EC) { | 
2342  |  |         SECOidTag curve = sftk_quickGetECCCurveOid(source);  | 
2343  |  |         switch (curve) { | 
2344  |  |             case SEC_OID_CURVE25519:  | 
2345  |  |                 /* change when we start algorithm testing on curve25519 */  | 
2346  |  |                 return 0;  | 
2347  |  |             case SEC_OID_SECG_EC_SECP256R1:  | 
2348  |  |                 return 256;  | 
2349  |  |             case SEC_OID_SECG_EC_SECP384R1:  | 
2350  |  |                 return 384;  | 
2351  |  |             case SEC_OID_SECG_EC_SECP521R1:  | 
2352  |  |                 /* this is a lie, but it makes the table easier. We don't  | 
2353  |  |                  * have to have a double entry for every ECC mechanism */  | 
2354  |  |                 return 512;  | 
2355  |  |             default:  | 
2356  |  |                 break;  | 
2357  |  |         }  | 
2358  |  |         /* other curves aren't NIST approved, returning 0 will cause these  | 
2359  |  |          * curves to fail FIPS length criteria */  | 
2360  |  |         return 0;  | 
2361  |  |     }  | 
2362  |  |  | 
2363  |  |     switch (keyType) { | 
2364  |  |         case CKK_RSA:  | 
2365  |  |             keyAttribute = CKA_MODULUS;  | 
2366  |  |             break;  | 
2367  |  |         case CKK_DSA:  | 
2368  |  |         case CKK_DH:  | 
2369  |  |             keyAttribute = CKA_PRIME;  | 
2370  |  |             break;  | 
2371  |  |         default:  | 
2372  |  |             keyAttribute = CKA_VALUE;  | 
2373  |  |             break;  | 
2374  |  |     }  | 
2375  |  |     attribute = sftk_FindAttribute(source, keyAttribute);  | 
2376  |  |     if (attribute) { | 
2377  |  |         keyLength = attribute->attrib.ulValueLen * 8;  | 
2378  |  |         sftk_FreeAttribute(attribute);  | 
2379  |  |     }  | 
2380  |  |     return keyLength;  | 
2381  |  | }  | 
2382  |  |  | 
2383  |  | /*  | 
2384  |  |  * handle specialized FIPS semantics that are too complicated to  | 
2385  |  |  * handle with just a table. NOTE: this means any additional semantics  | 
2386  |  |  * would have to be coded here before they can be added to the table */  | 
2387  |  | static PRBool  | 
2388  |  | sftk_handleSpecial(SFTKSlot *slot, CK_MECHANISM *mech,  | 
2389  |  |                    SFTKFIPSAlgorithmList *mechInfo, SFTKObject *source)  | 
2390  |  | { | 
2391  |  |     switch (mechInfo->special) { | 
2392  |  |         case SFTKFIPSDH: { | 
2393  |  |             SECItem dhPrime;  | 
2394  |  |             const SECItem *dhSubPrime;  | 
2395  |  |             CK_RV crv = sftk_Attribute2SecItem(NULL, &dhPrime,  | 
2396  |  |                                                source, CKA_PRIME);  | 
2397  |  |             if (crv != CKR_OK) { | 
2398  |  |                 return PR_FALSE;  | 
2399  |  |             }  | 
2400  |  |             dhSubPrime = sftk_VerifyDH_Prime(&dhPrime, PR_TRUE);  | 
2401  |  |             SECITEM_ZfreeItem(&dhPrime, PR_FALSE);  | 
2402  |  |             return (dhSubPrime) ? PR_TRUE : PR_FALSE;  | 
2403  |  |         }  | 
2404  |  |         case SFTKFIPSNone:  | 
2405  |  |             return PR_FALSE;  | 
2406  |  |         case SFTKFIPSECC:  | 
2407  |  |             /* we've already handled the curve selection in the 'getlength'  | 
2408  |  |           * function */  | 
2409  |  |             return PR_TRUE;  | 
2410  |  |         case SFTKFIPSAEAD: { | 
2411  |  |             if (mech->ulParameterLen == 0) { | 
2412  |  |                 /* AEAD ciphers are only in FIPS mode if we are using the  | 
2413  |  |                  * MESSAGE interface. This takes an empty parameter  | 
2414  |  |                  * in the init function */  | 
2415  |  |                 return PR_TRUE;  | 
2416  |  |             }  | 
2417  |  |             return PR_FALSE;  | 
2418  |  |         }  | 
2419  |  |         case SFTKFIPSRSAPSS: { | 
2420  |  |             /* PSS salt must not be longer than the  underlying hash.  | 
2421  |  |              * We verify that the underlying hash of the  | 
2422  |  |              * parameters matches Hash of the combined hash mechanisms, so  | 
2423  |  |              * we don't need to look at the specific PSS mechanism */  | 
2424  |  |             CK_RSA_PKCS_PSS_PARAMS *pss = (CK_RSA_PKCS_PSS_PARAMS *)  | 
2425  |  |                                               mech->pParameter;  | 
2426  |  |             const SECHashObject *hashObj = NULL;  | 
2427  |  |             if (mech->ulParameterLen != sizeof(*pss)) { | 
2428  |  |                 return PR_FALSE;  | 
2429  |  |             }  | 
2430  |  |             /* we use the existing hash utilities to find the length of  | 
2431  |  |              * the hash */  | 
2432  |  |             hashObj = HASH_GetRawHashObject(sftk_GetHashTypeFromMechanism(  | 
2433  |  |                 pss->hashAlg));  | 
2434  |  |             if (hashObj == NULL) { | 
2435  |  |                 return PR_FALSE;  | 
2436  |  |             }  | 
2437  |  |             if (pss->sLen > hashObj->length) { | 
2438  |  |                 return PR_FALSE;  | 
2439  |  |             }  | 
2440  |  |             return PR_TRUE;  | 
2441  |  |         }  | 
2442  |  |         default:  | 
2443  |  |             break;  | 
2444  |  |     }  | 
2445  |  |     /* if we didn't understand the special processing, mark it non-fips */  | 
2446  |  |     return PR_FALSE;  | 
2447  |  | }  | 
2448  |  | #endif  | 
2449  |  |  | 
2450  |  | PRBool  | 
2451  |  | sftk_operationIsFIPS(SFTKSlot *slot, CK_MECHANISM *mech, CK_ATTRIBUTE_TYPE op,  | 
2452  |  |                      SFTKObject *source)  | 
2453  | 21.2k  | { | 
2454  | 21.2k  | #ifndef NSS_HAS_FIPS_INDICATORS  | 
2455  | 21.2k  |     return PR_FALSE;  | 
2456  |  | #else  | 
2457  |  |     int i;  | 
2458  |  |     CK_FLAGS opFlags;  | 
2459  |  |     CK_ULONG keyLength;  | 
2460  |  |  | 
2461  |  |     /* handle all the quick stuff first */  | 
2462  |  |     if (!sftk_isFIPS(slot->slotID)) { | 
2463  |  |         return PR_FALSE;  | 
2464  |  |     }  | 
2465  |  |     if (source && !source->isFIPS) { | 
2466  |  |         return PR_FALSE;  | 
2467  |  |     }  | 
2468  |  |     if (mech == NULL) { | 
2469  |  |         return PR_FALSE;  | 
2470  |  |     }  | 
2471  |  |  | 
2472  |  |     /* now get the calculated values */  | 
2473  |  |     opFlags = sftk_AttributeToFlags(op);  | 
2474  |  |     if (opFlags == 0) { | 
2475  |  |         return PR_FALSE;  | 
2476  |  |     }  | 
2477  |  |     keyLength = sftk_getKeyLength(source);  | 
2478  |  |  | 
2479  |  |     /* check against our algorithm array */  | 
2480  |  |     for (i = 0; i < SFTK_NUMBER_FIPS_ALGORITHMS; i++) { | 
2481  |  |         SFTKFIPSAlgorithmList *mechs = &sftk_fips_mechs[i];  | 
2482  |  |         /* if we match the number of records exactly, then we are an  | 
2483  |  |          * approved algorithm in the approved mode with an approved key */  | 
2484  |  |         if (((mech->mechanism == mechs->type) &&  | 
2485  |  |              (opFlags == (mechs->info.flags & opFlags)) &&  | 
2486  |  |              (keyLength <= mechs->info.ulMaxKeySize) &&  | 
2487  |  |              (keyLength >= mechs->info.ulMinKeySize) &&  | 
2488  |  |              ((keyLength - mechs->info.ulMinKeySize) % mechs->step) == 0) &&  | 
2489  |  |             ((mechs->special == SFTKFIPSNone) ||  | 
2490  |  |              sftk_handleSpecial(slot, mech, mechs, source))) { | 
2491  |  |             return PR_TRUE;  | 
2492  |  |         }  | 
2493  |  |     }  | 
2494  |  |     return PR_FALSE;  | 
2495  |  | #endif  | 
2496  | 21.2k  | }  | 
2497  |  |  | 
2498  |  | /*  | 
2499  |  |  * create the FIPS Validation objects. If the vendor  | 
2500  |  |  * doesn't supply an NSS_FIPS_MODULE_ID, at compile time,  | 
2501  |  |  * then we assumethis is an unvalidated module.  | 
2502  |  |  */  | 
2503  |  | CK_RV  | 
2504  |  | sftk_CreateValidationObjects(SFTKSlot *slot)  | 
2505  | 0  | { | 
2506  | 0  |     const char *module_id;  | 
2507  | 0  |     int module_id_len;  | 
2508  | 0  |     CK_RV crv = CKR_OK;  | 
2509  |  |     /* we currently use vendor specific values until the validation  | 
2510  |  |      * objects are approved for PKCS #11 v3.2. */  | 
2511  | 0  |     CK_OBJECT_CLASS cko_validation = CKO_NSS_VALIDATION;  | 
2512  | 0  |     CK_NSS_VALIDATION_TYPE ckv_fips = CKV_NSS_FIPS_140;  | 
2513  | 0  |     CK_VERSION fips_version = { 3, 0 }; /* FIPS-140-3 */ | 
2514  | 0  |     CK_ULONG fips_level = 1;            /* or 2 if you validated at level 2 */  | 
2515  |  | 
  | 
2516  | 0  | #ifndef NSS_FIPS_MODULE_ID  | 
2517  | 0  | #define NSS_FIPS_MODULE_ID "Generic NSS " SOFTOKEN_VERSION " Unvalidated"  | 
2518  | 0  | #endif  | 
2519  | 0  |     module_id = NSS_FIPS_MODULE_ID;  | 
2520  | 0  |     module_id_len = sizeof(NSS_FIPS_MODULE_ID) - 1;  | 
2521  | 0  |     SFTKObject *object;  | 
2522  |  | 
  | 
2523  | 0  |     object = sftk_NewObject(slot); /* fill in the handle later */  | 
2524  | 0  |     if (object == NULL) { | 
2525  | 0  |         return CKR_HOST_MEMORY;  | 
2526  | 0  |     }  | 
2527  | 0  |     object->isFIPS = PR_FALSE;  | 
2528  |  | 
  | 
2529  | 0  |     crv = sftk_AddAttributeType(object, CKA_CLASS,  | 
2530  | 0  |                                 &cko_validation, sizeof(cko_validation));  | 
2531  | 0  |     if (crv != CKR_OK) { | 
2532  | 0  |         goto loser;  | 
2533  | 0  |     }  | 
2534  | 0  |     crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_TYPE,  | 
2535  | 0  |                                 &ckv_fips, sizeof(ckv_fips));  | 
2536  | 0  |     if (crv != CKR_OK) { | 
2537  | 0  |         goto loser;  | 
2538  | 0  |     }  | 
2539  | 0  |     crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_VERSION,  | 
2540  | 0  |                                 &fips_version, sizeof(fips_version));  | 
2541  | 0  |     if (crv != CKR_OK) { | 
2542  | 0  |         goto loser;  | 
2543  | 0  |     }  | 
2544  | 0  |     crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_LEVEL,  | 
2545  | 0  |                                 &fips_level, sizeof(fips_level));  | 
2546  | 0  |     if (crv != CKR_OK) { | 
2547  | 0  |         goto loser;  | 
2548  | 0  |     }  | 
2549  | 0  |     crv = sftk_AddAttributeType(object, CKA_NSS_VALIDATION_MODULE_ID,  | 
2550  | 0  |                                 module_id, module_id_len);  | 
2551  | 0  |     if (crv != CKR_OK) { | 
2552  | 0  |         goto loser;  | 
2553  | 0  |     }  | 
2554  |  |  | 
2555  |  |     /* future, fill in validation certificate information from a supplied  | 
2556  |  |      * pointer to a config file */  | 
2557  | 0  |     object->handle = sftk_getNextHandle(slot);  | 
2558  | 0  |     object->slot = slot;  | 
2559  | 0  |     sftk_AddObject(&slot->moduleObjects, object);  | 
2560  | 0  | loser:  | 
2561  | 0  |     sftk_FreeObject(object);  | 
2562  | 0  |     return crv;  | 
2563  | 0  | }  |