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  * Copyright (c) 2018, Joyent, Inc.
  26  */
  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                 default:
  83                         /* should never be here */
  84                         return (CKR_ATTRIBUTE_VALUE_INVALID);
  85         }
  86         rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue(
  87             session->hSession, slot_object->hObject, &attr, 1);
  88         if (rv != CKR_OK) {
  89                 return (rv);
  90         }
  91 
  92 get_attr:
  93         rv = get_master_attributes_by_type(class, subtype,
  94             attributes, num_attributes);
  95 
  96         return (rv);
  97 }
  98 
  99 /*
 100  * get_master_attributes_by_template
 101  *
 102  * Returns an (statically allocated) set of object attributes, as determined by
 103  * the supplied object template. The template is only used to determine the
 104  * class/subclass of the object. The attributes are only initialized to
 105  * default values.
 106  */
 107 CK_RV
 108 get_master_attributes_by_template(
 109         CK_ATTRIBUTE *template, CK_ULONG template_size,
 110         generic_attr_t **attributes, size_t *num_attributes)
 111 {
 112         CK_OBJECT_CLASS class;
 113         CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION;
 114         boolean_t found;
 115 
 116         found = get_template_ulong(CKA_CLASS, template, template_size, &class);
 117         if (!found) {
 118                 return (CKR_TEMPLATE_INCOMPLETE);
 119         }
 120 
 121         switch (class) {
 122                 case CKO_CERTIFICATE:
 123                         found = get_template_ulong(CKA_CERTIFICATE_TYPE,
 124                             template, template_size, &subtype);
 125                         break;
 126                 case CKO_HW_FEATURE:
 127                         found = get_template_ulong(CKA_HW_FEATURE_TYPE,
 128                             template, template_size, &subtype);
 129                         break;
 130                 case CKO_PUBLIC_KEY:
 131                 case CKO_PRIVATE_KEY:
 132                 case CKO_SECRET_KEY:
 133                 case CKO_DOMAIN_PARAMETERS:
 134                         found = get_template_ulong(CKA_KEY_TYPE,
 135                             template, template_size, &subtype);
 136                         break;
 137                 case CKO_DATA:
 138                         /* CKO_DATA has no subtype, just pretend it is found  */
 139                         found = B_TRUE;
 140                         break;
 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                 explicit_bzero(attr->attribute.pValue,
 531                     attr->attribute.ulValueLen);
 532 
 533                 if (attr->isMalloced)
 534                         free(attr->attribute.pValue);
 535         }
 536 
 537         free(attributes);
 538 }
 539 
 540 
 541 /*
 542  * attribute_set_value
 543  *
 544  * Sets the value of the specified attribute. Any portion of the old value
 545  * which will not be overwritten by the new value is zeroed out.
 546  */
 547 CK_RV
 548 attribute_set_value(CK_ATTRIBUTE *new_attr,
 549         generic_attr_t *attributes, size_t num_attributes)
 550 {
 551         generic_attr_t *attr = NULL;
 552 
 553         if (new_attr == NULL)
 554                 return (CKR_TEMPLATE_INCOMPLETE);
 555         else if (new_attr->pValue == NULL) {
 556                 return (CKR_ATTRIBUTE_VALUE_INVALID);
 557         }
 558 
 559         find_attribute(new_attr->type, attributes, num_attributes, &attr);
 560         if (attr == NULL) {
 561                 return (CKR_ATTRIBUTE_TYPE_INVALID);
 562         }
 563 
 564         /* Store the new value. */
 565         if (attr->attribute.ulValueLen >= new_attr->ulValueLen) {
 566                 /* Existing storage is sufficient to store new value. */
 567 
 568                 /* bzero() out any data that won't be overwritten. */
 569                 explicit_bzero((char *)attr->attribute.pValue +
 570                     new_attr->ulValueLen,
 571                     attr->attribute.ulValueLen - new_attr->ulValueLen);
 572 
 573         } else if (new_attr->ulValueLen <= sizeof (attr->generic_data)) {
 574                 /* Use generic storage to avoid a malloc. */
 575 
 576                 explicit_bzero(attr->attribute.pValue,
 577                     attr->attribute.ulValueLen);
 578                 if (attr->isMalloced) {
 579                         /*
 580                          * If app sets a large value (triggering a malloc),
 581                          * then sets a tiny value, and finally again sets
 582                          * a large value (phew!) we could end up here.
 583                          *
 584                          * FUTURE?: Store the original malloc size, so that
 585                          * we can regrow the value up to the original size.
 586                          * This might avoid some heap churn for pathalogic
 587                          * applications.
 588                          */
 589                         free(attr->attribute.pValue);
 590                         attr->isMalloced = B_FALSE;
 591                 }
 592 
 593                 attr->attribute.pValue = attr->generic_data;
 594 
 595         } else {
 596                 /* Need to allocate storage for the new value. */
 597                 void *newStorage;
 598 
 599                 newStorage = malloc(new_attr->ulValueLen);
 600                 if (newStorage == NULL)
 601                         return (CKR_HOST_MEMORY);
 602                 bzero(attr->attribute.pValue, attr->attribute.ulValueLen);
 603                 attr->attribute.pValue = newStorage;
 604                 attr->isMalloced = B_TRUE;
 605         }
 606 
 607         (void) memcpy(attr->attribute.pValue, new_attr->pValue,
 608             new_attr->ulValueLen);
 609         attr->attribute.ulValueLen = new_attr->ulValueLen;
 610         attr->hasValueForClone = B_TRUE;
 611 
 612         return (CKR_OK);
 613 }
 614 
 615 
 616 /*
 617  * find_attribute
 618  *
 619  * Passes a pointer to the requested attribute, or NULL if not found.
 620  */
 621 static void
 622 find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes,
 623         size_t num_attributes, generic_attr_t **found_attribute)
 624 {
 625         generic_attr_t *attr;
 626         boolean_t found = B_FALSE;
 627         size_t i;
 628 
 629         /* Find the requested attribute. */
 630         for (i = 0, attr = attributes; i < num_attributes; i++, attr++) {
 631                 if (attr->attribute.type == attrtype) {
 632                         found = B_TRUE;
 633                         break;
 634                 }
 635         }
 636 
 637         *found_attribute = found ? attr : NULL;
 638 }
 639 
 640 
 641 /*
 642  * get_template_ulong
 643  *
 644  * Look for the specified ulong-size attribute, and retrieve its value. The
 645  * return value specifies if the attribute was found (or not).
 646  */
 647 boolean_t
 648 get_template_ulong(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
 649         CK_ULONG num_attributes, CK_ULONG *result)
 650 {
 651         boolean_t found = B_FALSE;
 652         CK_ULONG i;
 653 
 654         for (i = 0; i < num_attributes; i++) {
 655                 if (attributes[i].type == type) {
 656                         CK_ULONG *value = attributes[i].pValue;
 657 
 658                         *result = *value;
 659                         found = B_TRUE;
 660                         break;
 661                 }
 662         }
 663 
 664         return (found);
 665 }
 666 
 667 
 668 /*
 669  * get_template_boolean
 670  *
 671  * Look for the specified boolean attribute, and retrieve its value. The
 672  * return value specifies if the attribute was found (or not).
 673  */
 674 boolean_t
 675 get_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
 676         CK_ULONG num_attributes, boolean_t *result)
 677 {
 678         boolean_t found = B_FALSE;
 679         CK_ULONG i;
 680 
 681         for (i = 0; i < num_attributes; i++) {
 682                 if (attributes[i].type == type) {
 683                         CK_BBOOL *value = attributes[i].pValue;
 684 
 685                         if (*value == CK_FALSE)
 686                                 *result = B_FALSE;
 687                         else
 688                                 *result = B_TRUE;
 689 
 690                         found = B_TRUE;
 691                         break;
 692                 }
 693         }
 694 
 695         return (found);
 696 }
 697 
 698 /*
 699  * set_template_boolean
 700  *
 701  * Look for the specified boolean attribute, and set its value.
 702  *
 703  * if 'local' is true, it sets the pointer to the value in the template a new
 704  * location.  There should be no memory leak created by this because we are
 705  * only doing this to booleans which should not be malloc'ed.
 706  *
 707  * if 'local' is false, it sets its value.
 708  *
 709  * The return value specifies if the attribute was found (or not).
 710  */
 711 int
 712 set_template_boolean(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attributes,
 713         CK_ULONG num_attributes, boolean_t local, CK_BBOOL *value)
 714 {
 715         int i;
 716 
 717         for (i = 0; i < num_attributes; i++) {
 718                 if (attributes[i].type == type) {
 719                         if (local)
 720                                 attributes[i].pValue = value;
 721                         else
 722                                 *((CK_BBOOL *)attributes[i].pValue) = *value;
 723 
 724                         return (i);
 725                 }
 726         }
 727 
 728         return (-1);
 729 }