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