/* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "kernelGlobal.h" #include "kernelSession.h" #include "kernelObject.h" static boolean_t attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt) { int i; for (i = 0; i < cnt; i++) { if (t[i].type == type) return (B_TRUE); } return (B_FALSE); } /* * This routine returns modulus bytes rounded up to the nearest 8 byte * chunk. This is so we don't have to pass in max sized buffers for * returned attributes. Every unnecessary byte that we pass in results * in a kernel allocation. */ static ulong_t get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt) { CK_ULONG modulus_len; int i; for (i = 0; i < cnt; i++) { if (t[i].type == CKA_MODULUS_BITS) { get_ulong_attr_from_template(&modulus_len, &t[i]); /* convert from bit length to byte length */ modulus_len = (modulus_len - 1) / 64 + 1; return (modulus_len * 8); } } return (0); } /* * Remove specified attribute from array. Storage for the attribute's * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are * contiguous within the array, i.e. the next attribute is shifted into * the position of the removed attribute. Returns TRUE if specified * attribute is removed. */ static boolean_t remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count, boolean_t free_attr) { int i, j; for (i = 0, j = 0; i < count; i++) { if (t[i].type == type) { if (free_attr) { free(t[i].pValue); } continue; } if (i != j) { t[j].type = t[i].type; t[j].pValue = t[i].pValue; t[j].ulValueLen = t[i].ulValueLen; } j++; } if (j == count) return (B_FALSE); /* safety */ t[j].pValue = NULL; t[j].ulValueLen = 0; return (B_TRUE); } static boolean_t is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount) { int i; for (i = 0; i < ulAttributeCount; i++) { if (pTemplate[i].type == CKA_CLASS && *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) == CKO_SECRET_KEY) return (B_TRUE); } return (B_FALSE); } /* * Allocate a template with space for new_count entries and copy the * specified template into the new template. */ static CK_ATTRIBUTE_PTR grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count, CK_ULONG new_count) { CK_ATTRIBUTE_PTR new_template; new_template = malloc(new_count * sizeof (CK_ATTRIBUTE)); if (new_template != NULL) bcopy(old_template, new_template, old_count * sizeof (CK_ATTRIBUTE)); return (new_template); } /* * For fixed length keys such as DES, return the length based on * the key type. For variable length keys such as AES, take the * length from the CKA_VALUE_LEN attribute. */ static int get_key_len_from_template(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, kernel_object_t *basekey_p, ulong_t *key_len) { boolean_t fixed_len_key = B_FALSE; ulong_t key_type; int i; for (i = 0; i < ulAttributeCount; i++) { if (pTemplate[i].type == CKA_KEY_TYPE) { get_ulong_attr_from_template(&key_type, &pTemplate[i]); break; } } /* CKA_KEY_TYPE must be present */ if (i == ulAttributeCount) return (CKR_TEMPLATE_INCOMPLETE); switch (key_type) { case CKK_DES: *key_len = 8; fixed_len_key = B_TRUE; break; case CKK_DES3: *key_len = 24; fixed_len_key = B_TRUE; break; case CKK_AES: case CKK_BLOWFISH: for (i = 0; i < ulAttributeCount; i++) { if (pTemplate[i].type == CKA_VALUE_LEN) { get_ulong_attr_from_template(key_len, &pTemplate[i]); break; } } /* CKA_VALUE_LEN must be present */ if (i == ulAttributeCount) return (CKR_TEMPLATE_INCOMPLETE); break; case CKK_GENERIC_SECRET: /* * The key will not be truncated, so we need to * get the max length for the mechanism. */ if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) { CK_ATTRIBUTE tmp; tmp.type = CKA_PRIME; tmp.pValue = NULL; /* get size of attribute */ if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) { return (CKR_ARGUMENTS_BAD); } *key_len = tmp.ulValueLen; } else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) { *key_len = EC_MAX_VALUE_LEN; } else { return (CKR_ARGUMENTS_BAD); } break; default: return (CKR_ATTRIBUTE_VALUE_INVALID); } if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN, pTemplate, ulAttributeCount)) return (CKR_TEMPLATE_INCONSISTENT); return (CKR_OK); } /* find specified attribute src template and copy to dest */ static int copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt, CK_ATTRIBUTE_PTR dst) { int rv, i; for (i = 0; i < src_cnt; i++) { if (src[i].type == type) { rv = get_string_from_template(dst, &src[i]); break; } } /* * The public template didn't have attribute. */ if (i == src_cnt) { rv = CKR_TEMPLATE_INCOMPLETE; } return (rv); } static void free_attributes(caddr_t p, uint_t *countp) { if (*countp > 0) { free_object_attributes(p, *countp); *countp = 0; } } CK_RV key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, kernel_session_t *session_p, crypto_mech_type_t k_mech_type, kernel_object_t *new_objp) { crypto_nostore_generate_key_t obj_ngk; char *key_buf = NULL; CK_ATTRIBUTE_PTR newTemplate = NULL; CK_BBOOL is_token_obj = FALSE; CK_RV rv = CKR_OK; ulong_t key_len = 0; uint_t attr_count; int r; obj_ngk.ngk_in_count = 0; obj_ngk.ngk_out_count = 0; rv = get_key_len_from_template(pMechanism, pTemplate, ulCount, NULL, &key_len); if (rv != CRYPTO_SUCCESS) goto failed_exit; if ((key_buf = malloc(key_len)) == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } attr_count = ulCount + 1; newTemplate = grow_template(pTemplate, ulCount, attr_count); if (newTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* Now add the CKA_VALUE attribute to template */ newTemplate[ulCount].type = CKA_VALUE; newTemplate[ulCount].pValue = (caddr_t)key_buf; newTemplate[ulCount].ulValueLen = key_len; rv = process_object_attributes(newTemplate, attr_count - 1, &obj_ngk.ngk_in_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } rv = process_object_attributes(&newTemplate[ulCount], 1, &obj_ngk.ngk_out_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } /* Cannot create a token object with a READ-ONLY session. */ if (is_token_obj && session_p->ses_RO) { rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */ obj_ngk.ngk_session = session_p->k_session; obj_ngk.ngk_in_count = attr_count - 1; obj_ngk.ngk_out_count = 1; obj_ngk.ngk_mechanism.cm_type = k_mech_type; obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter; obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen; while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY, &obj_ngk)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value); } free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count); if (rv != CKR_OK) { goto failed_exit; } rv = get_object_attributes(&newTemplate[ulCount], 1, obj_ngk.ngk_out_attributes); free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } /* * CKA_VALUE_LEN is not stored with the secret key object, * so we remove it by shifting attributes down one. */ (void) remove_one_attribute(newTemplate, CKA_VALUE_LEN, attr_count, B_FALSE); rv = kernel_build_object(newTemplate, attr_count - 1, new_objp, session_p, KERNEL_GEN_KEY); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } new_objp->is_lib_obj = B_TRUE; new_objp->session_handle = (CK_SESSION_HANDLE)session_p; (void) free(newTemplate); bzero(key_buf, key_len); (void) free(key_buf); return (CKR_OK); failed_exit: free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count); free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count); if (key_buf != NULL) { bzero(key_buf, key_len); (void) free(key_buf); } if (newTemplate != NULL) { (void) free(newTemplate); } return (rv); } CK_RV C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv = CKR_OK; kernel_session_t *session_p; kernel_object_t *new_objp = NULL; kernel_slot_t *pslot; boolean_t ses_lock_held = B_FALSE; CK_BBOOL is_pri_obj; CK_BBOOL is_token_obj = FALSE; crypto_mech_type_t k_mech_type; int r; if (!kernel_initialized) return (CKR_CRYPTOKI_NOT_INITIALIZED); /* Obtain the session pointer */ rv = handle2session(hSession, &session_p); if (rv != CKR_OK) return (rv); if ((pMechanism == NULL) || (phKey == NULL)) { rv = CKR_ARGUMENTS_BAD; goto failed_exit; } if ((pTemplate == NULL) && (ulCount != 0)) { rv = CKR_ARGUMENTS_BAD; goto failed_exit; } /* Get the kernel's internal mechanism number. */ rv = kernel_mech(pMechanism->mechanism, &k_mech_type); if (rv != CKR_OK) { goto failed_exit; } /* Create an object wrapper in the library first */ new_objp = calloc(1, sizeof (kernel_object_t)); if (new_objp == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* * Special Case: if token does not support object creation, * but does support key generation by value, then create a session * object and initialize with value returned by token. */ pslot = slot_table[session_p->ses_slotid]; if (!pslot->sl_func_list.fl_object_create) { rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p, k_mech_type, new_objp); if (rv != CKR_OK) goto failed_exit; } else { crypto_object_generate_key_t obj_gk; /* Process the attributes */ rv = process_object_attributes(pTemplate, ulCount, &obj_gk.gk_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } /* Cannot create a token object with a READ-ONLY session. */ if (is_token_obj && session_p->ses_RO) { free_object_attributes(obj_gk.gk_attributes, ulCount); rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* Call the CRYPTO_GENERATE_KEY ioctl */ obj_gk.gk_session = session_p->k_session; obj_gk.gk_count = ulCount; obj_gk.gk_mechanism.cm_type = k_mech_type; obj_gk.gk_mechanism.cm_param = pMechanism->pParameter; obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen; while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY, &obj_gk)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_gk.gk_return_value); } free_object_attributes(obj_gk.gk_attributes, ulCount); if (rv != CKR_OK) { goto failed_exit; } /* Get the value of the CKA_PRIVATE attribute. */ rv = get_cka_private_value(session_p, obj_gk.gk_handle, &is_pri_obj); if (rv != CKR_OK) { goto failed_exit; } /* * Store the kernel object handle in the object wrapper and * initialize the library object. */ new_objp->k_handle = obj_gk.gk_handle; new_objp->is_lib_obj = B_FALSE; new_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_objp->extra_attrlistp = NULL; if (is_pri_obj) new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; else new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; if (is_token_obj) new_objp->bool_attr_mask |= TOKEN_BOOL_ON; else new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; } (void) pthread_mutex_init(&new_objp->object_mutex, NULL); new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; /* * Add the new object to the slot's token object list if it is a * a token object. Otherwise, add it to the session's object list. */ if (is_token_obj) { pslot = slot_table[session_p->ses_slotid]; kernel_add_token_object_to_slot(new_objp, pslot); } else { kernel_add_object_to_session(new_objp, session_p); } *phKey = (CK_OBJECT_HANDLE)new_objp; REFRELE(session_p, ses_lock_held); return (rv); failed_exit: if (new_objp != NULL) { (void) free(new_objp); } REFRELE(session_p, ses_lock_held); return (rv); } CK_RV key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, kernel_session_t *session_p, crypto_mech_type_t k_mech_type, kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp) { crypto_nostore_generate_key_pair_t obj_nkp; CK_ATTRIBUTE_PTR pubTemplate = NULL; CK_ATTRIBUTE_PTR priTemplate = NULL; CK_RV rv = CKR_OK; CK_BBOOL is_token_obj1 = FALSE; CK_BBOOL is_token_obj2 = FALSE; uint_t pub_attr_count, pri_attr_count; uint_t pub_out_attr_count = 0, pri_out_attr_count = 0; char public_modulus[512]; char public_exponent[8]; char private_exponent[512]; char private_modulus[512]; char prime_1[512]; char prime_2[512]; char exponent_1[512]; char exponent_2[512]; char coefficient[512]; CK_ULONG pub_class = CKO_PUBLIC_KEY; CK_ULONG pri_class = CKO_PRIVATE_KEY; CK_ULONG key_type; CK_ULONG modulus_bytes; boolean_t has_class, has_key_type, has_pub_exponent; int n, r; obj_nkp.nkp_in_public_count = 0; obj_nkp.nkp_out_public_count = 0; obj_nkp.nkp_in_private_count = 0; obj_nkp.nkp_out_private_count = 0; /* modulus bits must be present when generating a RSA key pair */ if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate, ulPublicKeyAttributeCount)) { rv = CKR_TEMPLATE_INCOMPLETE; goto failed_exit; } modulus_bytes = get_modulus_bytes(pPublicKeyTemplate, ulPublicKeyAttributeCount); /* * Add CKA_MODULUS to the public template. * This attribute must not be in the template. */ if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate, ulPublicKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate, ulPublicKeyAttributeCount); has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate, ulPublicKeyAttributeCount); has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT, pPublicKeyTemplate, ulPublicKeyAttributeCount); pub_attr_count = ulPublicKeyAttributeCount + 1; if (!has_class) pub_attr_count++; if (!has_key_type) pub_attr_count++; if (!has_pub_exponent) pub_attr_count++; pubTemplate = grow_template(pPublicKeyTemplate, ulPublicKeyAttributeCount, pub_attr_count); if (pubTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulPublicKeyAttributeCount; if (!has_class) { pubTemplate[n].type = CKA_CLASS; pubTemplate[n].pValue = (caddr_t)&pub_class; pubTemplate[n].ulValueLen = sizeof (pub_class); n++; } if (!has_key_type) { pubTemplate[n].type = CKA_KEY_TYPE; key_type = CKK_RSA; pubTemplate[n].pValue = (caddr_t)&key_type; pubTemplate[n].ulValueLen = sizeof (key_type); n++; } if (!has_pub_exponent) { pubTemplate[n].type = CKA_PUBLIC_EXPONENT; pubTemplate[n].pValue = (caddr_t)public_exponent; pubTemplate[n].ulValueLen = modulus_bytes; n++; pub_out_attr_count++; } pubTemplate[n].type = CKA_MODULUS; pubTemplate[n].pValue = (caddr_t)public_modulus; pubTemplate[n].ulValueLen = modulus_bytes; pub_out_attr_count++; rv = process_object_attributes(pubTemplate, pub_attr_count - pub_out_attr_count, &obj_nkp.nkp_in_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count; rv = process_object_attributes( &pubTemplate[pub_attr_count - pub_out_attr_count], pub_out_attr_count, &obj_nkp.nkp_out_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_out_public_count = pub_out_attr_count; /* * Cannot create a token object with a READ-ONLY * session. */ if (is_token_obj1 && session_p->ses_RO) { rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT * to the private template. These attributes * must not be in the template. */ if (attribute_in_template(CKA_PRIVATE_EXPONENT, pPrivateKeyTemplate, ulPrivateKeyAttributeCount) || attribute_in_template(CKA_MODULUS, pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); pri_attr_count = ulPrivateKeyAttributeCount + 7; if (!has_class) pri_attr_count++; if (!has_key_type) pri_attr_count++; /* allocate space for CKA_PUBLIC_EXPONENT */ priTemplate = grow_template(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, pri_attr_count + 1); if (priTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulPrivateKeyAttributeCount; if (!has_class) { priTemplate[n].type = CKA_CLASS; priTemplate[n].pValue = (caddr_t)&pri_class; priTemplate[n].ulValueLen = sizeof (pri_class); n++; } if (!has_key_type) { priTemplate[n].type = CKA_KEY_TYPE; key_type = CKK_RSA; priTemplate[n].pValue = (caddr_t)&key_type; priTemplate[n].ulValueLen = sizeof (key_type); n++; } priTemplate[n].type = CKA_MODULUS; priTemplate[n].pValue = (caddr_t)private_modulus; priTemplate[n].ulValueLen = modulus_bytes; pri_out_attr_count++; n++; priTemplate[n].type = CKA_PRIVATE_EXPONENT; priTemplate[n].pValue = (caddr_t)private_exponent; priTemplate[n].ulValueLen = modulus_bytes; pri_out_attr_count++; n++; priTemplate[n].type = CKA_PRIME_1; priTemplate[n].pValue = (caddr_t)prime_1; priTemplate[n].ulValueLen = modulus_bytes/2; pri_out_attr_count++; n++; priTemplate[n].type = CKA_PRIME_2; priTemplate[n].pValue = (caddr_t)prime_2; priTemplate[n].ulValueLen = modulus_bytes/2; pri_out_attr_count++; n++; priTemplate[n].type = CKA_EXPONENT_1; priTemplate[n].pValue = (caddr_t)exponent_1; priTemplate[n].ulValueLen = modulus_bytes/2; pri_out_attr_count++; n++; priTemplate[n].type = CKA_EXPONENT_2; priTemplate[n].pValue = (caddr_t)exponent_2; priTemplate[n].ulValueLen = modulus_bytes/2; pri_out_attr_count++; n++; priTemplate[n].type = CKA_COEFFICIENT; priTemplate[n].pValue = (caddr_t)coefficient; priTemplate[n].ulValueLen = modulus_bytes/2; pri_out_attr_count++; rv = process_object_attributes(priTemplate, pri_attr_count - pri_out_attr_count, &obj_nkp.nkp_in_private_attributes, &is_token_obj2); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count; rv = process_object_attributes( &priTemplate[pri_attr_count - pri_out_attr_count], pri_out_attr_count, &obj_nkp.nkp_out_private_attributes, &is_token_obj2); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_out_private_count = pri_out_attr_count; /* * The public key and the private key need to contain the same * attribute values for CKA_TOKEN. */ if (is_token_obj1 != is_token_obj2) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto failed_exit; } /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */ obj_nkp.nkp_session = session_p-> k_session; obj_nkp.nkp_mechanism.cm_type = k_mech_type; obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter; obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen; while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR, &obj_nkp)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value); } free_attributes(obj_nkp.nkp_in_public_attributes, &obj_nkp.nkp_in_public_count); free_attributes(obj_nkp.nkp_in_private_attributes, &obj_nkp.nkp_in_private_count); if (rv != CKR_OK) { goto failed_exit; } rv = get_object_attributes( &pubTemplate[pub_attr_count - pub_out_attr_count], pub_out_attr_count, obj_nkp.nkp_out_public_attributes); if (rv == CRYPTO_SUCCESS) { rv = get_object_attributes( &priTemplate[pri_attr_count - pri_out_attr_count], pri_out_attr_count, obj_nkp.nkp_out_private_attributes); } free_attributes(obj_nkp.nkp_out_public_attributes, &obj_nkp.nkp_out_public_count); free_attributes(obj_nkp.nkp_out_private_attributes, &obj_nkp.nkp_out_private_count); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } /* store generated modulus and public exponent */ rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp, session_p, KERNEL_GEN_KEY); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } /* * Copy CKA_PUBLIC_EXPONENT from the public template * to the private template. */ rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate, pub_attr_count, &priTemplate[pri_attr_count]); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp, session_p, KERNEL_GEN_KEY); (void) free(priTemplate[pri_attr_count].pValue); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } (void) free(pubTemplate); (void) free(priTemplate); new_pub_objp->is_lib_obj = B_TRUE; new_pri_objp->is_lib_obj = B_TRUE; new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p; (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL); new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL); new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; return (CKR_OK); failed_exit: free_attributes(obj_nkp.nkp_in_public_attributes, &obj_nkp.nkp_in_public_count); free_attributes(obj_nkp.nkp_out_public_attributes, &obj_nkp.nkp_out_public_count); free_attributes(obj_nkp.nkp_in_private_attributes, &obj_nkp.nkp_in_private_count); free_attributes(obj_nkp.nkp_out_private_attributes, &obj_nkp.nkp_out_private_count); if (pubTemplate != NULL) { (void) free(pubTemplate); } if (priTemplate != NULL) { (void) free(priTemplate); } return (rv); } CK_RV key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, kernel_session_t *session_p, crypto_mech_type_t k_mech_type, kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp) { crypto_nostore_generate_key_pair_t obj_nkp; CK_ATTRIBUTE_PTR pubTemplate = NULL; CK_ATTRIBUTE_PTR priTemplate = NULL; CK_RV rv = CKR_OK; CK_BBOOL is_token_obj1 = FALSE; CK_BBOOL is_token_obj2 = FALSE; uint_t pub_attr_count, pri_attr_count; uint_t pub_out_attr_count = 0, pri_out_attr_count = 0; char public_value[256]; char private_value[256]; CK_ULONG pub_class = CKO_PUBLIC_KEY; CK_ULONG pri_class = CKO_PRIVATE_KEY; CK_ULONG key_type; boolean_t has_class, has_key_type; int n, r; obj_nkp.nkp_in_public_count = 0; obj_nkp.nkp_out_public_count = 0; obj_nkp.nkp_in_private_count = 0; obj_nkp.nkp_out_private_count = 0; /* * Add CKA_VALUE to the public template. * This attribute must not be in the template. */ if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate, ulPublicKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate, ulPublicKeyAttributeCount); has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate, ulPublicKeyAttributeCount); pub_attr_count = ulPublicKeyAttributeCount + 1; if (!has_class) pub_attr_count++; if (!has_key_type) pub_attr_count++; pubTemplate = grow_template(pPublicKeyTemplate, ulPublicKeyAttributeCount, pub_attr_count); if (pubTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulPublicKeyAttributeCount; if (!has_class) { pubTemplate[n].type = CKA_CLASS; pubTemplate[n].pValue = (caddr_t)&pub_class; pubTemplate[n].ulValueLen = sizeof (pub_class); n++; } if (!has_key_type) { pubTemplate[n].type = CKA_KEY_TYPE; key_type = CKK_DH; pubTemplate[n].pValue = (caddr_t)&key_type; pubTemplate[n].ulValueLen = sizeof (key_type); n++; } pubTemplate[n].type = CKA_VALUE; pubTemplate[n].pValue = (caddr_t)public_value; pubTemplate[n].ulValueLen = sizeof (public_value); pub_out_attr_count++; rv = process_object_attributes(pubTemplate, pub_attr_count - pub_out_attr_count, &obj_nkp.nkp_in_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count; rv = process_object_attributes( &pubTemplate[pub_attr_count - pub_out_attr_count], pub_out_attr_count, &obj_nkp.nkp_out_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_out_public_count = pub_out_attr_count; /* * Cannot create a token object with a READ-ONLY * session. */ if (is_token_obj1 && session_p->ses_RO) { rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear * in private template. */ if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount) || attribute_in_template(CKA_PRIME, pPrivateKeyTemplate, ulPrivateKeyAttributeCount) || attribute_in_template(CKA_VALUE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); pri_attr_count = ulPrivateKeyAttributeCount + 1; if (!has_class) pri_attr_count++; if (!has_key_type) pri_attr_count++; /* allocate space for CKA_BASE and CKA_PRIME */ priTemplate = grow_template(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, pri_attr_count + 2); if (priTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulPrivateKeyAttributeCount; if (!has_class) { priTemplate[n].type = CKA_CLASS; priTemplate[n].pValue = (caddr_t)&pri_class; priTemplate[n].ulValueLen = sizeof (pri_class); n++; } if (!has_key_type) { priTemplate[n].type = CKA_KEY_TYPE; key_type = CKK_DH; priTemplate[n].pValue = (caddr_t)&key_type; priTemplate[n].ulValueLen = sizeof (key_type); n++; } priTemplate[n].type = CKA_VALUE; priTemplate[n].pValue = (caddr_t)private_value; priTemplate[n].ulValueLen = sizeof (private_value); pri_out_attr_count++; rv = process_object_attributes(priTemplate, pri_attr_count - pri_out_attr_count, &obj_nkp.nkp_in_private_attributes, &is_token_obj2); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count; rv = process_object_attributes( &priTemplate[pri_attr_count - pri_out_attr_count], pri_out_attr_count, &obj_nkp.nkp_out_private_attributes, &is_token_obj2); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_out_private_count = pri_out_attr_count; /* * The public key and the private key need to contain the same * attribute values for CKA_TOKEN. */ if (is_token_obj1 != is_token_obj2) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto failed_exit; } /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */ obj_nkp.nkp_session = session_p-> k_session; obj_nkp.nkp_mechanism.cm_type = k_mech_type; obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter; obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen; while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR, &obj_nkp)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value); } free_attributes(obj_nkp.nkp_in_public_attributes, &obj_nkp.nkp_in_public_count); free_attributes(obj_nkp.nkp_in_private_attributes, &obj_nkp.nkp_in_private_count); if (rv != CKR_OK) { goto failed_exit; } rv = get_object_attributes( &pubTemplate[pub_attr_count - pub_out_attr_count], pub_out_attr_count, obj_nkp.nkp_out_public_attributes); if (rv == CRYPTO_SUCCESS) { rv = get_object_attributes( &priTemplate[pri_attr_count - pri_out_attr_count], pri_out_attr_count, obj_nkp.nkp_out_private_attributes); } free_attributes(obj_nkp.nkp_out_public_attributes, &obj_nkp.nkp_out_public_count); free_attributes(obj_nkp.nkp_out_private_attributes, &obj_nkp.nkp_out_private_count); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp, session_p, KERNEL_GEN_KEY); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } /* * Copy CKA_BASE and CKA_PRIME from the public template * to the private template. */ rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count, &priTemplate[pri_attr_count]); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count, &priTemplate[pri_attr_count + 1]); if (rv != CRYPTO_SUCCESS) { (void) free(priTemplate[pri_attr_count].pValue); goto failed_exit; } /* +2 to account for CKA_BASE and CKA_PRIME */ rv = kernel_build_object(priTemplate, pri_attr_count + 2, new_pri_objp, session_p, KERNEL_GEN_KEY); (void) free(priTemplate[pri_attr_count].pValue); (void) free(priTemplate[pri_attr_count + 1].pValue); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } (void) free(pubTemplate); (void) free(priTemplate); new_pub_objp->is_lib_obj = B_TRUE; new_pri_objp->is_lib_obj = B_TRUE; new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p; (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL); new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL); new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; return (CKR_OK); failed_exit: free_attributes(obj_nkp.nkp_in_public_attributes, &obj_nkp.nkp_in_public_count); free_attributes(obj_nkp.nkp_out_public_attributes, &obj_nkp.nkp_out_public_count); free_attributes(obj_nkp.nkp_in_private_attributes, &obj_nkp.nkp_in_private_count); free_attributes(obj_nkp.nkp_out_private_attributes, &obj_nkp.nkp_out_private_count); if (pubTemplate != NULL) { (void) free(pubTemplate); } if (priTemplate != NULL) { (void) free(priTemplate); } return (rv); } CK_RV key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, kernel_session_t *session_p, crypto_mech_type_t k_mech_type, kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp) { crypto_nostore_generate_key_pair_t obj_nkp; CK_ATTRIBUTE_PTR pubTemplate = NULL; CK_ATTRIBUTE_PTR priTemplate = NULL; CK_RV rv = CKR_OK; CK_BBOOL is_token_obj1 = FALSE; CK_BBOOL is_token_obj2 = FALSE; uint_t pub_attr_count, pri_attr_count; uint_t pub_out_attr_count = 0, pri_out_attr_count = 0; char value[EC_MAX_VALUE_LEN]; char point[EC_MAX_POINT_LEN]; CK_ULONG pub_class = CKO_PUBLIC_KEY; CK_ULONG pri_class = CKO_PRIVATE_KEY; CK_ULONG key_type; boolean_t has_class, has_key_type; int n, r; obj_nkp.nkp_in_public_count = 0; obj_nkp.nkp_out_public_count = 0; obj_nkp.nkp_in_private_count = 0; obj_nkp.nkp_out_private_count = 0; /* * Add CKA_EC_POINT to the public template. * This is the generated value Q. This attribute * must not be in the template. */ if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate, ulPublicKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate, ulPublicKeyAttributeCount); has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate, ulPublicKeyAttributeCount); pub_attr_count = ulPublicKeyAttributeCount + 1; if (!has_class) pub_attr_count++; if (!has_key_type) pub_attr_count++; pubTemplate = grow_template(pPublicKeyTemplate, ulPublicKeyAttributeCount, pub_attr_count); if (pubTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulPublicKeyAttributeCount; if (!has_class) { pubTemplate[n].type = CKA_CLASS; pubTemplate[n].pValue = (caddr_t)&pub_class; pubTemplate[n].ulValueLen = sizeof (pub_class); n++; } if (!has_key_type) { pubTemplate[n].type = CKA_KEY_TYPE; key_type = CKK_EC; pubTemplate[n].pValue = (caddr_t)&key_type; pubTemplate[n].ulValueLen = sizeof (key_type); n++; } pubTemplate[n].type = CKA_EC_POINT; pubTemplate[n].pValue = (caddr_t)point; pubTemplate[n].ulValueLen = sizeof (point); pub_out_attr_count++; rv = process_object_attributes(pubTemplate, pub_attr_count - pub_out_attr_count, &obj_nkp.nkp_in_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count; rv = process_object_attributes( &pubTemplate[pub_attr_count - pub_out_attr_count], pub_out_attr_count, &obj_nkp.nkp_out_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_out_public_count = pub_out_attr_count; /* * Cannot create a token object with a READ-ONLY * session. */ if (is_token_obj1 && session_p->ses_RO) { rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* * CKA_EC_PARAMS and CKA_VALUE must not appear in * private template. */ if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate, ulPrivateKeyAttributeCount) || attribute_in_template(CKA_VALUE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) { rv = CKR_TEMPLATE_INCONSISTENT; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate, ulPrivateKeyAttributeCount); pri_attr_count = ulPrivateKeyAttributeCount + 1; if (!has_class) pri_attr_count++; if (!has_key_type) pri_attr_count++; /* allocate space for CKA_EC_PARAMS */ priTemplate = grow_template(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, pri_attr_count + 1); if (priTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulPrivateKeyAttributeCount; if (!has_class) { priTemplate[n].type = CKA_CLASS; priTemplate[n].pValue = (caddr_t)&pri_class; priTemplate[n].ulValueLen = sizeof (pri_class); n++; } if (!has_key_type) { priTemplate[n].type = CKA_KEY_TYPE; key_type = CKK_EC; priTemplate[n].pValue = (caddr_t)&key_type; priTemplate[n].ulValueLen = sizeof (key_type); n++; } priTemplate[n].type = CKA_VALUE; priTemplate[n].pValue = (caddr_t)value; priTemplate[n].ulValueLen = sizeof (value); pri_out_attr_count++; rv = process_object_attributes(priTemplate, pri_attr_count - pri_out_attr_count, &obj_nkp.nkp_in_private_attributes, &is_token_obj2); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count; rv = process_object_attributes( &priTemplate[pri_attr_count - pri_out_attr_count], pri_out_attr_count, &obj_nkp.nkp_out_private_attributes, &is_token_obj2); if (rv != CKR_OK) { goto failed_exit; } obj_nkp.nkp_out_private_count = pri_out_attr_count; /* * The public key and the private key need to contain the same * attribute values for CKA_TOKEN. */ if (is_token_obj1 != is_token_obj2) { rv = CKR_ATTRIBUTE_VALUE_INVALID; goto failed_exit; } /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */ obj_nkp.nkp_session = session_p-> k_session; obj_nkp.nkp_mechanism.cm_type = k_mech_type; obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter; obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen; while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR, &obj_nkp)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value); } free_attributes(obj_nkp.nkp_in_public_attributes, &obj_nkp.nkp_in_public_count); free_attributes(obj_nkp.nkp_in_private_attributes, &obj_nkp.nkp_in_private_count); if (rv != CKR_OK) { goto failed_exit; } rv = get_object_attributes( &pubTemplate[pub_attr_count - pub_out_attr_count], pub_out_attr_count, obj_nkp.nkp_out_public_attributes); if (rv == CRYPTO_SUCCESS) { rv = get_object_attributes( &priTemplate[pri_attr_count - pri_out_attr_count], pri_out_attr_count, obj_nkp.nkp_out_private_attributes); } free_attributes(obj_nkp.nkp_out_public_attributes, &obj_nkp.nkp_out_public_count); free_attributes(obj_nkp.nkp_out_private_attributes, &obj_nkp.nkp_out_private_count); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp, session_p, KERNEL_GEN_KEY); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } /* * Copy CKA_EC_PARAMS from the public template to the * private template. */ rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count, &priTemplate[pri_attr_count]); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } /* +1 to account for CKA_EC_PARAMS */ rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp, session_p, KERNEL_GEN_KEY); (void) free(priTemplate[pri_attr_count].pValue); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } (void) free(pubTemplate); (void) free(priTemplate); new_pub_objp->is_lib_obj = B_TRUE; new_pri_objp->is_lib_obj = B_TRUE; new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p; (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL); new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL); new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; return (CKR_OK); failed_exit: free_attributes(obj_nkp.nkp_in_public_attributes, &obj_nkp.nkp_in_public_count); free_attributes(obj_nkp.nkp_out_public_attributes, &obj_nkp.nkp_out_public_count); free_attributes(obj_nkp.nkp_in_private_attributes, &obj_nkp.nkp_in_private_count); free_attributes(obj_nkp.nkp_out_private_attributes, &obj_nkp.nkp_out_private_count); if (pubTemplate != NULL) { (void) free(pubTemplate); } if (priTemplate != NULL) { (void) free(priTemplate); } return (rv); } CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { CK_RV rv = CKR_OK; kernel_session_t *session_p; kernel_object_t *new_pub_objp = NULL; kernel_object_t *new_pri_objp = NULL; kernel_slot_t *pslot; boolean_t ses_lock_held = B_FALSE; CK_BBOOL is_pri_obj1; CK_BBOOL is_pri_obj2; CK_BBOOL is_token_obj1 = FALSE; CK_BBOOL is_token_obj2 = FALSE; crypto_mech_type_t k_mech_type; int r; CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG, CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t, kernel_object_t *, kernel_object_t *); if (!kernel_initialized) return (CKR_CRYPTOKI_NOT_INITIALIZED); /* Obtain the session pointer. */ rv = handle2session(hSession, &session_p); if (rv != CKR_OK) return (rv); if ((pMechanism == NULL) || (phPublicKey == NULL) || (phPrivateKey == NULL)) { rv = CKR_ARGUMENTS_BAD; goto failed_exit; } if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) { rv = CKR_ARGUMENTS_BAD; goto failed_exit; } if ((pPrivateKeyTemplate == NULL) && (ulPrivateKeyAttributeCount != 0)) { rv = CKR_ARGUMENTS_BAD; goto failed_exit; } /* Get the kernel's internal mechanism number. */ rv = kernel_mech(pMechanism->mechanism, &k_mech_type); if (rv != CKR_OK) { goto failed_exit; } /* Create an object wrapper for the public key */ new_pub_objp = calloc(1, sizeof (kernel_object_t)); if (new_pub_objp == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* Create an object wrapper for the private key. */ new_pri_objp = calloc(1, sizeof (kernel_object_t)); if (new_pri_objp == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* * Special Case: if token does not support object creation, * but does support key generation by value, then create a session * object and initialize with values returned by token. */ pslot = slot_table[session_p->ses_slotid]; if (!pslot->sl_func_list.fl_object_create) { switch (pMechanism->mechanism) { case CKM_RSA_PKCS_KEY_PAIR_GEN: func = key_gen_rsa_by_value; break; case CKM_DH_PKCS_KEY_PAIR_GEN: func = key_gen_dh_by_value; break; case CKM_EC_KEY_PAIR_GEN: func = key_gen_ec_by_value; break; default: rv = CKR_MECHANISM_INVALID; goto failed_exit; } rv = (*func)(pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, session_p, k_mech_type, new_pub_objp, new_pri_objp); if (rv != CKR_OK) goto failed_exit; } else { crypto_object_generate_key_pair_t obj_kp; /* Process the public key attributes. */ rv = process_object_attributes(pPublicKeyTemplate, ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes, &is_token_obj1); if (rv != CKR_OK) { goto failed_exit; } /* Cannot create a token object with a READ-ONLY session. */ if (is_token_obj1 && session_p->ses_RO) { free_object_attributes(obj_kp.kp_public_attributes, ulPublicKeyAttributeCount); rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* Process the private key attributes. */ rv = process_object_attributes(pPrivateKeyTemplate, ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes, &is_token_obj2); if (rv != CKR_OK) { free_object_attributes(obj_kp.kp_public_attributes, ulPublicKeyAttributeCount); goto failed_exit; } /* * The public key and the private key need to contain the same * attribute values for CKA_TOKEN. */ if (is_token_obj1 != is_token_obj2) { free_object_attributes(obj_kp.kp_public_attributes, ulPublicKeyAttributeCount); free_object_attributes(obj_kp.kp_private_attributes, ulPrivateKeyAttributeCount); rv = CKR_ATTRIBUTE_VALUE_INVALID; goto failed_exit; } /* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */ obj_kp.kp_session = session_p-> k_session; obj_kp.kp_mechanism.cm_type = k_mech_type; obj_kp.kp_mechanism.cm_param = pMechanism->pParameter; obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen; obj_kp.kp_public_count = ulPublicKeyAttributeCount; obj_kp.kp_private_count = ulPrivateKeyAttributeCount; while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR, &obj_kp)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_kp.kp_return_value); } free_object_attributes(obj_kp.kp_public_attributes, ulPublicKeyAttributeCount); free_object_attributes(obj_kp.kp_private_attributes, ulPrivateKeyAttributeCount); if (rv != CKR_OK) goto failed_exit; /* Get the CKA_PRIVATE value for the key pair. */ rv = get_cka_private_value(session_p, obj_kp.kp_public_handle, &is_pri_obj1); if (rv != CKR_OK) { goto failed_exit; } rv = get_cka_private_value(session_p, obj_kp.kp_private_handle, &is_pri_obj2); if (rv != CKR_OK) { goto failed_exit; } /* * Store the kernel public key handle into the public key * object and finish the public key object initialization. */ new_pub_objp->is_lib_obj = B_FALSE; new_pub_objp->k_handle = obj_kp.kp_public_handle; new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_pub_objp->extra_attrlistp = NULL; if (is_pri_obj1) new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON; else new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; if (is_token_obj1) new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON; else new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL); new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; /* * Store the kernel private key handle into the private key * object and finish the private key object initialization. */ new_pri_objp->is_lib_obj = B_FALSE; new_pri_objp->k_handle = obj_kp.kp_private_handle; new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_pri_objp->extra_attrlistp = NULL; if (is_pri_obj2) new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON; else new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; if (is_token_obj2) new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON; else new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; } (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL); new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; /* * Add the new pub/pri objects to the slot's token list if they are * token objects. Otherwise, add them to the session's object list. */ if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */ pslot = slot_table[session_p->ses_slotid]; kernel_add_token_object_to_slot(new_pub_objp, pslot); kernel_add_token_object_to_slot(new_pri_objp, pslot); } else { kernel_add_object_to_session(new_pub_objp, session_p); kernel_add_object_to_session(new_pri_objp, session_p); } *phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp; *phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp; REFRELE(session_p, ses_lock_held); return (rv); failed_exit: if (new_pub_objp != NULL) { (void) free(new_pub_objp); } if (new_pri_objp != NULL) { (void) free(new_pri_objp); } REFRELE(session_p, ses_lock_held); return (rv); } CK_RV C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey, CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen) { CK_RV rv = CKR_OK; kernel_session_t *session_p; boolean_t ses_lock_held = B_FALSE; kernel_object_t *wrappingkey_p; kernel_object_t *key_p; crypto_mech_type_t k_mech_type; crypto_object_wrap_key_t obj_wrapkey; int r; if (!kernel_initialized) return (CKR_CRYPTOKI_NOT_INITIALIZED); if (pulWrappedKeyLen == NULL || pMechanism == NULL) { return (CKR_ARGUMENTS_BAD); } /* * Obtain the session pointer. Also, increment the session * reference count. */ rv = handle2session(hSession, &session_p); if (rv != CKR_OK) return (rv); /* Get the kernel's internal mechanism number. */ rv = kernel_mech(pMechanism->mechanism, &k_mech_type); if (rv != CKR_OK) { REFRELE(session_p, ses_lock_held); return (rv); } /* Obtain the wrapping key object pointer. */ HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv); if (rv != CKR_OK) { REFRELE(session_p, ses_lock_held); return (rv); } /* Obtain the to_be_wrapped key object pointer. */ HANDLE2OBJECT(hKey, key_p, rv); if (rv != CKR_OK) { OBJ_REFRELE(wrappingkey_p); REFRELE(session_p, ses_lock_held); return (rv); } /* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */ obj_wrapkey.wk_session = session_p->k_session; obj_wrapkey.wk_mechanism.cm_type = k_mech_type; obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter; obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen; obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE; obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle; obj_wrapkey.wk_object_handle = key_p->k_handle; obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen; obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey; while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value); } /* * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen * when the applciation-supplied wrapped key buffer is too small. * The situation that the application only asks for the length of * the wrapped key is covered in rv == CKR_OK. */ if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) { *pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len; } OBJ_REFRELE(key_p); OBJ_REFRELE(wrappingkey_p); REFRELE(session_p, ses_lock_held); return (rv); } CK_RV C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv = CKR_OK; kernel_session_t *session_p; kernel_object_t *unwrappingkey_p; kernel_object_t *new_objp = NULL; kernel_slot_t *pslot; boolean_t ses_lock_held = B_FALSE; CK_BBOOL is_pri_obj; CK_BBOOL is_token_obj = FALSE; CK_MECHANISM_INFO info; uint32_t k_mi_flags; CK_BYTE *clear_key_val = NULL; CK_ULONG ulDataLen; CK_ATTRIBUTE_PTR newTemplate = NULL; crypto_mech_type_t k_mech_type; crypto_object_unwrap_key_t obj_unwrapkey; int r; if (!kernel_initialized) return (CKR_CRYPTOKI_NOT_INITIALIZED); if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) { return (CKR_ARGUMENTS_BAD); } if ((pTemplate == NULL) && (ulAttributeCount != 0)) { return (CKR_ARGUMENTS_BAD); } /* Obtain the session pointer. */ rv = handle2session(hSession, &session_p); if (rv != CKR_OK) return (rv); /* Obtain the wrapping key object pointer. */ HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv); if (rv != CKR_OK) { REFRELE(session_p, ses_lock_held); return (rv); } /* * If the HW provider doesn't support C_UnwrapKey, we will try * to emulate it in the library. */ pslot = slot_table[session_p->ses_slotid]; if ((!pslot->sl_func_list.fl_object_create) && (!pslot->sl_func_list.fl_key_unwrap)) { rv = get_mechanism_info(pslot, pMechanism->mechanism, &info, &k_mi_flags); if (rv != CKR_OK) { goto failed_exit; } /* * If the mechanism flag doesn't have CKF_UNWRAP, and it's * an unwrapping of a secret key object, then help this * out with a decryption followed by an object creation. */ if (!(k_mi_flags & CRYPTO_FG_UNWRAP) && (k_mi_flags & CRYPTO_FG_DECRYPT) && (is_secret_key_template(pTemplate, ulAttributeCount))) { /* First allocate space for the recovered key value */ clear_key_val = malloc(ulWrappedKeyLen); if (clear_key_val == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } rv = kernel_decrypt_init(session_p, unwrappingkey_p, pMechanism); if (rv != CKR_OK) { goto failed_exit; } ulDataLen = ulWrappedKeyLen; rv = kernel_decrypt(session_p, pWrappedKey, ulWrappedKeyLen, clear_key_val, &ulDataLen); if (rv != CKR_OK) { goto failed_exit; } newTemplate = grow_template(pTemplate, ulAttributeCount, ulAttributeCount + 1); if (newTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* Now add the CKA_VALUE attribute to template */ newTemplate[ulAttributeCount].type = CKA_VALUE; newTemplate[ulAttributeCount].pValue = clear_key_val; newTemplate[ulAttributeCount].ulValueLen = ulDataLen; /* Finally create the key, based on the new template */ rv = kernel_add_object(newTemplate, ulAttributeCount + 1, phKey, session_p); (void) free(clear_key_val); (void) free(newTemplate); OBJ_REFRELE(unwrappingkey_p); REFRELE(session_p, ses_lock_held); return (rv); } else { rv = CKR_FUNCTION_FAILED; goto failed_exit; } } /* * If we come here, the HW provider must have registered the unwrapkey * entry. Therefore, the unwrap key will be performed in the HW * provider. */ rv = kernel_mech(pMechanism->mechanism, &k_mech_type); if (rv != CKR_OK) { goto failed_exit; } /* Create an object wrapper for the new key in the library first */ new_objp = calloc(1, sizeof (kernel_object_t)); if (new_objp == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* Process the attributes */ rv = process_object_attributes(pTemplate, ulAttributeCount, &obj_unwrapkey.uk_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } /* Cannot create a token object with a READ-ONLY session. */ if (is_token_obj && session_p->ses_RO) { free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount); rv = CKR_SESSION_READ_ONLY; goto failed_exit; } /* Make the CRYPTO_UNWRAP_KEY ioctl call. */ obj_unwrapkey.uk_session = session_p->k_session; obj_unwrapkey.uk_mechanism.cm_type = k_mech_type; obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter; obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen; obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE; obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle; obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey; obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen; obj_unwrapkey.uk_count = ulAttributeCount; while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value); } free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount); if (rv != CKR_OK) { goto failed_exit; } /* Get the CKA_PRIVATE value for the unwrapped key. */ rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle, &is_pri_obj); if (rv != CKR_OK) { goto failed_exit; } /* * Store the kernel object handle in the new key object wrapper and * initialize it. */ new_objp->k_handle = obj_unwrapkey.uk_object_handle; new_objp->is_lib_obj = B_FALSE; new_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_objp->extra_attrlistp = NULL; if (is_pri_obj) new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; else new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; if (is_token_obj) new_objp->bool_attr_mask |= TOKEN_BOOL_ON; else new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; (void) pthread_mutex_init(&new_objp->object_mutex, NULL); new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; /* * Add the new object to the slot's token object list if it is a * a token object. Otherwise, add it to the session's object list. */ if (is_token_obj) { pslot = slot_table[session_p->ses_slotid]; kernel_add_token_object_to_slot(new_objp, pslot); } else { kernel_add_object_to_session(new_objp, session_p); } *phKey = (CK_OBJECT_HANDLE)new_objp; OBJ_REFRELE(unwrappingkey_p); REFRELE(session_p, ses_lock_held); return (rv); failed_exit: OBJ_REFRELE(unwrappingkey_p); if (new_objp != NULL) (void) free(new_objp); if (clear_key_val != NULL) (void) free(clear_key_val); if (newTemplate != NULL) (void) free(newTemplate); REFRELE(session_p, ses_lock_held); return (rv); } /* * Get sufficient attributes from a base key to pass by value in a * crypto_key structure. Storage for attributes is allocated. * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT. * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE. */ static int get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value) { CK_ATTRIBUTE tmp; crypto_object_attribute_t *attrs = NULL; biginteger_t *big; int i, count = 0, rv; switch (base_key->key_type) { case CKK_EC: count = 2; attrs = malloc(count * sizeof (crypto_object_attribute_t)); if (attrs == NULL) { rv = CKR_HOST_MEMORY; goto out; } bzero(attrs, count * sizeof (crypto_object_attribute_t)); (void) pthread_mutex_lock(&base_key->object_mutex); if (!base_key->is_lib_obj) { rv = CRYPTO_ARGUMENTS_BAD; goto out; } if (base_key->class != CKO_PUBLIC_KEY && base_key->class != CKO_PRIVATE_KEY) { rv = CRYPTO_ARGUMENTS_BAD; goto out; } /* * Both public and private EC keys should have * a CKA_EC_PARAMS attribute. */ tmp.type = CKA_EC_PARAMS; tmp.pValue = NULL; /* get size of attribute */ rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { goto out; } tmp.pValue = malloc(tmp.ulValueLen); if (tmp.pValue == NULL) { rv = CKR_HOST_MEMORY; goto out; } rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { free(tmp.pValue); goto out; } attrs[0].oa_type = tmp.type; attrs[0].oa_value = tmp.pValue; attrs[0].oa_value_len = tmp.ulValueLen; switch (base_key->class) { case CKO_PUBLIC_KEY: big = OBJ_PUB_EC_POINT(base_key); tmp.type = CKA_EC_POINT; break; case CKO_PRIVATE_KEY: big = OBJ_PRI_EC_VALUE(base_key); tmp.type = CKA_VALUE; break; default: rv = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } tmp.ulValueLen = big->big_value_len; tmp.pValue = malloc(tmp.ulValueLen); if (tmp.pValue == NULL) { rv = CKR_HOST_MEMORY; goto out; } rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { free(tmp.pValue); goto out; } attrs[1].oa_type = tmp.type; attrs[1].oa_value = tmp.pValue; attrs[1].oa_value_len = tmp.ulValueLen; key_by_value->ck_attrs = attrs; key_by_value->ck_count = 2; break; case CKK_DH: count = 3; attrs = malloc(count * sizeof (crypto_object_attribute_t)); if (attrs == NULL) { rv = CKR_HOST_MEMORY; goto out; } bzero(attrs, count * sizeof (crypto_object_attribute_t)); (void) pthread_mutex_lock(&base_key->object_mutex); if (!base_key->is_lib_obj) { rv = CRYPTO_ARGUMENTS_BAD; goto out; } if (base_key->class != CKO_PRIVATE_KEY) { rv = CRYPTO_ARGUMENTS_BAD; goto out; } tmp.type = CKA_BASE; tmp.pValue = NULL; /* get size of attribute */ rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { goto out; } tmp.pValue = malloc(tmp.ulValueLen); if (tmp.pValue == NULL) { rv = CKR_HOST_MEMORY; goto out; } rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { free(tmp.pValue); goto out; } attrs[0].oa_type = tmp.type; attrs[0].oa_value = tmp.pValue; attrs[0].oa_value_len = tmp.ulValueLen; tmp.type = CKA_PRIME; tmp.pValue = NULL; /* get size of attribute */ rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { goto out; } tmp.pValue = malloc(tmp.ulValueLen); if (tmp.pValue == NULL) { rv = CKR_HOST_MEMORY; goto out; } rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { free(tmp.pValue); goto out; } attrs[1].oa_type = tmp.type; attrs[1].oa_value = tmp.pValue; attrs[1].oa_value_len = tmp.ulValueLen; big = OBJ_PRI_DH_VALUE(base_key); tmp.type = CKA_VALUE; tmp.ulValueLen = big->big_value_len; tmp.pValue = malloc(tmp.ulValueLen); if (tmp.pValue == NULL) { rv = CKR_HOST_MEMORY; goto out; } rv = kernel_get_attribute(base_key, &tmp); if (rv != CKR_OK) { free(tmp.pValue); goto out; } attrs[2].oa_type = tmp.type; attrs[2].oa_value = tmp.pValue; attrs[2].oa_value_len = tmp.ulValueLen; key_by_value->ck_attrs = attrs; key_by_value->ck_count = 3; break; default: rv = CKR_ATTRIBUTE_TYPE_INVALID; goto out; } (void) pthread_mutex_unlock(&base_key->object_mutex); return (CKR_OK); out: (void) pthread_mutex_unlock(&base_key->object_mutex); if (attrs != NULL) { for (i = 0; i < count; i++) { if (attrs[i].oa_value != NULL) free(attrs[i].oa_value); } free(attrs); } return (rv); } CK_RV derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, kernel_session_t *session_p, crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p, kernel_object_t *new_objp) { crypto_nostore_derive_key_t obj_ndk; char *key_buf = NULL; CK_ATTRIBUTE_PTR newTemplate = NULL; CK_BBOOL is_token_obj = FALSE; CK_RV rv = CKR_OK; CK_ULONG secret_class = CKO_SECRET_KEY; ulong_t key_len = 0; uint_t attr_count = 0; boolean_t removed; boolean_t has_class; int r, n; obj_ndk.ndk_in_count = 0; obj_ndk.ndk_out_count = 0; obj_ndk.ndk_base_key.ck_count = 0; rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount, basekey_p, &key_len); if (rv != CKR_OK) { goto failed_exit; } if ((key_buf = malloc(key_len)) == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } has_class = attribute_in_template(CKA_CLASS, pTemplate, ulAttributeCount); attr_count = ulAttributeCount + 1; if (!has_class) attr_count++; newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count); if (newTemplate == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } n = ulAttributeCount; if (!has_class) { newTemplate[n].type = CKA_CLASS; newTemplate[n].pValue = (caddr_t)&secret_class; newTemplate[n].ulValueLen = sizeof (secret_class); n++; } /* Add CKA_VALUE to the template */ newTemplate[n].type = CKA_VALUE; newTemplate[n].pValue = (caddr_t)key_buf; newTemplate[n].ulValueLen = key_len; rv = process_object_attributes(newTemplate, attr_count - 1, &obj_ndk.ndk_in_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } obj_ndk.ndk_in_count = attr_count - 1; rv = process_object_attributes(&newTemplate[attr_count - 1], 1, &obj_ndk.ndk_out_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } obj_ndk.ndk_out_count = 1; /* Cannot create a token object with a READ-ONLY session. */ if (is_token_obj && session_p->ses_RO) { rv = CKR_SESSION_READ_ONLY; goto failed_exit; } obj_ndk.ndk_session = session_p->k_session; obj_ndk.ndk_mechanism.cm_type = k_mech_type; obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter; obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen; /* * Obtain the attributes of base key and pass them by value. */ rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key); if (rv != CKR_OK) { goto failed_exit; } obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST; while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY, &obj_ndk)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value); } free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count); free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs, &obj_ndk.ndk_base_key.ck_count); if (rv != CKR_OK) { goto failed_exit; } rv = get_object_attributes(&newTemplate[attr_count - 1], 1, obj_ndk.ndk_out_attributes); free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN, attr_count, B_FALSE); rv = kernel_build_object(newTemplate, removed ? attr_count - 1 : attr_count, new_objp, session_p, KERNEL_GEN_KEY); if (rv != CRYPTO_SUCCESS) { goto failed_exit; } free(key_buf); free(newTemplate); new_objp->is_lib_obj = B_TRUE; new_objp->session_handle = (CK_SESSION_HANDLE)session_p; return (CKR_OK); failed_exit: if (key_buf != NULL) free(key_buf); if (newTemplate != NULL) free(newTemplate); free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count); free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count); free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs, &obj_ndk.ndk_base_key.ck_count); return (rv); } CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { CK_RV rv = CKR_OK; kernel_session_t *session_p; kernel_object_t *basekey_p; kernel_object_t *new_objp; kernel_slot_t *pslot; boolean_t ses_lock_held = B_FALSE; CK_BBOOL is_pri_obj; CK_BBOOL is_token_obj = FALSE; crypto_mech_type_t k_mech_type; int r; if (!kernel_initialized) return (CKR_CRYPTOKI_NOT_INITIALIZED); /* Obtain the session pointer. */ rv = handle2session(hSession, &session_p); if (rv != CKR_OK) return (rv); if (pMechanism == NULL) { REFRELE(session_p, ses_lock_held); return (CKR_ARGUMENTS_BAD); } if ((pTemplate == NULL && ulAttributeCount != 0) || (pTemplate != NULL && ulAttributeCount == 0)) { REFRELE(session_p, ses_lock_held); return (CKR_ARGUMENTS_BAD); } /* Obtain the base key object pointer. */ HANDLE2OBJECT(hBaseKey, basekey_p, rv); if (rv != CKR_OK) { REFRELE(session_p, ses_lock_held); return (rv); } /* Get the kernel's internal mechanism number. */ rv = kernel_mech(pMechanism->mechanism, &k_mech_type); if (rv != CKR_OK) { goto failed_exit; } /* Create an object wrapper in the library for the generated key. */ new_objp = calloc(1, sizeof (kernel_object_t)); if (new_objp == NULL) { rv = CKR_HOST_MEMORY; goto failed_exit; } /* * Special Case: if token does not support object creation, * but does support key derivation by value, then create a session * object and initialize with values returned by token. */ pslot = slot_table[session_p->ses_slotid]; if (!pslot->sl_func_list.fl_object_create) { rv = derive_key_by_value(pMechanism, pTemplate, ulAttributeCount, session_p, k_mech_type, basekey_p, new_objp); if (rv != CKR_OK) goto failed_exit; } else { crypto_derive_key_t obj_dk; rv = process_object_attributes(pTemplate, ulAttributeCount, &obj_dk.dk_attributes, &is_token_obj); if (rv != CKR_OK) { goto failed_exit; } /* Cannot create a token object with a READ-ONLY session. */ if (is_token_obj && session_p->ses_RO) { free_object_attributes(obj_dk.dk_attributes, ulAttributeCount); rv = CKR_SESSION_READ_ONLY; goto failed_exit; } obj_dk.dk_session = session_p->k_session; obj_dk.dk_mechanism.cm_type = k_mech_type; obj_dk.dk_mechanism.cm_param = pMechanism->pParameter; obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen; obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE; obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle; obj_dk.dk_count = ulAttributeCount; while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) { if (errno != EINTR) break; } if (r < 0) { rv = CKR_FUNCTION_FAILED; } else { rv = crypto2pkcs11_error_number(obj_dk.dk_return_value); } free_object_attributes(obj_dk.dk_attributes, ulAttributeCount); if (rv != CKR_OK) { goto failed_exit; } /* Get the CKA_PRIVATE value for the derived key. */ rv = get_cka_private_value(session_p, obj_dk.dk_object_handle, &is_pri_obj); if (rv != CKR_OK) { goto failed_exit; } /* * Store the kernel object handle into the new derived key * object and finish the object initialization. */ new_objp->is_lib_obj = B_FALSE; new_objp->k_handle = obj_dk.dk_object_handle; new_objp->session_handle = (CK_SESSION_HANDLE)session_p; new_objp->extra_attrlistp = NULL; if (is_pri_obj) new_objp->bool_attr_mask |= PRIVATE_BOOL_ON; else new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON; if (is_token_obj) new_objp->bool_attr_mask |= TOKEN_BOOL_ON; else new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON; } (void) pthread_mutex_init(&new_objp->object_mutex, NULL); new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC; /* * Add the new derived object to the slot's token list if it is a * token object. Otherwise, add it to the session's object list. */ if (is_token_obj) { pslot = slot_table[session_p->ses_slotid]; kernel_add_token_object_to_slot(new_objp, pslot); } else { kernel_add_object_to_session(new_objp, session_p); } *phKey = (CK_OBJECT_HANDLE)new_objp; OBJ_REFRELE(basekey_p); REFRELE(session_p, ses_lock_held); return (rv); failed_exit: OBJ_REFRELE(basekey_p); if (new_objp != NULL) { (void) free(new_objp); } REFRELE(session_p, ses_lock_held); return (rv); }