summaryrefslogtreecommitdiff
path: root/usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c')
-rw-r--r--usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c1726
1 files changed, 1726 insertions, 0 deletions
diff --git a/usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c b/usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c
new file mode 100644
index 0000000000..69d62bec2b
--- /dev/null
+++ b/usr/src/lib/pkcs11/pkcs11_kms/common/kmsAttributeUtil.c
@@ -0,0 +1,1726 @@
+/*
+ * 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);
+}