Home | History | Annotate | Download | only in common
      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 
     34 static void
     35 find_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  */
     45 CK_RV
     46 get_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 
     93 get_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  */
    108 CK_RV
    109 get_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  */
    161 CK_RV
    162 get_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  */
    382 CK_RV
    383 get_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  */
    445 CK_RV
    446 get_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  */
    515 void
    516 dealloc_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  */
    546 CK_RV
    547 attribute_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  */
    618 static void
    619 find_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  */
    644 boolean_t
    645 get_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  */
    671 boolean_t
    672 get_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  */
    708 int
    709 set_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