/* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include "kernelGlobal.h" #include "kernelObject.h" #include "kernelSession.h" #include "kernelSlot.h" /* * This attribute table is used by the kernel_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 public 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 PUB_KEY_ATTRS[] = { CKA_SUBJECT, CKA_ENCRYPT, CKA_WRAP, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_TRUSTED, CKA_ECDSA_PARAMS, CKA_EC_PARAMS, CKA_EC_POINT }; /* * attributes that exists only in private 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 PRIV_KEY_ATTRS[] = { CKA_DECRYPT, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, CKA_VALUE_BITS, CKA_SUBJECT, CKA_SENSITIVE, CKA_EXTRACTABLE, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, CKA_ECDSA_PARAMS, CKA_EC_PARAMS }; /* * 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 }; /* * attributes that exists only in domain parameter 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 DOMAIN_ATTRS[] = { CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, CKA_SUBPRIME_BITS, CKA_SUB_PRIME_BITS }; /* * attributes that exists only in hardware feature objects */ CK_ATTRIBUTE_TYPE HARDWARE_ATTRS[] = { CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, CKA_HAS_RESET }; /* * attributes that exists only in certificate objects */ CK_ATTRIBUTE_TYPE CERT_ATTRS[] = { CKA_CERTIFICATE_TYPE, CKA_SUBJECT, CKA_ID, CKA_ISSUER, CKA_AC_ISSUER, CKA_SERIAL_NUMBER, CKA_OWNER, CKA_ATTR_TYPES }; /* * Validate the attribute by using binary search algorithm. */ CK_RV kernel_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 kernel_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 = kernel_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 kernel_cleanup_extra_attr(kernel_object_t *object_p) { CK_ATTRIBUTE_INFO_PTR extra_attr; CK_ATTRIBUTE_INFO_PTR tmp; 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 kernel_add_extra_attr(CK_ATTRIBUTE_PTR template, kernel_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 kernel_copy_extra_attr(CK_ATTRIBUTE_INFO_PTR old_attrp, kernel_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(kernel_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(kernel_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 (kernel_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 big integer attribute value from template to a biginteger_t struct. */ CK_RV get_bigint_attr_from_template(biginteger_t *big, CK_ATTRIBUTE_PTR template) { if ((template->pValue != NULL) && (template->ulValueLen > 0)) { /* Allocate storage for the value of the attribute. */ big->big_value = malloc(template->ulValueLen); if (big->big_value == NULL) { return (CKR_HOST_MEMORY); } (void) memcpy(big->big_value, template->pValue, template->ulValueLen); big->big_value_len = template->ulValueLen; } else { big->big_value = NULL; big->big_value_len = 0; } return (CKR_OK); } /* * Copy the big integer attribute value from a biginteger_t struct in the * object to a template. */ CK_RV get_bigint_attr_from_object(biginteger_t *big, CK_ATTRIBUTE_PTR template) { if (template->pValue == NULL) { template->ulValueLen = big->big_value_len; return (CKR_OK); } if (big->big_value == NULL) { template->ulValueLen = 0; return (CKR_OK); } if (template->ulValueLen >= big->big_value_len) { /* * The buffer provided by the application is large * enough to hold the value of the attribute. */ (void) memcpy(template->pValue, big->big_value, big->big_value_len); template->ulValueLen = big->big_value_len; 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); } } /* * Copy the boolean data type attribute value from an object for the * specified attribute to the template. */ CK_RV get_bool_attr_from_object(kernel_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(kernel_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); } } /* * Copy the CK_ULONG data type attribute value from a template to the * object. */ void get_ulong_attr_from_template(CK_ULONG *value, CK_ATTRIBUTE_PTR template) { if (template->pValue != NULL) { *value = *(CK_ULONG_PTR)template->pValue; } else { *value = 0; } } /* * Copy the big integer attribute value from source's biginteger_t to * destination's biginteger_t. */ void copy_bigint_attr(biginteger_t *src, biginteger_t *dst) { if ((src->big_value != NULL) && (src->big_value_len > 0)) { /* * To do the copy, just have dst's big_value points * to src's. */ dst->big_value = src->big_value; dst->big_value_len = src->big_value_len; /* * After the copy, nullify the src's big_value pointer. * It prevents any double freeing the value. */ src->big_value = NULL; src->big_value_len = 0; } else { dst->big_value = NULL; dst->big_value_len = 0; } } 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; } } /* * Release the storage allocated for object attribute with big integer * value. */ void bigint_attr_cleanup(biginteger_t *big) { if (big == NULL) return; if (big->big_value) { (void) memset(big->big_value, 0, big->big_value_len); free(big->big_value); big->big_value = NULL; big->big_value_len = 0; } } /* * Clean up and release all the storage allocated to hold the big integer * attributes associated with the type (i.e. class) of the object. Also, * release the storage allocated to the type of the object. */ void kernel_cleanup_object_bigint_attrs(kernel_object_t *object_p) { CK_OBJECT_CLASS class = object_p->class; CK_KEY_TYPE keytype = object_p->key_type; switch (class) { case CKO_PUBLIC_KEY: if (OBJ_PUB(object_p)) { switch (keytype) { case CKK_RSA: bigint_attr_cleanup(OBJ_PUB_RSA_MOD( object_p)); bigint_attr_cleanup(OBJ_PUB_RSA_PUBEXPO( object_p)); break; case CKK_DSA: bigint_attr_cleanup(OBJ_PUB_DSA_PRIME( object_p)); bigint_attr_cleanup(OBJ_PUB_DSA_SUBPRIME( object_p)); bigint_attr_cleanup(OBJ_PUB_DSA_BASE( object_p)); bigint_attr_cleanup(OBJ_PUB_DSA_VALUE( object_p)); break; case CKK_DH: bigint_attr_cleanup(OBJ_PUB_DH_PRIME(object_p)); bigint_attr_cleanup(OBJ_PUB_DH_BASE(object_p)); bigint_attr_cleanup(OBJ_PUB_DH_VALUE(object_p)); break; case CKK_EC: bigint_attr_cleanup(OBJ_PUB_EC_POINT(object_p)); break; } /* Release Public Key Object struct */ free(OBJ_PUB(object_p)); OBJ_PUB(object_p) = NULL; } break; case CKO_PRIVATE_KEY: if (OBJ_PRI(object_p)) { switch (keytype) { case CKK_RSA: bigint_attr_cleanup(OBJ_PRI_RSA_MOD( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_PUBEXPO( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_PRIEXPO( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_PRIME1( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_PRIME2( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_EXPO1( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_EXPO2( object_p)); bigint_attr_cleanup(OBJ_PRI_RSA_COEF( object_p)); break; case CKK_DSA: bigint_attr_cleanup(OBJ_PRI_DSA_PRIME( object_p)); bigint_attr_cleanup(OBJ_PRI_DSA_SUBPRIME( object_p)); bigint_attr_cleanup(OBJ_PRI_DSA_BASE( object_p)); bigint_attr_cleanup(OBJ_PRI_DSA_VALUE( object_p)); break; case CKK_DH: bigint_attr_cleanup(OBJ_PRI_DH_PRIME(object_p)); bigint_attr_cleanup(OBJ_PRI_DH_BASE(object_p)); bigint_attr_cleanup(OBJ_PRI_DH_VALUE(object_p)); break; case CKK_EC: bigint_attr_cleanup(OBJ_PRI_EC_VALUE(object_p)); break; } /* Release Private Key Object struct. */ free(OBJ_PRI(object_p)); OBJ_PRI(object_p) = NULL; } break; } } /* * 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. */ CK_RV kernel_parse_common_attrs(CK_ATTRIBUTE_PTR template, kernel_session_t *sp, uint64_t *attr_mask_p) { CK_RV rv = CKR_OK; kernel_slot_t *pslot = slot_table[sp->ses_slotid]; switch (template->type) { case CKA_CLASS: break; /* default boolean attributes */ case CKA_TOKEN: if ((*(CK_BBOOL *)template->pValue) == TRUE) { rv = CKR_ATTRIBUTE_VALUE_INVALID; } 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_func_list.fl_object_create && 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 Public 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 Public Key object. * - Build the Public Key object according to the key type. Allocate * storage to hold the big integer value for the supplied attributes * that are required for a certain key type. * */ CK_RV kernel_build_public_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, kernel_object_t *new_object, kernel_session_t *sp, uint_t mode) { int i; CK_KEY_TYPE keytype = (CK_KEY_TYPE)~0UL; uint64_t attr_mask = PUBLIC_KEY_DEFAULT; CK_RV rv = CKR_OK; int isLabel = 0; /* Must set flags */ int isModulus = 0; int isPubExpo = 0; int isPrime = 0; int isSubprime = 0; int isBase = 0; int isValue = 0; int isPoint = 0; int isParams = 0; /* Must not set flags */ int isModulusBits = 0; CK_ULONG modulus_bits = 0; biginteger_t modulus; biginteger_t pubexpo; biginteger_t prime; biginteger_t subprime; biginteger_t base; biginteger_t value; biginteger_t point; CK_ATTRIBUTE string_tmp; CK_ATTRIBUTE param_tmp; public_key_obj_t *pbk; /* prevent bigint_attr_cleanup from freeing invalid attr value */ (void) memset(&modulus, 0x0, sizeof (biginteger_t)); (void) memset(&pubexpo, 0x0, sizeof (biginteger_t)); (void) memset(&prime, 0x0, sizeof (biginteger_t)); (void) memset(&subprime, 0x0, sizeof (biginteger_t)); (void) memset(&base, 0x0, sizeof (biginteger_t)); (void) memset(&value, 0x0, sizeof (biginteger_t)); (void) memset(&point, 0x0, sizeof (biginteger_t)); string_tmp.pValue = NULL; param_tmp.pValue = NULL; for (i = 0; i < ulAttrNum; i++) { /* Public 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: /* common public key attribute */ case CKA_SUBJECT: /* * Allocate storage to hold the attribute * value with byte array type, and add it to * the extra attribute list of the object. */ rv = kernel_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: 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_ENCRYPT: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= ENCRYPT_BOOL_ON; else attr_mask &= ~ENCRYPT_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_VERIFY_RECOVER: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= VERIFY_RECOVER_BOOL_ON; else attr_mask &= ~VERIFY_RECOVER_BOOL_ON; break; case CKA_WRAP: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= WRAP_BOOL_ON; break; case CKA_TRUSTED: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= TRUSTED_BOOL_ON; break; /* * The following key related attribute types must * be specified according to the key type by * C_CreateObject. */ case CKA_MODULUS: isModulus = 1; /* * Copyin big integer attribute from template * to a local variable. */ rv = get_bigint_attr_from_template(&modulus, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PUBLIC_EXPONENT: isPubExpo = 1; rv = get_bigint_attr_from_template(&pubexpo, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PRIME: isPrime = 1; rv = get_bigint_attr_from_template(&prime, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_SUBPRIME: isSubprime = 1; rv = get_bigint_attr_from_template(&subprime, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_BASE: isBase = 1; rv = get_bigint_attr_from_template(&base, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_VALUE: isValue = 1; rv = get_bigint_attr_from_template(&value, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_MODULUS_BITS: isModulusBits = 1; get_ulong_attr_from_template(&modulus_bits, &template[i]); break; case CKA_LABEL: isLabel = 1; rv = get_string_from_template(&string_tmp, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_EC_POINT: isPoint = 1; rv = get_bigint_attr_from_template(&point, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_EC_PARAMS: isParams = 1; rv = get_string_from_template(¶m_tmp, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; default: rv = kernel_parse_common_attrs(&template[i], sp, &attr_mask); if (rv != CKR_OK) goto fail_cleanup; break; } } /* For */ /* Allocate storage for Public Key Object. */ pbk = calloc(1, sizeof (public_key_obj_t)); if (pbk == NULL) { rv = CKR_HOST_MEMORY; goto fail_cleanup; } new_object->object_class_u.public_key = pbk; new_object->class = CKO_PUBLIC_KEY; if (keytype == (CK_KEY_TYPE)~0UL) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } new_object->key_type = keytype; /* Supported key types of the Public Key Object */ switch (keytype) { case CKK_RSA: if (mode == KERNEL_CREATE_OBJ) { if (isModulusBits || isPrime || isSubprime || isBase|| isValue) { rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } } if (isModulus && isPubExpo) { /* * Copy big integer attribute value to the * designated place in the public key object. */ copy_bigint_attr(&modulus, KEY_PUB_RSA_MOD(pbk)); copy_bigint_attr(&pubexpo, KEY_PUB_RSA_PUBEXPO(pbk)); } else { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } /* must be generating a RSA key pair by value */ if (isModulusBits) { KEY_PUB_RSA_MOD_BITS(pbk) = modulus_bits; } break; case CKK_DSA: if (isModulusBits || isModulus || isPubExpo) { rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } if (!(isPrime && isSubprime && isBase && isValue)) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } copy_bigint_attr(&prime, KEY_PUB_DSA_PRIME(pbk)); copy_bigint_attr(&subprime, KEY_PUB_DSA_SUBPRIME(pbk)); copy_bigint_attr(&base, KEY_PUB_DSA_BASE(pbk)); copy_bigint_attr(&value, KEY_PUB_DSA_VALUE(pbk)); break; case CKK_DH: if (!(isPrime && isBase && isValue)) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } copy_bigint_attr(&prime, KEY_PUB_DH_PRIME(pbk)); copy_bigint_attr(&base, KEY_PUB_DH_BASE(pbk)); copy_bigint_attr(&value, KEY_PUB_DH_VALUE(pbk)); break; case CKK_EC: if (!isPoint || !isParams) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } copy_bigint_attr(&point, KEY_PUB_EC_POINT(pbk)); rv = kernel_add_extra_attr(¶m_tmp, new_object); if (rv != CKR_OK) goto fail_cleanup; string_attr_cleanup(¶m_tmp); break; default: rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } /* Set up object. */ new_object->bool_attr_mask = attr_mask; if (isLabel) { rv = kernel_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. */ bigint_attr_cleanup(&modulus); bigint_attr_cleanup(&pubexpo); bigint_attr_cleanup(&prime); bigint_attr_cleanup(&subprime); bigint_attr_cleanup(&base); bigint_attr_cleanup(&value); bigint_attr_cleanup(&point); string_attr_cleanup(&string_tmp); string_attr_cleanup(¶m_tmp); /* * cleanup the storage allocated inside the object itself. */ kernel_cleanup_object(new_object); return (rv); } /* * Build a Private 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 Private Key object. * - Build the Private Key object according to the key type. Allocate * storage to hold the big integer value for the supplied attributes * that are required for a certain key type. * */ CK_RV kernel_build_private_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, kernel_object_t *new_object, kernel_session_t *sp, uint_t mode) { ulong_t i; CK_KEY_TYPE keytype = (CK_KEY_TYPE)~0UL; uint64_t attr_mask = PRIVATE_KEY_DEFAULT; CK_RV rv = CKR_OK; int isLabel = 0; /* Must set flags */ int isModulus = 0; int isPriExpo = 0; int isPrime = 0; int isSubprime = 0; int isBase = 0; int isValue = 0; int isParams = 0; /* Must not set flags */ int isValueBits = 0; CK_ULONG value_bits = 0; /* Private Key RSA optional */ int isPubExpo = 0; int isPrime1 = 0; int isPrime2 = 0; int isExpo1 = 0; int isExpo2 = 0; int isCoef = 0; biginteger_t modulus; biginteger_t priexpo; biginteger_t prime; biginteger_t subprime; biginteger_t base; biginteger_t value; biginteger_t pubexpo; biginteger_t prime1; biginteger_t prime2; biginteger_t expo1; biginteger_t expo2; biginteger_t coef; CK_ATTRIBUTE string_tmp; CK_ATTRIBUTE param_tmp; private_key_obj_t *pvk; /* prevent bigint_attr_cleanup from freeing invalid attr value */ (void) memset(&modulus, 0x0, sizeof (biginteger_t)); (void) memset(&priexpo, 0x0, sizeof (biginteger_t)); (void) memset(&prime, 0x0, sizeof (biginteger_t)); (void) memset(&subprime, 0x0, sizeof (biginteger_t)); (void) memset(&base, 0x0, sizeof (biginteger_t)); (void) memset(&value, 0x0, sizeof (biginteger_t)); (void) memset(&pubexpo, 0x0, sizeof (biginteger_t)); (void) memset(&prime1, 0x0, sizeof (biginteger_t)); (void) memset(&prime2, 0x0, sizeof (biginteger_t)); (void) memset(&expo1, 0x0, sizeof (biginteger_t)); (void) memset(&expo2, 0x0, sizeof (biginteger_t)); (void) memset(&coef, 0x0, sizeof (biginteger_t)); string_tmp.pValue = NULL; param_tmp.pValue = NULL; for (i = 0; i < ulAttrNum; i++) { /* Private 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: /* common private key attribute */ case CKA_SUBJECT: /* * Allocate storage to hold the attribute * value with byte array type, and add it to * the extra attribute list of the object. */ rv = kernel_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_AUTH_PIN_FLAGS: 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_SECONDARY_AUTH: if (*(CK_BBOOL *)template[i].pValue) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } 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_SIGN_RECOVER: if (*(CK_BBOOL *)template[i].pValue) attr_mask |= SIGN_RECOVER_BOOL_ON; else attr_mask &= ~SIGN_RECOVER_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; /* * The following key related attribute types must * be specified according to the key type by * C_CreateObject. */ case CKA_MODULUS: isModulus = 1; /* * Copyin big integer attribute from template * to a local variable. */ rv = get_bigint_attr_from_template(&modulus, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PUBLIC_EXPONENT: isPubExpo = 1; rv = get_bigint_attr_from_template(&pubexpo, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PRIVATE_EXPONENT: isPriExpo = 1; rv = get_bigint_attr_from_template(&priexpo, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PRIME_1: isPrime1 = 1; rv = get_bigint_attr_from_template(&prime1, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PRIME_2: isPrime2 = 1; rv = get_bigint_attr_from_template(&prime2, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_EXPONENT_1: isExpo1 = 1; rv = get_bigint_attr_from_template(&expo1, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_EXPONENT_2: isExpo2 = 1; rv = get_bigint_attr_from_template(&expo2, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_COEFFICIENT: isCoef = 1; rv = get_bigint_attr_from_template(&coef, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_PRIME: isPrime = 1; rv = get_bigint_attr_from_template(&prime, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_SUBPRIME: isSubprime = 1; rv = get_bigint_attr_from_template(&subprime, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_BASE: isBase = 1; rv = get_bigint_attr_from_template(&base, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_VALUE: isValue = 1; rv = get_bigint_attr_from_template(&value, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_VALUE_BITS: isValueBits = 1; get_ulong_attr_from_template(&value_bits, &template[i]); break; case CKA_LABEL: isLabel = 1; rv = get_string_from_template(&string_tmp, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; case CKA_EC_PARAMS: isParams = 1; rv = get_string_from_template(¶m_tmp, &template[i]); if (rv != CKR_OK) goto fail_cleanup; break; default: rv = kernel_parse_common_attrs(&template[i], sp, &attr_mask); if (rv != CKR_OK) goto fail_cleanup; break; } } /* For */ /* Allocate storage for Private Key Object. */ pvk = calloc(1, sizeof (private_key_obj_t)); if (pvk == NULL) { rv = CKR_HOST_MEMORY; goto fail_cleanup; } new_object->object_class_u.private_key = pvk; new_object->class = CKO_PRIVATE_KEY; if (keytype == (CK_KEY_TYPE)~0UL) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } new_object->key_type = keytype; /* Supported key types of the Private Key Object */ switch (keytype) { case CKK_RSA: if (isPrime || isSubprime || isBase || isValue || isValueBits) { rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } if (isModulus && isPriExpo) { /* * Copy big integer attribute value to the * designated place in the Private Key object. */ copy_bigint_attr(&modulus, KEY_PRI_RSA_MOD(pvk)); copy_bigint_attr(&priexpo, KEY_PRI_RSA_PRIEXPO(pvk)); } else { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } /* The following attributes are optional. */ if (isPubExpo) { copy_bigint_attr(&pubexpo, KEY_PRI_RSA_PUBEXPO(pvk)); } if (isPrime1) { copy_bigint_attr(&prime1, KEY_PRI_RSA_PRIME1(pvk)); } if (isPrime2) { copy_bigint_attr(&prime2, KEY_PRI_RSA_PRIME2(pvk)); } if (isExpo1) { copy_bigint_attr(&expo1, KEY_PRI_RSA_EXPO1(pvk)); } if (isExpo2) { copy_bigint_attr(&expo2, KEY_PRI_RSA_EXPO2(pvk)); } if (isCoef) { copy_bigint_attr(&coef, KEY_PRI_RSA_COEF(pvk)); } break; case CKK_DSA: if (isModulus || isPubExpo || isPriExpo || isPrime1 || isPrime2 || isExpo1 || isExpo2 || isCoef || isValueBits) { rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } if (!(isPrime && isSubprime && isBase && isValue)) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } copy_bigint_attr(&prime, KEY_PRI_DSA_PRIME(pvk)); copy_bigint_attr(&subprime, KEY_PRI_DSA_SUBPRIME(pvk)); copy_bigint_attr(&base, KEY_PRI_DSA_BASE(pvk)); copy_bigint_attr(&value, KEY_PRI_DSA_VALUE(pvk)); break; case CKK_DH: if (mode == KERNEL_CREATE_OBJ && isValueBits) { rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } if (!(isPrime && isBase && isValue)) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } copy_bigint_attr(&prime, KEY_PRI_DH_PRIME(pvk)); copy_bigint_attr(&base, KEY_PRI_DH_BASE(pvk)); copy_bigint_attr(&value, KEY_PRI_DH_VALUE(pvk)); KEY_PRI_DH_VAL_BITS(pvk) = (isValueBits) ? value_bits : 0; break; case CKK_EC: if (!isValue || !isParams) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } copy_bigint_attr(&value, KEY_PRI_EC_VALUE(pvk)); rv = kernel_add_extra_attr(¶m_tmp, new_object); if (rv != CKR_OK) goto fail_cleanup; string_attr_cleanup(¶m_tmp); break; default: rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } /* Set up object. */ new_object->bool_attr_mask = attr_mask; if (isLabel) { rv = kernel_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. */ bigint_attr_cleanup(&modulus); bigint_attr_cleanup(&priexpo); bigint_attr_cleanup(&prime); bigint_attr_cleanup(&subprime); bigint_attr_cleanup(&base); bigint_attr_cleanup(&value); bigint_attr_cleanup(&pubexpo); bigint_attr_cleanup(&prime1); bigint_attr_cleanup(&prime2); bigint_attr_cleanup(&expo1); bigint_attr_cleanup(&expo2); bigint_attr_cleanup(&coef); string_attr_cleanup(&string_tmp); string_attr_cleanup(¶m_tmp); /* * cleanup the storage allocated inside the object itself. */ kernel_cleanup_object(new_object); 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 kernel_build_secret_key_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, kernel_object_t *new_object, kernel_session_t *sp) { int i; CK_KEY_TYPE keytype = (CK_KEY_TYPE)~0UL; uint64_t attr_mask = SECRET_KEY_DEFAULT; CK_RV rv = CKR_OK; int isLabel = 0; /* Must set flags */ int isValue = 0; /* Must not set flags */ int isValueLen = 0; CK_ATTRIBUTE string_tmp; secret_key_obj_t *sck; string_tmp.pValue = NULL; /* 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 = kernel_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: isValue = 1; 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; 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 = kernel_parse_common_attrs(&template[i], sp, &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_RC4: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if ((sck->sk_value_len < ARCFOUR_MIN_KEY_BYTES) || (sck->sk_value_len > ARCFOUR_MAX_KEY_BYTES)) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; case CKK_GENERIC_SECRET: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } break; case CKK_AES: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if (sck->sk_value_len < AES_MIN_KEY_BYTES) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; case CKK_BLOWFISH: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if (sck->sk_value_len < BLOWFISH_MINBYTES) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; case CKK_DES: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if (sck->sk_value_len != DES_KEYSIZE) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; case CKK_DES2: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if (sck->sk_value_len != DES2_KEYSIZE) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; case CKK_DES3: if (!isValue) { rv = CKR_TEMPLATE_INCOMPLETE; goto fail_cleanup; } if (sck->sk_value_len != DES3_KEYSIZE) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto fail_cleanup; } break; default: rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } if (isValueLen) { rv = CKR_TEMPLATE_INCONSISTENT; goto fail_cleanup; } /* Set up object. */ new_object->bool_attr_mask = attr_mask; if (isLabel) { rv = kernel_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. */ kernel_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 * - CKO_PUBLIC_KEY * - CKO_PRIVATE_KEY */ CK_RV kernel_build_object(CK_ATTRIBUTE_PTR template, CK_ULONG ulAttrNum, kernel_object_t *new_object, kernel_session_t *sp, uint_t mode) { 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 = kernel_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_PUBLIC_KEY: rv = kernel_build_public_key_object(template, ulAttrNum, new_object, sp, mode); break; case CKO_PRIVATE_KEY: rv = kernel_build_private_key_object(template, ulAttrNum, new_object, sp, mode); break; case CKO_SECRET_KEY: rv = kernel_build_secret_key_object(template, ulAttrNum, new_object, sp); break; case CKO_DOMAIN_PARAMETERS: case CKO_DATA: case CKO_CERTIFICATE: case CKO_HW_FEATURE: case CKO_VENDOR_DEFINED: 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 kernel_get_common_attrs(kernel_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); } /* * A token object will not be created in the library, so we * return FALSE. */ *((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 kernel_get_common_key_attrs(kernel_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 Public Key Object. * * Rule: All the attributes in the public key object can be revealed. */ CK_RV kernel_get_public_key_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_RV rv = CKR_OK; CK_KEY_TYPE keytype = object_p->key_type; switch (template->type) { case CKA_SUBJECT: case CKA_EC_PARAMS: /* * The above extra attributes have byte array type. */ return (get_extra_attr_from_object(object_p, template)); /* Key related boolean attributes */ case CKA_ENCRYPT: return (get_bool_attr_from_object(object_p, ENCRYPT_BOOL_ON, template)); case CKA_VERIFY: return (get_bool_attr_from_object(object_p, VERIFY_BOOL_ON, template)); case CKA_VERIFY_RECOVER: return (get_bool_attr_from_object(object_p, VERIFY_RECOVER_BOOL_ON, template)); case CKA_WRAP: return (get_bool_attr_from_object(object_p, WRAP_BOOL_ON, template)); case CKA_TRUSTED: return (get_bool_attr_from_object(object_p, TRUSTED_BOOL_ON, template)); case CKA_MODULUS: /* * This attribute is valid only for RSA public key * object. */ if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PUB_RSA_MOD(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_PUBLIC_EXPONENT: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PUB_RSA_PUBEXPO(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_MODULUS_BITS: if (keytype == CKK_RSA) { return (get_ulong_attr_from_object( OBJ_PUB_RSA_MOD_BITS(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_PRIME: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PUB_DSA_PRIME(object_p), template)); case CKK_DH: return (get_bigint_attr_from_object( OBJ_PUB_DH_PRIME(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_SUBPRIME: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PUB_DSA_SUBPRIME(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_BASE: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PUB_DSA_BASE(object_p), template)); case CKK_DH: return (get_bigint_attr_from_object( OBJ_PUB_DH_BASE(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_VALUE: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PUB_DSA_VALUE(object_p), template)); case CKK_DH: return (get_bigint_attr_from_object( OBJ_PUB_DH_VALUE(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_EC_POINT: switch (keytype) { case CKK_EC: return (get_bigint_attr_from_object( OBJ_PUB_EC_POINT(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } 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 = kernel_get_common_key_attrs(object_p, template); if (rv == CKR_ATTRIBUTE_TYPE_INVALID) { rv = kernel_get_common_attrs(object_p, template); } break; } return (rv); } /* * Get the value of a requested attribute of a Private Key Object. * * Rule: All the attributes in the private 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 (p.88 in PKCS11 spec.). */ CK_RV kernel_get_private_key_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_RV rv = CKR_OK; CK_KEY_TYPE keytype = object_p->key_type; /* * If the following specified attributes for the private 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)) { switch (template->type) { case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: case CKA_VALUE: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_SENSITIVE); } } switch (template->type) { case CKA_SUBJECT: case CKA_EC_PARAMS: /* * The above extra attributes have byte array type. */ return (get_extra_attr_from_object(object_p, template)); /* Key related boolean attributes */ case CKA_SENSITIVE: return (get_bool_attr_from_object(object_p, SENSITIVE_BOOL_ON, template)); case CKA_SECONDARY_AUTH: return (get_bool_attr_from_object(object_p, SECONDARY_AUTH_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_SIGN_RECOVER: return (get_bool_attr_from_object(object_p, SIGN_RECOVER_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_MODULUS: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_MOD(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_PUBLIC_EXPONENT: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_PUBEXPO(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_PRIVATE_EXPONENT: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_PRIEXPO(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_PRIME_1: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_PRIME1(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_PRIME_2: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_PRIME2(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_EXPONENT_1: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_EXPO1(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_EXPONENT_2: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_EXPO2(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_COEFFICIENT: if (keytype == CKK_RSA) { return (get_bigint_attr_from_object( OBJ_PRI_RSA_COEF(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_VALUE_BITS: if (keytype == CKK_DH) { return (get_ulong_attr_from_object( OBJ_PRI_DH_VAL_BITS(object_p), template)); } else { template->ulValueLen = (CK_ULONG)-1; rv = CKR_ATTRIBUTE_TYPE_INVALID; break; } case CKA_PRIME: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PRI_DSA_PRIME(object_p), template)); case CKK_DH: return (get_bigint_attr_from_object( OBJ_PRI_DH_PRIME(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_SUBPRIME: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PRI_DSA_SUBPRIME(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_BASE: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PRI_DSA_BASE(object_p), template)); case CKK_DH: return (get_bigint_attr_from_object( OBJ_PRI_DH_BASE(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } case CKA_VALUE: switch (keytype) { case CKK_DSA: return (get_bigint_attr_from_object( OBJ_PRI_DSA_VALUE(object_p), template)); case CKK_DH: return (get_bigint_attr_from_object( OBJ_PRI_DH_VALUE(object_p), template)); case CKK_EC: return (get_bigint_attr_from_object( OBJ_PRI_EC_VALUE(object_p), template)); default: template->ulValueLen = (CK_ULONG)-1; return (CKR_ATTRIBUTE_TYPE_INVALID); } 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 = kernel_get_common_key_attrs(object_p, template); if (rv == CKR_ATTRIBUTE_TYPE_INVALID) { rv = kernel_get_common_attrs(object_p, template); } break; } return (rv); } /* * 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 (p.88 in PKCS11 spec.). */ CK_RV kernel_get_secret_key_attribute(kernel_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_RC4: case CKK_GENERIC_SECRET: case CKK_RC5: case CKK_DES: case CKK_DES2: case CKK_DES3: case CKK_CDMF: case CKK_AES: case CKK_BLOWFISH: /* * 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); } 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 = kernel_get_common_key_attrs(object_p, template); if (rv == CKR_ATTRIBUTE_TYPE_INVALID) { rv = kernel_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 kernel_get_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template) { CK_RV rv = CKR_OK; CK_OBJECT_CLASS class = object_p->class; switch (class) { case CKO_PUBLIC_KEY: rv = kernel_get_public_key_attribute(object_p, template); break; case CKO_PRIVATE_KEY: rv = kernel_get_private_key_attribute(object_p, template); break; case CKO_SECRET_KEY: rv = kernel_get_secret_key_attribute(object_p, template); break; 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). */ CK_RV kernel_set_common_key_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy, kernel_session_t *sp) { kernel_slot_t *pslot = slot_table[sp->ses_slotid]; 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_func_list.fl_object_create && 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 Public Key Object. * * Rule: The attributes marked with footnote number "8" in the PKCS11 * spec may be modified (p.88 in PKCS11 spec.). */ CK_RV kernel_set_public_key_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy, kernel_session_t *sp) { CK_KEY_TYPE keytype = object_p->key_type; switch (template->type) { case CKA_SUBJECT: return (set_extra_attr_to_object(object_p, CKA_SUBJECT, template)); case CKA_ENCRYPT: return (set_bool_attr_to_object(object_p, ENCRYPT_BOOL_ON, template)); case CKA_VERIFY: return (set_bool_attr_to_object(object_p, VERIFY_BOOL_ON, template)); case CKA_VERIFY_RECOVER: return (set_bool_attr_to_object(object_p, VERIFY_RECOVER_BOOL_ON, template)); case CKA_WRAP: return (set_bool_attr_to_object(object_p, WRAP_BOOL_ON, template)); case CKA_MODULUS: case CKA_MODULUS_BITS: case CKA_PUBLIC_EXPONENT: if (keytype == CKK_RSA) return (CKR_ATTRIBUTE_READ_ONLY); break; case CKA_SUBPRIME: case CKA_PRIME: case CKA_BASE: case CKA_VALUE: if (keytype == CKK_DSA) return (CKR_ATTRIBUTE_READ_ONLY); break; default: /* * Set the value of a common key attribute. */ return (kernel_set_common_key_attribute(object_p, template, copy, sp)); } /* * If we got this far, then the combination of key type * and requested attribute is invalid. */ return (CKR_ATTRIBUTE_TYPE_INVALID); } /* * Set the value of an attribute of a Private Key Object. * * Rule: The attributes marked with footnote number "8" in the PKCS11 * spec may be modified (p.88 in PKCS11 spec.). */ CK_RV kernel_set_private_key_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy, kernel_session_t *sp) { CK_KEY_TYPE keytype = object_p->key_type; switch (template->type) { case CKA_SUBJECT: return (set_extra_attr_to_object(object_p, CKA_SUBJECT, template)); 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_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_SIGN_RECOVER: return (set_bool_attr_to_object(object_p, SIGN_RECOVER_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_MODULUS: case CKA_PUBLIC_EXPONENT: case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: if (keytype == CKK_RSA) { return (CKR_ATTRIBUTE_READ_ONLY); } break; case CKA_SUBPRIME: case CKA_PRIME: case CKA_BASE: case CKA_VALUE: if (keytype == CKK_DSA) return (CKR_ATTRIBUTE_READ_ONLY); break; default: /* * Set the value of a common key attribute. */ return (kernel_set_common_key_attribute(object_p, template, copy, sp)); } /* * If we got this far, then the combination of key type * and requested attribute is invalid. */ return (CKR_ATTRIBUTE_TYPE_INVALID); } /* * 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.). */ CK_RV kernel_set_secret_key_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy, kernel_session_t *sp) { 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 (kernel_set_common_key_attribute(object_p, template, copy, sp)); } /* * 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 kernel_set_attribute(kernel_object_t *object_p, CK_ATTRIBUTE_PTR template, boolean_t copy, kernel_session_t *sp) { CK_RV rv = CKR_OK; CK_OBJECT_CLASS class = object_p->class; switch (class) { case CKO_PUBLIC_KEY: rv = kernel_set_public_key_attribute(object_p, template, copy, sp); break; case CKO_PRIVATE_KEY: rv = kernel_set_private_key_attribute(object_p, template, copy, sp); break; case CKO_SECRET_KEY: rv = kernel_set_secret_key_attribute(object_p, template, copy, sp); break; 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); } static CK_RV copy_bigint(biginteger_t *new_bigint, biginteger_t *old_bigint) { new_bigint->big_value = malloc((sizeof (CK_BYTE) * new_bigint->big_value_len)); if (new_bigint->big_value == NULL) { return (CKR_HOST_MEMORY); } (void) memcpy(new_bigint->big_value, old_bigint->big_value, (sizeof (CK_BYTE) * new_bigint->big_value_len)); return (CKR_OK); } static void free_public_key_attr(public_key_obj_t *pbk, CK_KEY_TYPE key_type) { if (pbk == NULL) { return; } switch (key_type) { case CKK_RSA: bigint_attr_cleanup(KEY_PUB_RSA_MOD(pbk)); bigint_attr_cleanup(KEY_PUB_RSA_PUBEXPO(pbk)); break; case CKK_DSA: bigint_attr_cleanup(KEY_PUB_DSA_PRIME(pbk)); bigint_attr_cleanup(KEY_PUB_DSA_SUBPRIME(pbk)); bigint_attr_cleanup(KEY_PUB_DSA_BASE(pbk)); bigint_attr_cleanup(KEY_PUB_DSA_VALUE(pbk)); break; default: break; } free(pbk); } CK_RV kernel_copy_public_key_attr(public_key_obj_t *old_pub_key_obj_p, public_key_obj_t **new_pub_key_obj_p, CK_KEY_TYPE key_type) { public_key_obj_t *pbk; CK_RV rv = CKR_OK; pbk = calloc(1, sizeof (public_key_obj_t)); if (pbk == NULL) { return (CKR_HOST_MEMORY); } switch (key_type) { case CKK_RSA: (void) memcpy(KEY_PUB_RSA(pbk), KEY_PUB_RSA(old_pub_key_obj_p), sizeof (rsa_pub_key_t)); /* copy modulus */ rv = copy_bigint(KEY_PUB_RSA_MOD(pbk), KEY_PUB_RSA_MOD(old_pub_key_obj_p)); if (rv != CKR_OK) { free_public_key_attr(pbk, key_type); return (rv); } /* copy public exponent */ rv = copy_bigint(KEY_PUB_RSA_PUBEXPO(pbk), KEY_PUB_RSA_PUBEXPO(old_pub_key_obj_p)); if (rv != CKR_OK) { free_public_key_attr(pbk, key_type); return (rv); } break; case CKK_DSA: (void) memcpy(KEY_PUB_DSA(pbk), KEY_PUB_DSA(old_pub_key_obj_p), sizeof (dsa_pub_key_t)); /* copy prime */ rv = copy_bigint(KEY_PUB_DSA_PRIME(pbk), KEY_PUB_DSA_PRIME(old_pub_key_obj_p)); if (rv != CKR_OK) { free_public_key_attr(pbk, key_type); return (rv); } /* copy subprime */ rv = copy_bigint(KEY_PUB_DSA_SUBPRIME(pbk), KEY_PUB_DSA_SUBPRIME(old_pub_key_obj_p)); if (rv != CKR_OK) { free_public_key_attr(pbk, key_type); return (rv); } /* copy base */ rv = copy_bigint(KEY_PUB_DSA_BASE(pbk), KEY_PUB_DSA_BASE(old_pub_key_obj_p)); if (rv != CKR_OK) { free_public_key_attr(pbk, key_type); return (rv); } /* copy value */ rv = copy_bigint(KEY_PUB_DSA_VALUE(pbk), KEY_PUB_DSA_VALUE(old_pub_key_obj_p)); if (rv != CKR_OK) { free_public_key_attr(pbk, key_type); return (rv); } break; default: break; } *new_pub_key_obj_p = pbk; return (rv); } static void free_private_key_attr(private_key_obj_t *pbk, CK_KEY_TYPE key_type) { if (pbk == NULL) { return; } switch (key_type) { case CKK_RSA: bigint_attr_cleanup(KEY_PRI_RSA_MOD(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_PUBEXPO(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_PRIEXPO(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_PRIME1(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_PRIME2(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_EXPO1(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_EXPO2(pbk)); bigint_attr_cleanup(KEY_PRI_RSA_COEF(pbk)); break; case CKK_DSA: bigint_attr_cleanup(KEY_PRI_DSA_PRIME(pbk)); bigint_attr_cleanup(KEY_PRI_DSA_SUBPRIME(pbk)); bigint_attr_cleanup(KEY_PRI_DSA_BASE(pbk)); bigint_attr_cleanup(KEY_PRI_DSA_VALUE(pbk)); break; default: break; } free(pbk); } CK_RV kernel_copy_private_key_attr(private_key_obj_t *old_pri_key_obj_p, private_key_obj_t **new_pri_key_obj_p, CK_KEY_TYPE key_type) { CK_RV rv = CKR_OK; private_key_obj_t *pbk; pbk = calloc(1, sizeof (private_key_obj_t)); if (pbk == NULL) { return (CKR_HOST_MEMORY); } switch (key_type) { case CKK_RSA: (void) memcpy(KEY_PRI_RSA(pbk), KEY_PRI_RSA(old_pri_key_obj_p), sizeof (rsa_pri_key_t)); /* copy modulus */ rv = copy_bigint(KEY_PRI_RSA_MOD(pbk), KEY_PRI_RSA_MOD(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy public exponent */ rv = copy_bigint(KEY_PRI_RSA_PUBEXPO(pbk), KEY_PRI_RSA_PUBEXPO(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy private exponent */ rv = copy_bigint(KEY_PRI_RSA_PRIEXPO(pbk), KEY_PRI_RSA_PRIEXPO(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy prime_1 */ rv = copy_bigint(KEY_PRI_RSA_PRIME1(pbk), KEY_PRI_RSA_PRIME1(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy prime_2 */ rv = copy_bigint(KEY_PRI_RSA_PRIME2(pbk), KEY_PRI_RSA_PRIME2(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy exponent_1 */ rv = copy_bigint(KEY_PRI_RSA_EXPO1(pbk), KEY_PRI_RSA_EXPO1(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy exponent_2 */ rv = copy_bigint(KEY_PRI_RSA_EXPO2(pbk), KEY_PRI_RSA_EXPO2(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy coefficient */ rv = copy_bigint(KEY_PRI_RSA_COEF(pbk), KEY_PRI_RSA_COEF(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } break; case CKK_DSA: (void) memcpy(KEY_PRI_DSA(pbk), KEY_PRI_DSA(old_pri_key_obj_p), sizeof (dsa_pri_key_t)); /* copy prime */ rv = copy_bigint(KEY_PRI_DSA_PRIME(pbk), KEY_PRI_DSA_PRIME(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy subprime */ rv = copy_bigint(KEY_PRI_DSA_SUBPRIME(pbk), KEY_PRI_DSA_SUBPRIME(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy base */ rv = copy_bigint(KEY_PRI_DSA_BASE(pbk), KEY_PRI_DSA_BASE(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } /* copy value */ rv = copy_bigint(KEY_PRI_DSA_VALUE(pbk), KEY_PRI_DSA_VALUE(old_pri_key_obj_p)); if (rv != CKR_OK) { free_private_key_attr(pbk, key_type); return (rv); } break; default: break; } *new_pri_key_obj_p = pbk; return (rv); } CK_RV kernel_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 possiblely contain one of the attributes. * */ void kernel_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 pub_found = B_FALSE, priv_found = B_FALSE, secret_found = B_FALSE, domain_found = B_FALSE, hardware_found = B_FALSE, cert_found = B_FALSE; int num_pub_key_attrs, num_priv_key_attrs, num_secret_key_attrs, num_domain_attrs, num_hardware_attrs, num_cert_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_pub_key_attrs = sizeof (PUB_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); num_priv_key_attrs = sizeof (PRIV_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); num_secret_key_attrs = sizeof (SECRET_KEY_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); num_domain_attrs = sizeof (DOMAIN_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); num_hardware_attrs = sizeof (HARDWARE_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); num_cert_attrs = sizeof (CERT_ATTRS) / sizeof (CK_ATTRIBUTE_TYPE); /* * Get the list of objects class that might contain * some attributes. */ for (i = 0; i < ulCount; i++) { /* * only check if this attribute can belong to public key object * class if public key object isn't already in the list */ if (!pub_found) { for (j = 0; j < num_pub_key_attrs; j++) { if (pTemplate[i].type == PUB_KEY_ATTRS[j]) { pub_found = B_TRUE; pclasses[num_pclasses++] = CKO_PUBLIC_KEY; break; } } } if (!priv_found) { for (j = 0; j < num_priv_key_attrs; j++) { if (pTemplate[i].type == PRIV_KEY_ATTRS[j]) { priv_found = B_TRUE; pclasses[num_pclasses++] = CKO_PRIVATE_KEY; break; } } } 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; } } } if (!domain_found) { for (j = 0; j < num_domain_attrs; j++) { if (pTemplate[i].type == DOMAIN_ATTRS[j]) { domain_found = B_TRUE; pclasses[num_pclasses++] = CKO_DOMAIN_PARAMETERS; break; } } } if (!hardware_found) { for (j = 0; j < num_hardware_attrs; j++) { if (pTemplate[i].type == HARDWARE_ATTRS[j]) { hardware_found = B_TRUE; pclasses[num_pclasses++] = CKO_HW_FEATURE; break; } } } if (!cert_found) { for (j = 0; j < num_cert_attrs; j++) { if (pTemplate[i].type == CERT_ATTRS[j]) { cert_found = B_TRUE; pclasses[num_pclasses++] = CKO_CERTIFICATE; break; } } } } *num_result_pclasses = num_pclasses; } boolean_t kernel_find_match_attrs(kernel_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; biginteger_t *bigint; boolean_t compare_attr, compare_bigint, compare_boolean; /* * Check if the class of this object match with any * of object classes that can possiblely 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 possiblely 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_bigint = 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: /* * CKA_TOKEN value is not applicable to an object * created in the library, it should only contain * the default value FALSE */ attr_mask = 0; 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: /* * secret_key_obj_t is the same as * biginteger_t */ bigint = (biginteger_t *)OBJ_SEC(obj); break; case CKO_PRIVATE_KEY: if (obj->key_type == CKK_DSA) { bigint = OBJ_PRI_DSA_VALUE(obj); } else { return (B_FALSE); } break; case CKO_PUBLIC_KEY: if (obj->key_type == CKK_DSA) { bigint = OBJ_PUB_DSA_VALUE(obj); } else { return (B_FALSE); } break; default: return (B_FALSE); } compare_bigint = B_TRUE; break; case CKA_MODULUS: /* only RSA public and private key have this attr */ if (obj->key_type == CKK_RSA) { if (obj->class == CKO_PUBLIC_KEY) { bigint = OBJ_PUB_RSA_MOD(obj); } else if (obj->class == CKO_PRIVATE_KEY) { bigint = OBJ_PRI_RSA_MOD(obj); } else { return (B_FALSE); } compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_MODULUS_BITS: /* only RSA public key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PUBLIC_KEY)) { CK_ULONG mod_bits = OBJ_PUB_RSA_MOD_BITS(obj); if (mod_bits != *((CK_ULONG *)tmpl_attr->pValue)) { return (B_FALSE); } } else { return (B_FALSE); } break; case CKA_PUBLIC_EXPONENT: /* only RSA public and private key have this attr */ if (obj->key_type == CKK_RSA) { if (obj->class == CKO_PUBLIC_KEY) { bigint = OBJ_PUB_RSA_PUBEXPO(obj); } else if (obj->class == CKO_PRIVATE_KEY) { bigint = OBJ_PRI_RSA_PUBEXPO(obj); } else { return (B_FALSE); } compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_PRIVATE_EXPONENT: /* only RSA private key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PRIVATE_KEY)) { bigint = OBJ_PRI_RSA_PRIEXPO(obj); compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_PRIME_1: /* only RSA private key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PRIVATE_KEY)) { bigint = OBJ_PRI_RSA_PRIME1(obj); compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_PRIME_2: /* only RSA private key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PRIVATE_KEY)) { bigint = OBJ_PRI_RSA_PRIME2(obj); compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_EXPONENT_1: /* only RSA private key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PRIVATE_KEY)) { bigint = OBJ_PRI_RSA_EXPO1(obj); compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_EXPONENT_2: /* only RSA private key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PRIVATE_KEY)) { bigint = OBJ_PRI_RSA_EXPO2(obj); compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_COEFFICIENT: /* only RSA private key has this attribute */ if ((obj->key_type == CKK_RSA) && (obj->class == CKO_PRIVATE_KEY)) { bigint = OBJ_PRI_RSA_COEF(obj); compare_bigint = B_TRUE; } else { return (B_FALSE); } break; case CKA_VALUE_BITS: return (B_FALSE); case CKA_PRIME: if (obj->class == CKO_PUBLIC_KEY) { switch (obj->key_type) { case CKK_DSA: bigint = OBJ_PUB_DSA_PRIME(obj); break; default: return (B_FALSE); } } else if (obj->class == CKO_PRIVATE_KEY) { switch (obj->key_type) { case CKK_DSA: bigint = OBJ_PRI_DSA_PRIME(obj); break; default: return (B_FALSE); } } else { return (B_FALSE); } compare_bigint = B_TRUE; break; case CKA_SUBPRIME: if (obj->class == CKO_PUBLIC_KEY) { switch (obj->key_type) { case CKK_DSA: bigint = OBJ_PUB_DSA_SUBPRIME(obj); break; default: return (B_FALSE); } } else if (obj->class == CKO_PRIVATE_KEY) { switch (obj->key_type) { case CKK_DSA: bigint = OBJ_PRI_DSA_SUBPRIME(obj); break; default: return (B_FALSE); } } else { return (B_FALSE); } compare_bigint = B_TRUE; break; case CKA_BASE: if (obj->class == CKO_PUBLIC_KEY) { switch (obj->key_type) { case CKK_DSA: bigint = OBJ_PUB_DSA_BASE(obj); break; default: return (B_FALSE); } } else if (obj->class == CKO_PRIVATE_KEY) { switch (obj->key_type) { case CKK_DSA: bigint = OBJ_PRI_DSA_BASE(obj); break; default: return (B_FALSE); } } else { return (B_FALSE); } compare_bigint = B_TRUE; break; case CKA_PRIME_BITS: return (B_FALSE); case CKA_SUBPRIME_BITS: return (B_FALSE); 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_bigint) { if (bigint == NULL) { return (B_FALSE); } if (tmpl_attr->ulValueLen != bigint->big_value_len) { return (B_FALSE); } if (memcmp(tmpl_attr->pValue, bigint->big_value, tmpl_attr->ulValueLen) != 0) { 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, kernel_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); }