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