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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <string.h> 30 #include <stdlib.h> 31 #include <strings.h> 32 #include "metaGlobal.h" 33 #include "metaAttrMasters.h" 34 35 static void 36 find_attribute(CK_ATTRIBUTE_TYPE attrtype, generic_attr_t *attributes, 37 size_t num_attributes, generic_attr_t **found_attribute); 38 39 /* 40 * get_master_attributes_by_object 41 * 42 * Returns an (statically allocated) set of object attributes, as determined by 43 * class and keytype of the supplied object. The attributes are only 44 * initialized to default values. 45 */ 46 CK_RV 47 get_master_attributes_by_object(slot_session_t *session, 48 slot_object_t *slot_object, generic_attr_t **attributes, 49 size_t *num_attributes) 50 { 51 CK_RV rv; 52 CK_ATTRIBUTE attr; 53 CK_OBJECT_CLASS class; 54 CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION; 55 56 /* first get the class */ 57 attr.type = CKA_CLASS; 58 attr.pValue = &class; 59 attr.ulValueLen = sizeof (class); 60 rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue( 61 session->hSession, slot_object->hObject, &attr, 1); 62 if (rv != CKR_OK) { 63 return (rv); 64 } 65 66 attr.pValue = &subtype; 67 attr.ulValueLen = sizeof (subtype); 68 switch (class) { 69 case CKO_CERTIFICATE: 70 attr.type = CKA_CERTIFICATE_TYPE; 71 break; 72 case CKO_HW_FEATURE: 73 attr.type = CKA_HW_FEATURE_TYPE; 74 break; 75 case CKO_PUBLIC_KEY: 76 case CKO_PRIVATE_KEY: 77 case CKO_SECRET_KEY: 78 case CKO_DOMAIN_PARAMETERS: 79 attr.type = CKA_KEY_TYPE; 80 break; 81 case CKO_DATA: 82 goto get_attr; 83 break; 84 default: 85 /* should never be here */ 86 return (CKR_ATTRIBUTE_VALUE_INVALID); 87 } 88 rv = FUNCLIST(session->fw_st_id)->C_GetAttributeValue( 89 session->hSession, slot_object->hObject, &attr, 1); 90 if (rv != CKR_OK) { 91 return (rv); 92 } 93 94 get_attr: 95 rv = get_master_attributes_by_type(class, subtype, 96 attributes, num_attributes); 97 98 return (rv); 99 } 100 101 /* 102 * get_master_attributes_by_template 103 * 104 * Returns an (statically allocated) set of object attributes, as determined by 105 * the supplied object template. The template is only used to determine the 106 * class/subclass of the object. The attributes are only initialized to 107 * default values. 108 */ 109 CK_RV 110 get_master_attributes_by_template( 111 CK_ATTRIBUTE *template, CK_ULONG template_size, 112 generic_attr_t **attributes, size_t *num_attributes) 113 { 114 CK_OBJECT_CLASS class; 115 CK_ULONG subtype = CK_UNAVAILABLE_INFORMATION; 116 boolean_t found; 117 118 found = get_template_ulong(CKA_CLASS, template, template_size, &class); 119 if (!found) { 120 return (CKR_TEMPLATE_INCOMPLETE); 121 } 122 123 switch (class) { 124 case CKO_CERTIFICATE: 125 found = get_template_ulong(CKA_CERTIFICATE_TYPE, 126 template, template_size, &subtype); 127 break; 128 case CKO_HW_FEATURE: 129 found = get_template_ulong(CKA_HW_FEATURE_TYPE, 130 template, template_size, &subtype); 131 break; 132 case CKO_PUBLIC_KEY: 133 case CKO_PRIVATE_KEY: 134 case CKO_SECRET_KEY: 135 case CKO_DOMAIN_PARAMETERS: 136 found = get_template_ulong(CKA_KEY_TYPE, 137 template, template_size, &subtype); 138 break; 139 case CKO_DATA: 140 /* CKO_DATA has no subtype, just pretend it is found */ 141 found = B_TRUE; 142 default: 143 /* unknown object class */ 144 return (CKR_ATTRIBUTE_VALUE_INVALID); 145 } 146 147 if (!found) { 148 return (CKR_TEMPLATE_INCOMPLETE); 149 } 150 151 return (get_master_attributes_by_type(class, subtype, 152 attributes, num_attributes)); 153 } 154 155 /* 156 * get_master_template_by_type 157 * 158 * Returns an (statically allocated) set of object attributes, as determined 159 * by the specified class and subtype. The attributes are initialized to default 160 * values. 161 */ 162 CK_RV 163 get_master_template_by_type(CK_OBJECT_CLASS class, CK_ULONG subtype, 164 generic_attr_t **attributes, size_t *num_attributes) 165 { 166 generic_attr_t *master_template = NULL; 167 size_t master_template_size = 0; 168 169 switch (class) { 170 case CKO_HW_FEATURE: 171 switch (subtype) { 172 case CKO_HW_FEATURE: 173 master_template = (generic_attr_t *)OBJ_HW_CLOCK; 174 master_template_size = sizeof (OBJ_HW_CLOCK); 175 break; 176 177 case CKH_MONOTONIC_COUNTER: 178 master_template = (generic_attr_t *)OBJ_HW_MONOTONIC; 179 master_template_size = sizeof (OBJ_HW_MONOTONIC); 180 break; 181 182 default: 183 /* Unsupported. */ 184 break; 185 } 186 break; 187 188 case CKO_DATA: 189 /* Objects of this class have no subtype. */ 190 master_template = (generic_attr_t *)OBJ_DATA; 191 master_template_size = sizeof (OBJ_DATA); 192 break; 193 194 case CKO_CERTIFICATE: 195 switch (subtype) { 196 case CKC_X_509: 197 master_template = (generic_attr_t *)OBJ_CERT_X509; 198 master_template_size = sizeof (OBJ_CERT_X509); 199 break; 200 201 case CKC_X_509_ATTR_CERT: 202 master_template = (generic_attr_t *)OBJ_CERT_X509ATTR; 203 master_template_size = sizeof (OBJ_CERT_X509ATTR); 204 break; 205 206 default: 207 /* Unsupported. */ 208 break; 209 } 210 break; 211 212 case CKO_PUBLIC_KEY: 213 switch (subtype) { 214 case CKK_RSA: 215 master_template = (generic_attr_t *)OBJ_PUBKEY_RSA; 216 master_template_size = sizeof (OBJ_PUBKEY_RSA); 217 break; 218 219 case CKK_DSA: 220 master_template = (generic_attr_t *)OBJ_PUBKEY_DSA; 221 master_template_size = sizeof (OBJ_PUBKEY_DSA); 222 break; 223 224 case CKK_EC: 225 master_template = (generic_attr_t *)OBJ_PUBKEY_EC; 226 master_template_size = sizeof (OBJ_PUBKEY_EC); 227 break; 228 229 case CKK_DH: 230 master_template = (generic_attr_t *)OBJ_PUBKEY_DH; 231 master_template_size = sizeof (OBJ_PUBKEY_DH); 232 break; 233 234 case CKK_X9_42_DH: 235 master_template = (generic_attr_t *)OBJ_PUBKEY_X942DH; 236 master_template_size = sizeof (OBJ_PUBKEY_X942DH); 237 break; 238 239 case CKK_KEA: 240 master_template = (generic_attr_t *)OBJ_PUBKEY_KEA; 241 master_template_size = sizeof (OBJ_PUBKEY_KEA); 242 break; 243 244 default: 245 /* Unsupported. */ 246 break; 247 } 248 break; 249 250 case CKO_PRIVATE_KEY: 251 switch (subtype) { 252 case CKK_RSA: 253 master_template = (generic_attr_t *)OBJ_PRIVKEY_RSA; 254 master_template_size = sizeof (OBJ_PRIVKEY_RSA); 255 break; 256 257 case CKK_DSA: 258 master_template = (generic_attr_t *)OBJ_PRIVKEY_DSA; 259 master_template_size = sizeof (OBJ_PRIVKEY_DSA); 260 break; 261 262 case CKK_EC: 263 master_template = (generic_attr_t *)OBJ_PRIVKEY_EC; 264 master_template_size = sizeof (OBJ_PRIVKEY_EC); 265 break; 266 267 case CKK_DH: 268 master_template = (generic_attr_t *)OBJ_PRIVKEY_DH; 269 master_template_size = sizeof (OBJ_PRIVKEY_DH); 270 break; 271 272 case CKK_X9_42_DH: 273 master_template = (generic_attr_t *)OBJ_PRIVKEY_X942DH; 274 master_template_size = sizeof (OBJ_PRIVKEY_X942DH); 275 break; 276 277 case CKK_KEA: 278 master_template = (generic_attr_t *)OBJ_PRIVKEY_KEA; 279 master_template_size = sizeof (OBJ_PRIVKEY_KEA); 280 break; 281 282 default: 283 /* Unsupported. */ 284 break; 285 } 286 break; 287 288 case CKO_SECRET_KEY: 289 /* 290 * The only difference between secret keys is that some 291 * are valiable length (eg CKK_AES), while others are not 292 * (eg CKK_DES) -- and do not have a CKA_VALUE_LEN attribute. 293 * 294 * FUTURE(?): Consider using obj_seckey_withlen for unknown 295 * keytypes. This is the most likely choice, as new algorithms 296 * seem to support variable length keys. That's not the default 297 * now, because if people have implemented new key types with 298 * different attribute sets (like the mess of public/private 299 * key types), then incorrect behaviour would result. It's 300 * easier to relax this restriction than to tighten it (which 301 * would introduce a regression to anyone relying on this 302 * working for unknown key types). 303 * 304 */ 305 switch (subtype) { 306 case CKK_DES: 307 case CKK_DES2: 308 case CKK_DES3: 309 case CKK_IDEA: 310 case CKK_CDMF: 311 case CKK_SKIPJACK: 312 case CKK_BATON: 313 case CKK_JUNIPER: 314 master_template = (generic_attr_t *)OBJ_SECKEY; 315 master_template_size = sizeof (OBJ_SECKEY); 316 break; 317 318 case CKK_GENERIC_SECRET: 319 case CKK_RC2: 320 case CKK_RC4: 321 case CKK_RC5: 322 case CKK_AES: 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