Mercurial > illumos > illumos-gate
view usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c @ 12720:3db6e0082404
PSARC 2010/195 PKCS11 KMS Provider
6944296 Solaris needs a PKCS#11 provider to allow access to KMS keystore functionality
author | Wyllys Ingersoll <Wyllys.Ingersoll@Sun.COM> |
---|---|
date | Mon, 28 Jun 2010 16:04:11 -0700 |
parents | |
children | e5889df1eaac |
line wrap: on
line source
/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <stdlib.h> #include <string.h> #include <security/cryptoki.h> #include <sys/crypto/common.h> #include <aes_impl.h> #include "kmsGlobal.h" #include "kmsObject.h" #include "kmsSession.h" #include "kmsSlot.h" /* * This attribute table is used by the kms_lookup_attr() * to validate the attributes. */ CK_ATTRIBUTE_TYPE attr_map[] = { CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, CKA_START_DATE, CKA_END_DATE, CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS, CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, CKA_HAS_RESET }; /* * attributes that exists only in secret key objects * Note: some attributes may also exist in one or two * other object classes, but they are also listed * because not all object have them. */ CK_ATTRIBUTE_TYPE SECRET_KEY_ATTRS[] = { CKA_VALUE_LEN, CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_VERIFY, CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE }; /* * Validate the attribute by using binary search algorithm. */ CK_RV kms_lookup_attr(CK_ATTRIBUTE_TYPE type) { size_t lower, middle, upper; lower = 0; upper = (sizeof (attr_map) / sizeof (CK_ATTRIBUTE_TYPE)) - 1; while (lower <= upper) { /* Always starts from middle. */ middle = (lower + upper) / 2; if (type > attr_map[middle]) { /* Adjust the lower bound to upper half. */ lower = middle + 1; continue; } if (type == attr_map[middle]) { /* Found it. */ return (CKR_OK); } if (type < attr_map[middle]) { /* Adjust the upper bound to lower half. */ upper = middle - 1; continue; } } /* Failed to find the matching attribute from the attribute table. */ return (CKR_ATTRIBUTE_TYPE_INVALID); } /* * Validate the attribute by using the following search algorithm: * * 1) Search for the most frequently used attributes first. * 2) If not found, search for the usage-purpose attributes - these * attributes have dense set of values, therefore compiler will * optimize it with a branch table and branch to the appropriate * case. * 3) If still not found, use binary search for the rest of the * attributes in the attr_map[] table. */ CK_RV kms_validate_attr(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, CK_OBJECT_CLASS *class) { CK_ULONG i; CK_RV rv = CKR_OK; for (i = 0; i < ulAttrNum; i++) { /* First tier search */ switch (template[i].type) { case CKA_CLASS: *class = *((CK_OBJECT_CLASS*)template[i].pValue); break; case CKA_TOKEN: break; case CKA_KEY_TYPE: break; case CKA_VALUE: break; case CKA_VALUE_LEN: break; case CKA_VALUE_BITS: break; default: /* Second tier search */ switch (template[i].type) { case CKA_ENCRYPT: break; case CKA_DECRYPT: break; case CKA_WRAP: break; case CKA_UNWRAP: break; case CKA_SIGN: break; case CKA_SIGN_RECOVER: break; case CKA_VERIFY: break; case CKA_VERIFY_RECOVER: break; case CKA_DERIVE: break; default: /* Third tier search */ rv = kms_lookup_attr(template[i].type); if (rv != CKR_OK) return (rv); break; } break; } } return (rv); } /* * Clean up and release all the storage in the extra attribute list * of an object. */ void kms_cleanup_extra_attr(kms_object_t *object_p) { CK_ATTRIBUTE_INFO_PTR extra_attr; CK_ATTRIBUTE_INFO_PTR tmp; if (object_p == NULL) return; extra_attr = object_p->extra_attrlistp; while (extra_attr) { tmp = extra_attr->next; if (extra_attr->attr.pValue) /* * All extra attributes in the extra attribute * list have pValue points to the value of the * attribute (with simple byte array type). * Free the storage for the value of the attribute. */ free(extra_attr->attr.pValue); /* Free the storage for the attribute_info struct. */ free(extra_attr); extra_attr = tmp; } object_p->extra_attrlistp = NULL; } /* * Create the attribute_info struct to hold the object's attribute, * and add it to the extra attribute list of an object. */ CK_RV kms_add_extra_attr(CK_ATTRIBUTE_PTR template, kms_object_t *object_p) { CK_ATTRIBUTE_INFO_PTR attrp; /* Allocate the storage for the attribute_info struct. */ attrp = calloc(1, sizeof (attribute_info_t)); if (attrp == NULL) { return (CKR_HOST_MEMORY); } /* Set up attribute_info struct. */ attrp->attr.type = template->type; attrp->attr.ulValueLen = template->ulValueLen; if ((template->pValue != NULL) && (template->ulValueLen > 0)) { /* Allocate storage for the value of the attribute. */ attrp->attr.pValue = malloc(template->ulValueLen); if (attrp->attr.pValue == NULL) { free(attrp); return (CKR_HOST_MEMORY); } (void) memcpy(attrp->attr.pValue, template->pValue, template->ulValueLen); } else { attrp->attr.pValue = NULL; } /* Insert the new attribute in front of extra attribute list. */ if (object_p->extra_attrlistp == NULL) { object_p->extra_attrlistp = attrp; attrp->next = NULL; } else { attrp->next = object_p->extra_attrlistp; object_p->extra_attrlistp = attrp; } return (CKR_OK); } /* * Copy the attribute_info struct from the old object to a new attribute_info * struct, and add that new struct to the extra attribute list of the new * object. */ CK_RV kms_copy_extra_attr(CK_ATTRIBUTE_INFO_PTR old_attrp, kms_object_t *object_p) { CK_ATTRIBUTE_INFO_PTR attrp; /* Allocate attribute_info struct. */ attrp = calloc(1, sizeof (attribute_info_t)); if (attrp == NULL) { return (CKR_HOST_MEMORY); } attrp->attr.type = old_attrp->attr.type; attrp->attr.ulValueLen = old_attrp->attr.ulValueLen; if ((old_attrp->attr.pValue != NULL) && (old_attrp->attr.ulValueLen > 0)) { attrp->attr.pValue = malloc(old_attrp->attr.ulValueLen); if (attrp->attr.pValue == NULL) { free(attrp); return (CKR_HOST_MEMORY); } (void) memcpy(attrp->attr.pValue, old_attrp->attr.pValue, old_attrp->attr.ulValueLen); } else { attrp->attr.pValue = NULL; } /* Insert the new attribute in front of extra attribute list */ if (object_p->extra_attrlistp == NULL) { object_p->extra_attrlistp = attrp; attrp->next = NULL; } else { attrp->next = object_p->extra_attrlistp; object_p->extra_attrlistp = attrp; } return (CKR_OK); } /* * Get the attribute triple from the extra attribute list in the object * (if the specified attribute type is found), and copy it to a template. * Note the type of the attribute to be copied is specified by the template, * and the storage is pre-allocated for the atrribute value in the template * for doing the copy. */ CK_RV get_extra_attr_from_object(kms_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_ATTRIBUTE_INFO_PTR extra_attr; CK_ATTRIBUTE_TYPE type = template->type; extra_attr = object_p->extra_attrlistp; while (extra_attr) { if (type == extra_attr->attr.type) { /* Found it. */ break; } else { /* Does not match, try next one. */ extra_attr = extra_attr->next; } } if (extra_attr == NULL) { /* A valid but un-initialized attribute. */ template->ulValueLen = 0; return (CKR_OK); } /* * We found the attribute in the extra attribute list. */ if (template->pValue == NULL) { template->ulValueLen = extra_attr->attr.ulValueLen; return (CKR_OK); } if (template->ulValueLen >= extra_attr->attr.ulValueLen) { /* * The buffer provided by the application is large * enough to hold the value of the attribute. */ (void) memcpy(template->pValue, extra_attr->attr.pValue, extra_attr->attr.ulValueLen); template->ulValueLen = extra_attr->attr.ulValueLen; return (CKR_OK); } else { /* * The buffer provided by the application does * not have enough space to hold the value. */ template->ulValueLen = (CK_ULONG)-1; return (CKR_BUFFER_TOO_SMALL); } } /* * Modify the attribute triple in the extra attribute list of the object * if the specified attribute type is found. Otherwise, just add it to * list. */ CK_RV set_extra_attr_to_object(kms_object_t *object_p, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR template) { CK_ATTRIBUTE_INFO_PTR extra_attr; extra_attr = object_p->extra_attrlistp; while (extra_attr) { if (type == extra_attr->attr.type) { /* Found it. */ break; } else { /* Does not match, try next one. */ extra_attr = extra_attr->next; } } if (extra_attr == NULL) { /* * This attribute is a new one, go ahead adding it to * the extra attribute list. */ return (kms_add_extra_attr(template, object_p)); } /* We found the attribute in the extra attribute list. */ if ((template->pValue != NULL) && (template->ulValueLen > 0)) { if (template->ulValueLen > extra_attr->attr.ulValueLen) { /* The old buffer is too small to hold the new value. */ if (extra_attr->attr.pValue != NULL) /* Free storage for the old attribute value. */ free(extra_attr->attr.pValue); /* Allocate storage for the new attribute value. */ extra_attr->attr.pValue = malloc(template->ulValueLen); if (extra_attr->attr.pValue == NULL) { return (CKR_HOST_MEMORY); } } /* Replace the attribute with new value. */ extra_attr->attr.ulValueLen = template->ulValueLen; (void) memcpy(extra_attr->attr.pValue, template->pValue, template->ulValueLen); } else { extra_attr->attr.pValue = NULL; } return (CKR_OK); } /* * Copy the boolean data type attribute value from an object for the * specified attribute to the template. */ CK_RV get_bool_attr_from_object(kms_object_t *object_p, CK_ULONG bool_flag, CK_ATTRIBUTE_PTR template) { if (template->pValue == NULL) { template->ulValueLen = sizeof (CK_BBOOL); return (CKR_OK); } if (template->ulValueLen >= sizeof (CK_BBOOL)) { /* * The buffer provided by the application is large * enough to hold the value of the attribute. */ if (object_p->bool_attr_mask & bool_flag) { *((CK_BBOOL *)template->pValue) = B_TRUE; } else { *((CK_BBOOL *)template->pValue) = B_FALSE; } template->ulValueLen = sizeof (CK_BBOOL); return (CKR_OK); } else { /* * The buffer provided by the application does * not have enough space to hold the value. */ template->ulValueLen = (CK_ULONG)-1; return (CKR_BUFFER_TOO_SMALL); } } /* * Set the boolean data type attribute value in the object. */ CK_RV set_bool_attr_to_object(kms_object_t *object_p, CK_ULONG bool_flag, CK_ATTRIBUTE_PTR template) { if (*(CK_BBOOL *)template->pValue) object_p->bool_attr_mask |= bool_flag; else object_p->bool_attr_mask &= ~bool_flag; return (CKR_OK); } /* * Copy the CK_ULONG data type attribute value from an object to the * template. */ CK_RV get_ulong_attr_from_object(CK_ULONG value, CK_ATTRIBUTE_PTR template) { if (template->pValue == NULL) { template->ulValueLen = sizeof (CK_ULONG); return (CKR_OK); } if (template->ulValueLen >= sizeof (CK_ULONG)) { /* * The buffer provided by the application is large * enough to hold the value of the attribute. */ *(CK_ULONG_PTR)template->pValue = value; template->ulValueLen = sizeof (CK_ULONG); return (CKR_OK); } else { /* * The buffer provided by the application does * not have enough space to hold the value. */ template->ulValueLen = (CK_ULONG)-1; return (CKR_BUFFER_TOO_SMALL); } } CK_RV get_string_from_template(CK_ATTRIBUTE_PTR dest, CK_ATTRIBUTE_PTR src) { if ((src->pValue != NULL) && (src->ulValueLen > 0)) { /* Allocate storage for the value of the attribute. */ dest->pValue = malloc(src->ulValueLen); if (dest->pValue == NULL) { return (CKR_HOST_MEMORY); } (void) memcpy(dest->pValue, src->pValue, src->ulValueLen); dest->ulValueLen = src->ulValueLen; dest->type = src->type; } else { dest->pValue = NULL; dest->ulValueLen = 0; dest->type = src->type; } return (CKR_OK); } void string_attr_cleanup(CK_ATTRIBUTE_PTR template) { if (template->pValue) { free(template->pValue); template->pValue = NULL; template->ulValueLen = 0; } } /* * Parse the common attributes. Return to caller with appropriate return * value to indicate if the supplied template specifies a valid attribute * with a valid value. */ static CK_RV kms_parse_common_attrs(CK_ATTRIBUTE_PTR template, uint64_t *attr_mask_p) { CK_RV rv = CKR_OK; kms_slot_t *pslot = get_slotinfo(); switch (template->type) { case CKA_CLASS: break; case CKA_TOKEN: if ((*(CK_BBOOL *)template->pValue) == TRUE) *attr_mask_p |= TOKEN_BOOL_ON; break; case CKA_PRIVATE: if ((*(CK_BBOOL *)template->pValue) == TRUE) { /* * Cannot create a private object if the token * has a keystore and the user isn't logged in. */ if (pslot->sl_state != CKU_USER) { rv = CKR_ATTRIBUTE_VALUE_INVALID; } else { *attr_mask_p |= PRIVATE_BOOL_ON; } } break; case CKA_MODIFIABLE: if ((*(CK_BBOOL *)template->pValue) == FALSE) { *attr_mask_p &= ~MODIFIABLE_BOOL_ON; } break; case CKA_LABEL: break; default: rv = CKR_TEMPLATE_INCONSISTENT; } return (rv); } /* * Build a Secret Key Object. * * - Parse the object's template, and when an error is detected such as * invalid attribute type, invalid attribute value, etc., return * with appropriate return value. * - Set up attribute mask field in the object for the supplied common * attributes that have boolean type. * - Build the attribute_info struct to hold the value of each supplied * attribute that has byte array type. Link attribute_info structs * together to form the extra attribute list of the object. * - Allocate storage for the Secret Key object. * - Build the Secret Key object. Allocate storage to hold the big integer * value for the attribute CKA_VALUE that is required for all the key * types supported by secret key object. * */ CK_RV kms_build_secret_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, kms_object_t *new_object) { int i; CK_KEY_TYPE keytype = (CK_KEY_TYPE)~0UL; uint64_t attr_mask; CK_RV rv = CKR_OK; int isLabel = 0; /* Must not set flags */ int isValueLen = 0; CK_ATTRIBUTE string_tmp; secret_key_obj_t *sck; string_tmp.pValue = NULL; /* * If the object was pulled from the KMS, the * attributes are encoded in the object record * before this function is called, we don't * want to overwrite them unless the attribute * template says differently. */ if (new_object->bool_attr_mask != 0) attr_mask = new_object->bool_attr_mask; else attr_mask = SECRET_KEY_DEFAULT; /* Allocate storage for Secret Key Object. */ sck = calloc(1, sizeof (secret_key_obj_t)); if (sck == NULL) { rv = CKR_HOST_MEMORY; goto fail_cleanup; } new_object->object_class_u.secret_key = sck; new_object->class = CKO_SECRET_KEY; for (i = 0; i < ulAttrNum; i++) { /* Secret Key Object Attributes */ switch (template[i].type) { /* common key attributes */ case CKA_KEY_TYPE: keytype = *((CK_KEY_TYPE*)template[i].pValue); break; case CKA_ID: case CKA_START_DATE: case CKA_END_DATE: /* * Allocate storage to hold the attribute * value with byte array type, and add it to * the extra attribute list of the object. */ rv = kms_add_extra_attr(&template[i], new_object); if (rv != CKR_OK) { goto fail_cleanup; } break; /* * The following key related attribute types must * not be specified by C_CreateObject. */ case CKA_LOCAL: case CKA_KEY_GEN_MECHANISM: case CKA_ALWAYS_SENSITIVE: case CKA_NEVER_EXTRACTABLE: rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; /* Key related boolean attributes */ case CKA_DERIVE: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= DERIVE_BOOL_ON; break; case CKA_SENSITIVE: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= SENSITIVE_BOOL_ON; break; case CKA_ENCRYPT: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= ENCRYPT_BOOL_ON; else attr_mask &= ~ENCRYPT_BOOL_ON; break; case CKA_DECRYPT: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= DECRYPT_BOOL_ON; else attr_mask &= ~DECRYPT_BOOL_ON; break; case CKA_SIGN: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= SIGN_BOOL_ON; else attr_mask &= ~SIGN_BOOL_ON; break; case CKA_VERIFY: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= VERIFY_BOOL_ON; else attr_mask &= ~VERIFY_BOOL_ON; break; case CKA_WRAP: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= WRAP_BOOL_ON; break; case CKA_UNWRAP: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= UNWRAP_BOOL_ON; break; case CKA_EXTRACTABLE: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= EXTRACTABLE_BOOL_ON; else attr_mask &= ~EXTRACTABLE_BOOL_ON; break; case CKA_VALUE: if ((template[i].ulValueLen == 0) || (template[i].pValue == NULL)) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } /* * Copyin attribute from template * to a local variable. */ sck->sk_value = malloc(template[i].ulValueLen); if (sck->sk_value == NULL) { rv = CKR_HOST_MEMORY; goto fail_cleanup; } (void) memcpy(sck->sk_value, template[i].pValue, template[i].ulValueLen); sck->sk_value_len = template[i].ulValueLen; break; case CKA_VALUE_LEN: isValueLen = 1; if (template[i].pValue != NULL) sck->sk_value_len = *(CK_ULONG_PTR)template[i].pValue; else sck->sk_value_len = 0; break; case CKA_LABEL: isLabel = 1; rv = get_string_from_template(&string_tmp, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; default: rv = kms_parse_common_attrs(&template[i], &attr_mask); if (rv != CKR_OK) goto fail_cleanup; break; } } /* For */ if (keytype == (CK_KEY_TYPE)~0UL) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } new_object->key_type = keytype; /* Supported key types of the Secret Key Object */ switch (keytype) { case CKK_AES: if (!isValueLen) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if (sck->sk_value_len != AES_MIN_KEY_BYTES && sck->sk_value_len != AES_192_KEY_BYTES && sck->sk_value_len != AES_MAX_KEY_BYTES) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; case CKK_RC4: case CKK_GENERIC_SECRET: case CKK_BLOWFISH: case CKK_DES: case CKK_DES2: case CKK_DES3: default: rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } /* Set up object. */ new_object->bool_attr_mask = attr_mask; if (isLabel) { rv = kms_add_extra_attr(&string_tmp, new_object); if (rv != CKR_OK) goto fail_cleanup; string_attr_cleanup(&string_tmp); } return (rv); fail_cleanup: /* * cleanup the storage allocated to the local variables. */ string_attr_cleanup(&string_tmp); /* * cleanup the storage allocated inside the object itself. */ kms_cleanup_object(new_object); return (rv); } /* * Validate the attribute types in the object's template. Then, * call the appropriate build function according to the class of * the object specified in the template. * * Note: The following classes of objects are supported: * - CKO_SECRET_KEY */ CK_RV kms_build_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, kms_object_t *new_object) { CK_OBJECT_CLASS class = (CK_OBJECT_CLASS)~0UL; CK_RV rv = CKR_OK; if (template == NULL) { return (CKR_ARGUMENTS_BAD); } /* Validate the attribute type in the template. */ rv = kms_validate_attr(template, ulAttrNum, &class); if (rv != CKR_OK) return (rv); if (class == (CK_OBJECT_CLASS)~0UL) return (CKR_TEMPLATE_INCOMPLETE); /* * Call the appropriate function based on the supported class * of the object. */ switch (class) { case CKO_SECRET_KEY: rv = kms_build_secret_key_object(template, ulAttrNum, new_object); break; case CKO_DOMAIN_PARAMETERS: case CKO_DATA: case CKO_CERTIFICATE: case CKO_HW_FEATURE: case CKO_VENDOR_DEFINED: case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: default: return (CKR_ATTRIBUTE_VALUE_INVALID); } return (rv); } /* * Get the value of a requested attribute that is common to all supported * classes (i.e. public key, private key, secret key classes). */ CK_RV kms_get_common_attrs(kms_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_RV rv = CKR_OK; switch (template->type) { case CKA_CLASS: return (get_ulong_attr_from_object(object_p->class, template)); /* default boolean attributes */ case CKA_TOKEN: template->ulValueLen = sizeof (CK_BBOOL); if (template->pValue == NULL) { return (CKR_OK); } *((CK_BBOOL *)template->pValue) = B_FALSE; break; case CKA_PRIVATE: template->ulValueLen = sizeof (CK_BBOOL); if (template->pValue == NULL) { return (CKR_OK); } if (object_p->bool_attr_mask & PRIVATE_BOOL_ON) { *((CK_BBOOL *)template->pValue) = B_TRUE; } else { *((CK_BBOOL *)template->pValue) = B_FALSE; } break; case CKA_MODIFIABLE: template->ulValueLen = sizeof (CK_BBOOL); if (template->pValue == NULL) { return (CKR_OK); } if ((object_p->bool_attr_mask) & MODIFIABLE_BOOL_ON) *((CK_BBOOL *)template->pValue) = B_TRUE; else *((CK_BBOOL *)template->pValue) = B_FALSE; break; case CKA_LABEL: return (get_extra_attr_from_object(object_p, template)); break; default: /* * The specified attribute for the object is invalid. * (the object does not possess such an attribute.) */ template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } return (rv); } /* * Get the value of a requested attribute that is common to all key objects * (i.e. public key, private key and secret key). */ CK_RV kms_get_common_key_attrs(kms_object_t *object_p, CK_ATTRIBUTE_PTR template) { switch (template->type) { case CKA_KEY_TYPE: return (get_ulong_attr_from_object(object_p->key_type, template)); case CKA_ID: case CKA_START_DATE: case CKA_END_DATE: /* * The above extra attributes have byte array type. */ return (get_extra_attr_from_object(object_p, template)); /* Key related boolean attributes */ case CKA_LOCAL: return (get_bool_attr_from_object(object_p, LOCAL_BOOL_ON, template)); case CKA_DERIVE: return (get_bool_attr_from_object(object_p, DERIVE_BOOL_ON, template)); case CKA_KEY_GEN_MECHANISM: return (get_ulong_attr_from_object(object_p->mechanism, template)); default: return (CKR_ATTRIBUTE_TYPE_INVALID); } } /* * Get the value of a requested attribute of a Secret Key Object. * * Rule: All the attributes in the secret key object can be revealed * except those marked with footnote number "7" when the object * has its CKA_SENSITIVE attribute set to TRUE or its * CKA_EXTRACTABLE attribute set to FALSE. */ CK_RV kms_get_secret_key_attribute(kms_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_RV rv = CKR_OK; CK_KEY_TYPE keytype = object_p->key_type; switch (template->type) { /* Key related boolean attributes */ case CKA_SENSITIVE: return (get_bool_attr_from_object(object_p, SENSITIVE_BOOL_ON, template)); case CKA_ENCRYPT: return (get_bool_attr_from_object(object_p, ENCRYPT_BOOL_ON, template)); case CKA_DECRYPT: return (get_bool_attr_from_object(object_p, DECRYPT_BOOL_ON, template)); case CKA_SIGN: return (get_bool_attr_from_object(object_p, SIGN_BOOL_ON, template)); case CKA_VERIFY: return (get_bool_attr_from_object(object_p, VERIFY_BOOL_ON, template)); case CKA_WRAP: return (get_bool_attr_from_object(object_p, WRAP_BOOL_ON, template)); case CKA_UNWRAP: return (get_bool_attr_from_object(object_p, UNWRAP_BOOL_ON, template)); case CKA_EXTRACTABLE: return (get_bool_attr_from_object(object_p, EXTRACTABLE_BOOL_ON, template)); case CKA_ALWAYS_SENSITIVE: return (get_bool_attr_from_object(object_p, ALWAYS_SENSITIVE_BOOL_ON, template)); case CKA_NEVER_EXTRACTABLE: return (get_bool_attr_from_object(object_p, NEVER_EXTRACTABLE_BOOL_ON, template)); case CKA_VALUE: /* * If the specified attribute for the secret key object * cannot be revealed because the object is sensitive * or unextractable, then the ulValueLen is set to -1. */ if ((object_p->bool_attr_mask & SENSITIVE_BOOL_ON) || !(object_p->bool_attr_mask & EXTRACTABLE_BOOL_ON)) { template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_SENSITIVE); } switch (keytype) { case CKK_AES: /* * Copy secret key object attributes to template. */ if (template->pValue == NULL) { template->ulValueLen = OBJ_SEC_VALUE_LEN(object_p); return (CKR_OK); } if (OBJ_SEC_VALUE(object_p) == NULL) { template->ulValueLen = 0; return (CKR_OK); } if (template->ulValueLen >= OBJ_SEC_VALUE_LEN(object_p)) { (void) memcpy(template->pValue, OBJ_SEC_VALUE(object_p), OBJ_SEC_VALUE_LEN(object_p)); template->ulValueLen = OBJ_SEC_VALUE_LEN(object_p); return (CKR_OK); } else { template->ulValueLen = (CK_ULONG)-1; return (CKR_BUFFER_TOO_SMALL); } case CKK_RC4: case CKK_GENERIC_SECRET: case CKK_RC5: case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_CDMF: case CKK_BLOWFISH: default: template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } break; case CKA_VALUE_LEN: return (get_ulong_attr_from_object(OBJ_SEC_VALUE_LEN(object_p), template)); default: /* * First, get the value of the request attribute defined * in the list of common key attributes. If the request * attribute is not found in that list, then get the * attribute from the list of common attributes. */ rv = kms_get_common_key_attrs(object_p, template); if (rv == CKR_ATTRIBUTE_TYPE_INVALID) { rv = kms_get_common_attrs(object_p, template); } break; } return (rv); } /* * Call the appropriate get attribute function according to the class * of object. * * The caller of this function holds the lock on the object. */ CK_RV kms_get_attribute(kms_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_RV rv = CKR_OK; CK_OBJECT_CLASS class = object_p->class; switch (class) { case CKO_SECRET_KEY: rv = kms_get_secret_key_attribute(object_p, template); break; case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: default: /* * If the specified attribute for the object is invalid * (the object does not possess such as attribute), then * the ulValueLen is modified to hold the value -1. */ template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } return (rv); } /* * Set the value of an attribute that is common to all key objects * (i.e. public key, private key and secret key). */ static CK_RV kms_set_common_key_attribute(kms_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy) { kms_slot_t *pslot = get_slotinfo(); CK_RV rv = CKR_OK; switch (template->type) { case CKA_LABEL: /* * Only the LABEL can be modified in the common storage * object attributes after the object is created. */ return (set_extra_attr_to_object(object_p, CKA_LABEL, template)); case CKA_ID: return (set_extra_attr_to_object(object_p, CKA_ID, template)); case CKA_START_DATE: return (set_extra_attr_to_object(object_p, CKA_START_DATE, template)); case CKA_END_DATE: return (set_extra_attr_to_object(object_p, CKA_END_DATE, template)); case CKA_DERIVE: return (set_bool_attr_to_object(object_p, DERIVE_BOOL_ON, template)); case CKA_CLASS: case CKA_KEY_TYPE: case CKA_LOCAL: return (CKR_ATTRIBUTE_READ_ONLY); case CKA_PRIVATE: if (!copy) { /* called from C_SetAttributeValue() */ return (CKR_ATTRIBUTE_READ_ONLY); } /* called from C_CopyObject() */ if ((*(CK_BBOOL *)template->pValue) != B_TRUE) { return (CKR_OK); } (void) pthread_mutex_lock(&pslot->sl_mutex); /* * Cannot create a private object if the token * has a keystore and the user isn't logged in. */ if (pslot->sl_state != CKU_USER) { rv = CKR_USER_NOT_LOGGED_IN; } else { rv = set_bool_attr_to_object(object_p, PRIVATE_BOOL_ON, template); } (void) pthread_mutex_unlock(&pslot->sl_mutex); return (rv); case CKA_MODIFIABLE: if (copy) { rv = set_bool_attr_to_object(object_p, MODIFIABLE_BOOL_ON, template); } else { rv = CKR_ATTRIBUTE_READ_ONLY; } return (rv); default: return (CKR_TEMPLATE_INCONSISTENT); } } /* * Set the value of an attribute of a Secret Key Object. * * Rule: The attributes marked with footnote number "8" in the PKCS11 * spec may be modified (p.88 in PKCS11 spec.). */ static CK_RV kms_set_secret_key_attribute(kms_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy) { CK_KEY_TYPE keytype = object_p->key_type; switch (template->type) { case CKA_SENSITIVE: /* * Cannot set SENSITIVE to FALSE if it is already ON. */ if (((*(CK_BBOOL *)template->pValue) == B_FALSE) && (object_p->bool_attr_mask & SENSITIVE_BOOL_ON)) { return (CKR_ATTRIBUTE_READ_ONLY); } if (*(CK_BBOOL *)template->pValue) object_p->bool_attr_mask |= SENSITIVE_BOOL_ON; return (CKR_OK); case CKA_ENCRYPT: return (set_bool_attr_to_object(object_p, ENCRYPT_BOOL_ON, template)); case CKA_DECRYPT: return (set_bool_attr_to_object(object_p, DECRYPT_BOOL_ON, template)); case CKA_SIGN: return (set_bool_attr_to_object(object_p, SIGN_BOOL_ON, template)); case CKA_VERIFY: return (set_bool_attr_to_object(object_p, VERIFY_BOOL_ON, template)); case CKA_WRAP: return (set_bool_attr_to_object(object_p, WRAP_BOOL_ON, template)); case CKA_UNWRAP: return (set_bool_attr_to_object(object_p, UNWRAP_BOOL_ON, template)); case CKA_EXTRACTABLE: /* * Cannot set EXTRACTABLE to TRUE if it is already OFF. */ if ((*(CK_BBOOL *)template->pValue) && !(object_p->bool_attr_mask & EXTRACTABLE_BOOL_ON)) { return (CKR_ATTRIBUTE_READ_ONLY); } if ((*(CK_BBOOL *)template->pValue) == B_FALSE) object_p->bool_attr_mask &= ~EXTRACTABLE_BOOL_ON; return (CKR_OK); case CKA_VALUE: return (CKR_ATTRIBUTE_READ_ONLY); case CKA_VALUE_LEN: if ((keytype == CKK_RC4) || (keytype == CKK_GENERIC_SECRET) || (keytype == CKK_AES) || (keytype == CKK_BLOWFISH)) return (CKR_ATTRIBUTE_READ_ONLY); break; default: /* * Set the value of a common key attribute. */ return (kms_set_common_key_attribute(object_p, template, copy)); } /* * If we got this far, then the combination of key type * and requested attribute is invalid. */ return (CKR_ATTRIBUTE_TYPE_INVALID); } /* * Call the appropriate set attribute function according to the class * of object. * * The caller of this function does not hold the lock on the original * object, since this function is setting the attribute on the new object * that is being modified. * */ CK_RV kms_set_attribute(kms_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy) { CK_RV rv = CKR_OK; CK_OBJECT_CLASS class = object_p->class; switch (class) { case CKO_SECRET_KEY: rv = kms_set_secret_key_attribute(object_p, template, copy); break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: default: /* * If the template specifies a value of an attribute * which is incompatible with other existing attributes * of the object, then fails with return code * CKR_TEMPLATE_INCONSISTENT. */ rv = CKR_TEMPLATE_INCONSISTENT; break; } return (rv); } CK_RV kms_copy_secret_key_attr(secret_key_obj_t *old_secret_key_obj_p, secret_key_obj_t **new_secret_key_obj_p) { secret_key_obj_t *sk; sk = malloc(sizeof (secret_key_obj_t)); if (sk == NULL) { return (CKR_HOST_MEMORY); } (void) memcpy(sk, old_secret_key_obj_p, sizeof (secret_key_obj_t)); /* copy the secret key value */ sk->sk_value = malloc((sizeof (CK_BYTE) * sk->sk_value_len)); if (sk->sk_value == NULL) { free(sk); return (CKR_HOST_MEMORY); } (void) memcpy(sk->sk_value, old_secret_key_obj_p->sk_value, (sizeof (CK_BYTE) * sk->sk_value_len)); *new_secret_key_obj_p = sk; return (CKR_OK); } /* * If CKA_CLASS not given, guess CKA_CLASS using * attributes on template. * * Some attributes are specific to an object class. If one or more * of these attributes are in the template, make a list of classes * that can have these attributes. This would speed up the search later, * because we can immediately skip an object if the class of that * object can not possibly contain one of the attributes. * */ void kms_process_find_attr(CK_OBJECT_CLASS *pclasses, CK_ULONG *num_result_pclasses, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { ulong_t i; int j; boolean_t secret_found = B_FALSE; int num_secret_key_attrs; int num_pclasses = 0; for (i = 0; i < ulCount; i++) { if (pTemplate[i].type == CKA_CLASS) { /* * don't need to guess the class, it is specified. * Just record the class, and return. */ pclasses[0] = (*((CK_OBJECT_CLASS *)pTemplate[i].pValue)); *num_result_pclasses = 1; return; } } num_secret_key_attrs = sizeof (SECRET_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); /* * Get the list of objects class that might contain * some attributes. */ for (i = 0; i < ulCount; i++) { if (!secret_found) { for (j = 0; j < num_secret_key_attrs; j++) { if (pTemplate[i].type == SECRET_KEY_ATTRS[j]) { secret_found = B_TRUE; pclasses[num_pclasses++] = CKO_SECRET_KEY; break; } } } } *num_result_pclasses = num_pclasses; } boolean_t kms_find_match_attrs(kms_object_t *obj, CK_OBJECT_CLASS *pclasses, CK_ULONG num_pclasses, CK_ATTRIBUTE *template, CK_ULONG num_attr) { ulong_t i; CK_ATTRIBUTE *tmpl_attr, *obj_attr; uint64_t attr_mask; boolean_t compare_attr, compare_boolean; /* * Check if the class of this object match with any * of object classes that can possibly contain the * requested attributes. */ if (num_pclasses > 0) { for (i = 0; i < num_pclasses; i++) { if (obj->class == pclasses[i]) { break; } } if (i == num_pclasses) { /* * this object can't possibly contain one or * more attributes, don't need to check this object */ return (B_FALSE); } } /* need to examine everything */ for (i = 0; i < num_attr; i++) { tmpl_attr = &(template[i]); compare_attr = B_FALSE; compare_boolean = B_FALSE; switch (tmpl_attr->type) { /* First, check the most common attributes */ case CKA_CLASS: if (*((CK_OBJECT_CLASS *)tmpl_attr->pValue) != obj->class) { return (B_FALSE); } break; case CKA_KEY_TYPE: if (*((CK_KEY_TYPE *)tmpl_attr->pValue) != obj->key_type) { return (B_FALSE); } break; case CKA_ENCRYPT: attr_mask = (obj->bool_attr_mask) & ENCRYPT_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_DECRYPT: attr_mask = (obj->bool_attr_mask) & DECRYPT_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_WRAP: attr_mask = (obj->bool_attr_mask) & WRAP_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_UNWRAP: attr_mask = (obj->bool_attr_mask) & UNWRAP_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_SIGN: attr_mask = (obj->bool_attr_mask) & SIGN_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_SIGN_RECOVER: attr_mask = (obj->bool_attr_mask) & SIGN_RECOVER_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_VERIFY: attr_mask = (obj->bool_attr_mask) & VERIFY_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_VERIFY_RECOVER: attr_mask = (obj->bool_attr_mask) & VERIFY_RECOVER_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_DERIVE: attr_mask = (obj->bool_attr_mask) & DERIVE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_LOCAL: attr_mask = (obj->bool_attr_mask) & LOCAL_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_SENSITIVE: attr_mask = (obj->bool_attr_mask) & SENSITIVE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_SECONDARY_AUTH: attr_mask = (obj->bool_attr_mask) & SECONDARY_AUTH_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_TRUSTED: attr_mask = (obj->bool_attr_mask) & TRUSTED_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_EXTRACTABLE: attr_mask = (obj->bool_attr_mask) & EXTRACTABLE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_ALWAYS_SENSITIVE: attr_mask = (obj->bool_attr_mask) & ALWAYS_SENSITIVE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_NEVER_EXTRACTABLE: attr_mask = (obj->bool_attr_mask) & NEVER_EXTRACTABLE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_TOKEN: attr_mask = (obj->bool_attr_mask) & TOKEN_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_PRIVATE: attr_mask = (obj->bool_attr_mask) & PRIVATE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_MODIFIABLE: attr_mask = (obj->bool_attr_mask) & MODIFIABLE_BOOL_ON; compare_boolean = B_TRUE; break; case CKA_SUBJECT: case CKA_ID: case CKA_START_DATE: case CKA_END_DATE: case CKA_KEY_GEN_MECHANISM: case CKA_LABEL: /* find these attributes from extra_attrlistp */ obj_attr = get_extra_attr(tmpl_attr->type, obj); compare_attr = B_TRUE; break; case CKA_VALUE_LEN: /* only secret key has this attribute */ if (obj->class == CKO_SECRET_KEY) { if (*((CK_ULONG *)tmpl_attr->pValue) != OBJ_SEC_VALUE_LEN(obj)) { return (B_FALSE); } } else { return (B_FALSE); } break; case CKA_VALUE: switch (obj->class) { case CKO_SECRET_KEY: break; default: return (B_FALSE); } break; case CKA_VALUE_BITS: case CKA_PRIME_BITS: case CKA_SUBPRIME_BITS: default: /* * any other attributes are currently not supported. * so, it's not possible for them to be in the * object */ return (B_FALSE); } if (compare_boolean) { CK_BBOOL bval; if (attr_mask) { bval = TRUE; } else { bval = FALSE; } if (bval != *((CK_BBOOL *)tmpl_attr->pValue)) { return (B_FALSE); } } else if (compare_attr) { if (obj_attr == NULL) { /* * The attribute type is valid, and its value * has not been initialized in the object. In * this case, it only matches the template's * attribute if the template's value length * is 0. */ if (tmpl_attr->ulValueLen != 0) return (B_FALSE); } else { if (tmpl_attr->ulValueLen != obj_attr->ulValueLen) { return (B_FALSE); } if (memcmp(tmpl_attr->pValue, obj_attr->pValue, tmpl_attr->ulValueLen) != 0) { return (B_FALSE); } } } } return (B_TRUE); } CK_ATTRIBUTE_PTR get_extra_attr(CK_ATTRIBUTE_TYPE type, kms_object_t *obj) { CK_ATTRIBUTE_INFO_PTR tmp; tmp = obj->extra_attrlistp; while (tmp != NULL) { if (tmp->attr.type == type) { return (&(tmp->attr)); } tmp = tmp->next; } /* if get there, the specified attribute is not found */ return (NULL); }