1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <string.h>
29#include <stdlib.h>
30#include <strings.h>
31#include "metaGlobal.h"
32#include "metaAttrMasters.h"
33
34static void
35find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes,
36	size_t num_attributes, generic_attr_t **found_attribute);
37
38/*
39 * get_master_attributes_by_object
40 *
41 * Returns an (statically allocated) set of object attributes, as determined by
42 * class and keytype of the supplied object.  The attributes are only
43 * initialized to default values.
44 */
45CK_RV
46get_master_attributes_by_object(slot_session_t *session,
47    slot_object_t *slot_object, generic_attr_t **attributes,
48    size_t *num_attributes)
49{
50	CK_RV rv;
51	CK_ATTRIBUTE attr;
52	CK_OBJECT_CLASS class;
53	CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION;
54
55	/* first get the class */
56	attr.type = CKA_CLASS;
57	attr.pValue = &class;
58	attr.ulValueLen = sizeof (class);
59	rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue(
60	    session->hSession, slot_object->hObject, &attr, 1);
61	if (rv != CKR_OK) {
62		return (rv);
63	}
64
65	attr.pValue = &subtype;
66	attr.ulValueLen = sizeof (subtype);
67	switch (class) {
68		case CKO_CERTIFICATE:
69			attr.type = CKA_CERTIFICATE_TYPE;
70			break;
71		case CKO_HW_FEATURE:
72			attr.type = CKA_HW_FEATURE_TYPE;
73			break;
74		case CKO_PUBLIC_KEY:
75		case CKO_PRIVATE_KEY:
76		case CKO_SECRET_KEY:
77		case CKO_DOMAIN_PARAMETERS:
78			attr.type = CKA_KEY_TYPE;
79			break;
80		case CKO_DATA:
81			goto get_attr;
82			break;
83		default:
84			/* should never be here */
85			return (CKR_ATTRIBUTE_VALUE_INVALID);
86	}
87	rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue(
88	    session->hSession, slot_object->hObject, &attr, 1);
89	if (rv != CKR_OK) {
90		return (rv);
91	}
92
93get_attr:
94	rv = get_master_attributes_by_type(class, subtype,
95	    attributes, num_attributes);
96
97	return (rv);
98}
99
100/*
101 * get_master_attributes_by_template
102 *
103 * Returns an (statically allocated) set of object attributes, as determined by
104 * the supplied object template. The template is only used to determine the
105 * class/subclass of the object. The attributes are only initialized to
106 * default values.
107 */
108CK_RV
109get_master_attributes_by_template(
110	CK_ATTRIBUTE *template, CK_ULONG template_size,
111	generic_attr_t **attributes, size_t *num_attributes)
112{
113	CK_OBJECT_CLASS class;
114	CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION;
115	boolean_t found;
116
117	found = get_template_ulong(CKA_CLASS, template, template_size, &class);
118	if (!found) {
119		return (CKR_TEMPLATE_INCOMPLETE);
120	}
121
122	switch (class) {
123		case CKO_CERTIFICATE:
124			found = get_template_ulong(CKA_CERTIFICATE_TYPE,
125			    template, template_size, &subtype);
126			break;
127		case CKO_HW_FEATURE:
128			found = get_template_ulong(CKA_HW_FEATURE_TYPE,
129			    template, template_size, &subtype);
130			break;
131		case CKO_PUBLIC_KEY:
132		case CKO_PRIVATE_KEY:
133		case CKO_SECRET_KEY:
134		case CKO_DOMAIN_PARAMETERS:
135			found = get_template_ulong(CKA_KEY_TYPE,
136			    template, template_size, &subtype);
137			break;
138		case CKO_DATA:
139			/* CKO_DATA has no subtype, just pretend it is found  */
140			found = B_TRUE;
141		default:
142			/* unknown object class */
143			return (CKR_ATTRIBUTE_VALUE_INVALID);
144	}
145
146	if (!found) {
147		return (CKR_TEMPLATE_INCOMPLETE);
148	}
149
150	return (get_master_attributes_by_type(class, subtype,
151		attributes, num_attributes));
152}
153
154/*
155 * get_master_template_by_type
156 *
157 * Returns an (statically allocated) set of object attributes, as determined
158 * by the specified class and subtype. The attributes are initialized to default
159 * values.
160 */
161CK_RV
162get_master_template_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype,
163    generic_attr_t **attributes, size_t *num_attributes)
164{
165	generic_attr_t *master_template = NULL;
166	size_t master_template_size = 0;
167
168	switch (class) {
169	    case CKO_HW_FEATURE:
170		switch (subtype) {
171		    case CKO_HW_FEATURE:
172			master_template = (generic_attr_t *)OBJ_HW_CLOCK;
173			master_template_size = sizeof (OBJ_HW_CLOCK);
174			break;
175
176		    case CKH_MONOTONIC_COUNTER:
177			master_template = (generic_attr_t *)OBJ_HW_MONOTONIC;
178			master_template_size = sizeof (OBJ_HW_MONOTONIC);
179			break;
180
181		    default:
182			/* Unsupported. */
183			break;
184		}
185		break;
186
187	    case CKO_DATA:
188		/* Objects of this class have no subtype. */
189		master_template = (generic_attr_t *)OBJ_DATA;
190		master_template_size = sizeof (OBJ_DATA);
191		break;
192
193	    case CKO_CERTIFICATE:
194		switch (subtype) {
195		    case CKC_X_509:
196			master_template = (generic_attr_t *)OBJ_CERT_X509;
197			master_template_size = sizeof (OBJ_CERT_X509);
198			break;
199
200		    case CKC_X_509_ATTR_CERT:
201			master_template = (generic_attr_t *)OBJ_CERT_X509ATTR;
202			master_template_size = sizeof (OBJ_CERT_X509ATTR);
203			break;
204
205		    default:
206			/* Unsupported. */
207			break;
208		}
209		break;
210
211	    case CKO_PUBLIC_KEY:
212		switch (subtype) {
213		    case CKK_RSA:
214			master_template = (generic_attr_t *)OBJ_PUBKEY_RSA;
215			master_template_size = sizeof (OBJ_PUBKEY_RSA);
216			break;
217
218		    case CKK_DSA:
219			master_template = (generic_attr_t *)OBJ_PUBKEY_DSA;
220			master_template_size = sizeof (OBJ_PUBKEY_DSA);
221			break;
222
223		    case CKK_EC:
224			master_template = (generic_attr_t *)OBJ_PUBKEY_EC;
225			master_template_size = sizeof (OBJ_PUBKEY_EC);
226			break;
227
228		    case CKK_DH:
229			master_template = (generic_attr_t *)OBJ_PUBKEY_DH;
230			master_template_size = sizeof (OBJ_PUBKEY_DH);
231			break;
232
233		    case CKK_X9_42_DH:
234			master_template = (generic_attr_t *)OBJ_PUBKEY_X942DH;
235			master_template_size = sizeof (OBJ_PUBKEY_X942DH);
236			break;
237
238		    case CKK_KEA:
239			master_template = (generic_attr_t *)OBJ_PUBKEY_KEA;
240			master_template_size = sizeof (OBJ_PUBKEY_KEA);
241			break;
242
243		    default:
244			/* Unsupported. */
245			break;
246		}
247		break;
248
249	    case CKO_PRIVATE_KEY:
250		switch (subtype) {
251		    case CKK_RSA:
252			master_template = (generic_attr_t *)OBJ_PRIVKEY_RSA;
253			master_template_size = sizeof (OBJ_PRIVKEY_RSA);
254			break;
255
256		    case CKK_DSA:
257			master_template = (generic_attr_t *)OBJ_PRIVKEY_DSA;
258			master_template_size = sizeof (OBJ_PRIVKEY_DSA);
259			break;
260
261		    case CKK_EC:
262			master_template = (generic_attr_t *)OBJ_PRIVKEY_EC;
263			master_template_size = sizeof (OBJ_PRIVKEY_EC);
264			break;
265
266		    case CKK_DH:
267			master_template = (generic_attr_t *)OBJ_PRIVKEY_DH;
268			master_template_size = sizeof (OBJ_PRIVKEY_DH);
269			break;
270
271		    case CKK_X9_42_DH:
272			master_template = (generic_attr_t *)OBJ_PRIVKEY_X942DH;
273			master_template_size = sizeof (OBJ_PRIVKEY_X942DH);
274			break;
275
276		    case CKK_KEA:
277			master_template = (generic_attr_t *)OBJ_PRIVKEY_KEA;
278			master_template_size = sizeof (OBJ_PRIVKEY_KEA);
279			break;
280
281		    default:
282			/* Unsupported. */
283			break;
284		}
285		break;
286
287	    case CKO_SECRET_KEY:
288		/*
289		 * The only difference between secret keys is that some
290		 * are valiable length (eg CKK_AES), while others are not
291		 * (eg CKK_DES) -- and do not have a CKA_VALUE_LEN attribute.
292		 *
293		 * FUTURE(?): Consider using obj_seckey_withlen for unknown
294		 * keytypes. This is the most likely choice, as new algorithms
295		 * seem to support variable length keys. That's not the default
296		 * now, because if people have implemented new key types with
297		 * different attribute sets (like the mess of public/private
298		 * key types), then incorrect behaviour would result. It's
299		 * easier to relax this restriction than to tighten it (which
300		 * would introduce a regression to anyone relying on this
301		 * working for unknown key types).
302		 *
303		 */
304		switch (subtype) {
305		    case CKK_DES:
306		    case CKK_DES2:
307		    case CKK_DES3:
308		    case CKK_IDEA:
309		    case CKK_CDMF:
310		    case CKK_SKIPJACK:
311		    case CKK_BATON:
312		    case CKK_JUNIPER:
313			master_template = (generic_attr_t *)OBJ_SECKEY;
314			master_template_size = sizeof (OBJ_SECKEY);
315			break;
316
317		    case CKK_GENERIC_SECRET:
318		    case CKK_RC2:
319		    case CKK_RC4:
320		    case CKK_RC5:
321		    case CKK_AES:
322		    case CKK_BLOWFISH:
323		    case CKK_CAST:
324		    case CKK_CAST3:
325		    case CKK_CAST128:
326			master_template = (generic_attr_t *)OBJ_SECKEY_WITHLEN;
327			master_template_size = sizeof (OBJ_SECKEY_WITHLEN);
328			break;
329
330		    default:
331			/* Unsupported. */
332			break;
333		}
334		break;
335
336	    case CKO_DOMAIN_PARAMETERS:
337		switch (subtype) {
338		    case CKK_DSA:
339			master_template = (generic_attr_t *)OBJ_DOM_DSA;
340			master_template_size = sizeof (OBJ_DOM_DSA);
341			break;
342
343		    case CKK_DH:
344			master_template = (generic_attr_t *)OBJ_DOM_DH;
345			master_template_size = sizeof (OBJ_DOM_DH);
346			break;
347
348		    case CKK_X9_42_DH:
349			master_template = (generic_attr_t *)OBJ_DOM_X942DH;
350			master_template_size = sizeof (OBJ_DOM_X942DH);
351			break;
352
353		    default:
354			/* Unsupported. */
355			break;
356		}
357		break;
358
359	    default:
360		/* Unsupported. */
361		break;
362	}
363
364	/* Requested object is unknown or invalid. */
365	if (master_template == NULL)
366		return (CKR_ATTRIBUTE_VALUE_INVALID);
367	else {
368		*attributes = master_template;
369		*num_attributes = master_template_size;
370		return (CKR_OK);
371	}
372}
373
374
375/*
376 * get_master_attributes_by_type
377 *
378 * Returns an (statically allocated) set of object attributes, as determined by
379 * the specified class and subtype. The attributes are initialized to default
380 * values.
381 */
382CK_RV
383get_master_attributes_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype,
384	generic_attr_t **attributes, size_t *num_attributes)
385{
386	CK_RV rv;
387	generic_attr_t *master_template = NULL;
388	generic_attr_t *new_attributes;
389	size_t i, num_new_attributes, master_template_size = 0;
390
391	/* Determine the appropriate master template needed. */
392	rv = get_master_template_by_type(class, subtype,
393		&master_template, &master_template_size);
394	if (rv != CKR_OK)
395		return (rv);
396
397	/* Duplicate the master template. */
398	new_attributes = malloc(master_template_size);
399	if (new_attributes == NULL)
400		return (CKR_HOST_MEMORY);
401
402	(void) memcpy(new_attributes, master_template, master_template_size);
403	num_new_attributes = master_template_size / sizeof (generic_attr_t);
404
405	/* Set the pointer in the appropriate storage area. */
406	for (i = 0; i < num_new_attributes; i++) {
407		generic_attr_t *attr;
408
409		attr = new_attributes + i;
410
411		switch (attr->attribute.ulValueLen) {
412			case (sizeof (CK_ULONG)):
413				attr->attribute.pValue = &attr->generic_ulong;
414				break;
415			case (sizeof (CK_BBOOL)):
416				attr->attribute.pValue = &attr->generic_bbool;
417				break;
418			default:
419				attr->attribute.pValue = attr->generic_data;
420				break;
421		}
422
423	}
424
425	/* Secret keys share a common template, so set the key type here. */
426	if (class == CKO_SECRET_KEY) {
427		/* Keytype / subtype is always the second attribute. */
428		new_attributes[1].generic_ulong = subtype;
429	}
430
431	*attributes = new_attributes;
432	*num_attributes = num_new_attributes;
433
434	return (CKR_OK);
435}
436
437
438/*
439 * get_master_attributes_by_duplication
440 *
441 * Returns an (statically allocated) set of object attributes, as copied from an
442 * existing set of attributes. The new attributes inherit the values from
443 * the old attributes.
444 */
445CK_RV
446get_master_attributes_by_duplication(
447	generic_attr_t *src_attrs, size_t num_src_attrs,
448	generic_attr_t **dst_attrs, size_t *num_dst_attrs)
449{
450	CK_RV rv = CKR_OK;
451	generic_attr_t *new_attrs, *src, *dst;
452	size_t i;
453
454	new_attrs = malloc(sizeof (generic_attr_t) * num_src_attrs);
455	if (new_attrs == NULL)
456		return (CKR_HOST_MEMORY);
457
458	for (i = 0; i < num_src_attrs; i++) {
459		src = src_attrs + i;
460		dst = new_attrs + i;
461
462		*dst = *src;
463
464		/* Adjust pointers in dst so that they don't point to src. */
465
466		if (src->isMalloced) {
467			dst->attribute.pValue =
468				malloc(src->attribute.ulValueLen);
469
470			if (dst->attribute.pValue == NULL) {
471				/*
472				 * Continue on error, so that the cleanup
473				 * routine doesn't see pointers to src_attrs.
474				 */
475				dst->attribute.ulValueLen = 0;
476				rv = CKR_HOST_MEMORY;
477				continue;
478			}
479		} else if (src->attribute.pValue == &src->generic_bbool) {
480			dst->attribute.pValue = &dst->generic_bbool;
481		} else if (src->attribute.pValue == &src->generic_ulong) {
482			dst->attribute.pValue = &dst->generic_ulong;
483		} else if (src->attribute.pValue == &src->generic_data) {
484			dst->attribute.pValue = &dst->generic_data;
485		} else {
486			/* This shouldn't happen. */
487			dst->attribute.pValue = NULL;
488			dst->attribute.ulValueLen = 0;
489			rv = CKR_GENERAL_ERROR;
490			num_src_attrs = i + 1;
491			break;
492		}
493
494		(void) memcpy(dst->attribute.pValue, src->attribute.pValue,
495			src->attribute.ulValueLen);
496	}
497
498	if (rv != CKR_OK) {
499		dealloc_attributes(new_attrs, num_src_attrs);
500	} else {
501		*dst_attrs = new_attrs;
502		*num_dst_attrs = num_src_attrs;
503	}
504
505	return (rv);
506}
507
508
509/*
510 * dealloc_attributes
511 *
512 * Deallocates the storage used for a set of attributes. The attribute
513 * values are zeroed out before being free'd.
514 */
515void
516dealloc_attributes(generic_attr_t *attributes, size_t num_attributes)
517{
518	size_t i;
519	generic_attr_t *attr;
520
521	for (i = 0; i < num_attributes; i++) {
522		attr = attributes + i;
523
524		/*
525		 * Zero-out any attribute values. We could do this just for
526		 * attributes with isSensitive == True, but it's not much
527		 * extra work to just do them all. [Most attributes are just
528		 * 1 or 4 bytes]
529		 */
530		bzero(attr->attribute.pValue, attr->attribute.ulValueLen);
531
532		if (attr->isMalloced)
533			free(attr->attribute.pValue);
534	}
535
536	free(attributes);
537}
538
539
540/*
541 * attribute_set_value
542 *
543 * Sets the value of the specified attribute. Any portion of the old value
544 * which will not be overwritten by the new value is zeroed out.
545 */
546CK_RV
547attribute_set_value(CK_ATTRIBUTE *new_attr,
548	generic_attr_t *attributes, size_t num_attributes)
549{
550	generic_attr_t *attr = NULL;
551
552	if (new_attr == NULL)
553		return (CKR_TEMPLATE_INCOMPLETE);
554	else if (new_attr->pValue == NULL) {
555		return (CKR_ATTRIBUTE_VALUE_INVALID);
556	}
557
558	find_attribute(new_attr->type, attributes, num_attributes, &attr);
559	if (attr == NULL) {
560		return (CKR_ATTRIBUTE_TYPE_INVALID);
561	}
562
563	/* Store the new value. */
564	if (attr->attribute.ulValueLen >= new_attr->ulValueLen) {
565		/* Existing storage is sufficient to store new value. */
566
567		/* bzero() out any data that won't be overwritten. */
568		bzero((char *)attr->attribute.pValue + new_attr->ulValueLen,
569			attr->attribute.ulValueLen - new_attr->ulValueLen);
570
571	} else if (new_attr->ulValueLen <= sizeof (attr->generic_data)) {
572		/* Use generic storage to avoid a malloc. */
573
574		bzero(attr->attribute.pValue, attr->attribute.ulValueLen);
575		if (attr->isMalloced) {
576			/*
577			 * If app sets a large value (triggering a malloc),
578			 * then sets a tiny value, and finally again sets
579			 * a large value (phew!) we could end up here.
580			 *
581			 * FUTURE?: Store the original malloc size, so that
582			 * we can regrow the value up to the original size.
583			 * This might avoid some heap churn for pathalogic
584			 * applications.
585			 */
586			free(attr->attribute.pValue);
587			attr->isMalloced = B_FALSE;
588		}
589
590		attr->attribute.pValue = attr->generic_data;
591
592	} else {
593		/* Need to allocate storage for the new value. */
594		void *newStorage;
595
596		newStorage = malloc(new_attr->ulValueLen);
597		if (newStorage == NULL)
598			return (CKR_HOST_MEMORY);
599		bzero(attr->attribute.pValue, attr->attribute.ulValueLen);
600		attr->attribute.pValue = newStorage;
601		attr->isMalloced = B_TRUE;
602	}
603
604	(void) memcpy(attr->attribute.pValue, new_attr->pValue,
605		new_attr->ulValueLen);
606	attr->attribute.ulValueLen = new_attr->ulValueLen;
607	attr->hasValueForClone = B_TRUE;
608
609	return (CKR_OK);
610}
611
612
613/*
614 * find_attribute
615 *
616 * Passes a pointer to the requested attribute, or NULL if not found.
617 */
618static void
619find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes,
620	size_t num_attributes, generic_attr_t **found_attribute)
621{
622	generic_attr_t *attr;
623	boolean_t found = B_FALSE;
624	size_t i;
625
626	/* Find the requested attribute. */
627	for (i = 0, attr = attributes; i < num_attributes; i++, attr++) {
628		if (attr->attribute.type == attrtype) {
629			found = B_TRUE;
630			break;
631		}
632	}
633
634	*found_attribute = found ? attr : NULL;
635}
636
637
638/*
639 * get_template_ulong
640 *
641 * Look for the specified ulong-size attribute, and retrieve its value. The
642 * return value specifies if the attribute was found (or not).
643 */
644boolean_t
645get_template_ulong(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
646	CK_ULONG num_attributes, CK_ULONG *result)
647{
648	boolean_t found = B_FALSE;
649	CK_ULONG i;
650
651	for (i = 0; i < num_attributes; i++) {
652		if (attributes[i].type == type) {
653			CK_ULONG *value = attributes[i].pValue;
654
655			*result = *value;
656			found = B_TRUE;
657			break;
658		}
659	}
660
661	return (found);
662}
663
664
665/*
666 * get_template_boolean
667 *
668 * Look for the specified boolean attribute, and retrieve its value. The
669 * return value specifies if the attribute was found (or not).
670 */
671boolean_t
672get_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
673	CK_ULONG num_attributes, boolean_t *result)
674{
675	boolean_t found = B_FALSE;
676	CK_ULONG i;
677
678	for (i = 0; i < num_attributes; i++) {
679		if (attributes[i].type == type) {
680			CK_BBOOL *value = attributes[i].pValue;
681
682			if (*value == CK_FALSE)
683				*result = B_FALSE;
684			else
685				*result = B_TRUE;
686
687			found = B_TRUE;
688			break;
689		}
690	}
691
692	return (found);
693}
694
695/*
696 * set_template_boolean
697 *
698 * Look for the specified boolean attribute, and set its value.
699 *
700 * if 'local' is true, it sets the pointer to the value in the template a new
701 * location.  There should be no memory leak created by this because we are
702 * only doing this to booleans which should not be malloc'ed.
703 *
704 * if 'local' is false, it sets its value.
705 *
706 * The return value specifies if the attribute was found (or not).
707 */
708int
709set_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
710	CK_ULONG num_attributes, boolean_t local, CK_BBOOL *value)
711{
712	int i;
713
714	for (i = 0; i < num_attributes; i++) {
715		if (attributes[i].type == type) {
716			if (local)
717				attributes[i].pValue = value;
718			else
719				*((CK_BBOOL *)attributes[i].pValue) = *value;
720
721			return (i);
722		}
723	}
724
725	return (-1);
726}
727