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