17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 590e0e8c4Sizick * Common Development and Distribution License (the "License"). 690e0e8c4Sizick * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*00756404SDarren J Moffat * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * Solaris specific functions to reduce the initialization 277c478bd9Sstevel@tonic-gate * overhead of using PKCS #11 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <security/cryptoki.h> 337c478bd9Sstevel@tonic-gate #include <assert.h> 347c478bd9Sstevel@tonic-gate #include <cryptoutil.h> 3590e0e8c4Sizick #include <pkcs11Global.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; 387c478bd9Sstevel@tonic-gate static CK_BBOOL falsevalue = FALSE; 397c478bd9Sstevel@tonic-gate static CK_BBOOL truevalue = TRUE; 407c478bd9Sstevel@tonic-gate 411c9bd843Sdinak #define NUM_SECRETKEY_ATTRS 12 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate typedef struct _ATTRTYPE_MECHINFO_MAPPING { 447c478bd9Sstevel@tonic-gate CK_ATTRIBUTE_TYPE attr; 457c478bd9Sstevel@tonic-gate CK_FLAGS flag; 467c478bd9Sstevel@tonic-gate } ATTRTYPE_MECHINFO_MAPPING; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* possible attribute types for creating key */ 497c478bd9Sstevel@tonic-gate ATTRTYPE_MECHINFO_MAPPING mapping[] = { 507c478bd9Sstevel@tonic-gate {CKA_ENCRYPT, CKF_ENCRYPT}, 517c478bd9Sstevel@tonic-gate {CKA_DECRYPT, CKF_DECRYPT}, 527c478bd9Sstevel@tonic-gate {CKA_SIGN, CKF_SIGN}, 531c9bd843Sdinak {CKA_VERIFY, CKF_VERIFY}, 541c9bd843Sdinak {CKA_WRAP, CKF_WRAP}, 551c9bd843Sdinak {CKA_UNWRAP, CKF_UNWRAP} 567c478bd9Sstevel@tonic-gate }; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * List of mechanisms that only supports asymmetric key operations 617c478bd9Sstevel@tonic-gate * in PKCS #11 V2.11 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate CK_MECHANISM_TYPE asymmetric_mechs[] = { 647c478bd9Sstevel@tonic-gate CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509, 657c478bd9Sstevel@tonic-gate CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, 667c478bd9Sstevel@tonic-gate CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1, 677c478bd9Sstevel@tonic-gate CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN, 687c478bd9Sstevel@tonic-gate CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE, 697c478bd9Sstevel@tonic-gate CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE 707c478bd9Sstevel@tonic-gate }; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate 731c9bd843Sdinak typedef struct _KEY_TYPE_SIZE_MAPPING { 741c9bd843Sdinak CK_KEY_TYPE type; 751c9bd843Sdinak CK_ULONG len; 761c9bd843Sdinak } KEY_TYPE_SIZE_MAPPING; 771c9bd843Sdinak 781c9bd843Sdinak /* 791c9bd843Sdinak * List of secret key types that have fixed sizes and their sizes. 801c9bd843Sdinak * These key types do not allow CKA_VALUE_LEN for key generation. 811c9bd843Sdinak * The sizes are in bytes. 821c9bd843Sdinak * 831c9bd843Sdinak * Discrete-sized keys, such as AES and Twofish, and variable sized 841c9bd843Sdinak * keys, such as Blowfish, are not in this list. 851c9bd843Sdinak */ 861c9bd843Sdinak KEY_TYPE_SIZE_MAPPING fixed_size_secrets[] = { 871c9bd843Sdinak {CKK_DES, 8}, {CKK_DES2, 16}, {CKK_DES3, 24}, {CKK_IDEA, 16}, 881c9bd843Sdinak {CKK_CDMF, 8}, {CKK_SKIPJACK, 12}, {CKK_BATON, 40}, {CKK_JUNIPER, 40} 891c9bd843Sdinak }; 901c9bd843Sdinak 9117e2ff97Sdinak /* 9217e2ff97Sdinak * match_mech is an example of many possible criteria functions. 9317e2ff97Sdinak * It matches the given mech type (in args) with the slot's mech info. 9417e2ff97Sdinak * If no match is found, pkcs11_GetCriteriaSession is asked to return 9517e2ff97Sdinak * CKR_MECHANISM_INVALID. 9617e2ff97Sdinak */ 9717e2ff97Sdinak boolean_t 9817e2ff97Sdinak match_mech(CK_SLOT_ID slot_id, void *args, CK_RV *rv) 9917e2ff97Sdinak { 10017e2ff97Sdinak CK_MECHANISM_INFO mech_info; 10117e2ff97Sdinak CK_MECHANISM_TYPE mech = (CK_MECHANISM_TYPE)args; 10217e2ff97Sdinak 10317e2ff97Sdinak *rv = CKR_MECHANISM_INVALID; 10417e2ff97Sdinak return (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK); 10517e2ff97Sdinak } 10617e2ff97Sdinak 10717e2ff97Sdinak /* 10817e2ff97Sdinak * pkcs11_GetCriteriaSession will initialize the framework and do all 10917e2ff97Sdinak * the necessary work of calling C_GetSlotList(), C_GetMechanismInfo() 11017e2ff97Sdinak * C_OpenSession() to create a session that meets all the criteria in 11117e2ff97Sdinak * the given function pointer. 11217e2ff97Sdinak * 11317e2ff97Sdinak * The criteria function must return a boolean value of true or false. 11417e2ff97Sdinak * The arguments to the function are the current slot id, an opaque 11517e2ff97Sdinak * args value that is passed through to the function, and the error 11617e2ff97Sdinak * value pkcs11_GetCriteriaSession should return if no slot id meets the 11717e2ff97Sdinak * criteria. 11817e2ff97Sdinak * 11917e2ff97Sdinak * If the function is called multiple times, it will return a new session 12017e2ff97Sdinak * without reinitializing the framework. 12117e2ff97Sdinak */ 12217e2ff97Sdinak CK_RV 12317e2ff97Sdinak pkcs11_GetCriteriaSession( 12417e2ff97Sdinak boolean_t (*criteria)(CK_SLOT_ID slot_id, void *args, CK_RV *rv), 12517e2ff97Sdinak void *args, CK_SESSION_HANDLE_PTR hSession) 12617e2ff97Sdinak { 12717e2ff97Sdinak CK_RV rv; 12817e2ff97Sdinak CK_ULONG slotcount; 12917e2ff97Sdinak CK_SLOT_ID_PTR slot_list; 13017e2ff97Sdinak CK_SLOT_ID slot_id; 13117e2ff97Sdinak CK_ULONG i; 13217e2ff97Sdinak 13317e2ff97Sdinak if (hSession == NULL || criteria == NULL) { 13417e2ff97Sdinak return (CKR_ARGUMENTS_BAD); 13517e2ff97Sdinak } 13617e2ff97Sdinak 13717e2ff97Sdinak /* initialize PKCS #11 */ 13817e2ff97Sdinak if (!pkcs11_initialized) { 13917e2ff97Sdinak rv = C_Initialize(NULL); 14017e2ff97Sdinak if ((rv != CKR_OK) && 14117e2ff97Sdinak (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { 14217e2ff97Sdinak return (rv); 14317e2ff97Sdinak } 14417e2ff97Sdinak } 14517e2ff97Sdinak 14617e2ff97Sdinak /* get slot count */ 14717e2ff97Sdinak rv = C_GetSlotList(0, NULL, &slotcount); 14817e2ff97Sdinak if (rv != CKR_OK) { 14917e2ff97Sdinak return (rv); 15017e2ff97Sdinak } 15117e2ff97Sdinak 15217e2ff97Sdinak if (slotcount == 0) { 15317e2ff97Sdinak return (CKR_FUNCTION_FAILED); 15417e2ff97Sdinak } 15517e2ff97Sdinak 15617e2ff97Sdinak 15717e2ff97Sdinak /* allocate memory for slot list */ 15817e2ff97Sdinak slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); 15917e2ff97Sdinak if (slot_list == NULL) { 16017e2ff97Sdinak return (CKR_HOST_MEMORY); 16117e2ff97Sdinak } 16217e2ff97Sdinak 16317e2ff97Sdinak if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { 16417e2ff97Sdinak free(slot_list); 16517e2ff97Sdinak return (rv); 16617e2ff97Sdinak } 16717e2ff97Sdinak 16817e2ff97Sdinak /* find slot with matching criteria */ 16917e2ff97Sdinak for (i = 0; i < slotcount; i++) { 17017e2ff97Sdinak slot_id = slot_list[i]; 17117e2ff97Sdinak if ((*criteria)(slot_id, args, &rv)) { 17217e2ff97Sdinak break; 17317e2ff97Sdinak } 17417e2ff97Sdinak } 17517e2ff97Sdinak 17617e2ff97Sdinak if (i == slotcount) { 17717e2ff97Sdinak /* no matching slot found */ 17817e2ff97Sdinak free(slot_list); 17917e2ff97Sdinak return (rv); /* this rv is from the criteria function */ 18017e2ff97Sdinak } 18117e2ff97Sdinak 18217e2ff97Sdinak rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, 18317e2ff97Sdinak NULL, hSession); 18417e2ff97Sdinak 18517e2ff97Sdinak free(slot_list); 18617e2ff97Sdinak return (rv); 18717e2ff97Sdinak } 1881c9bd843Sdinak 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * SUNW_C_GetMechSession will initialize the framework and do all 1917c478bd9Sstevel@tonic-gate * of the neccessary work of calling C_GetSlotList(), C_GetMechanismInfo() 19217e2ff97Sdinak * C_OpenSession() to create a session capable of providing the requested 1937c478bd9Sstevel@tonic-gate * mechanism. 1947c478bd9Sstevel@tonic-gate * 1957c478bd9Sstevel@tonic-gate * If the function is called multiple times, it will return a new session 1967c478bd9Sstevel@tonic-gate * without reinitializing the framework. 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate CK_RV 1997c478bd9Sstevel@tonic-gate SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession) 2007c478bd9Sstevel@tonic-gate { 20117e2ff97Sdinak /* 20217e2ff97Sdinak * All the code in this function can be replaced with one line: 20317e2ff97Sdinak * 20417e2ff97Sdinak * return (pkcs11_GetCriteriaSession(match_mech, (void *)mech, 20517e2ff97Sdinak * hSession)); 20617e2ff97Sdinak * 20717e2ff97Sdinak */ 2087c478bd9Sstevel@tonic-gate CK_RV rv; 2097c478bd9Sstevel@tonic-gate CK_ULONG slotcount; 2107c478bd9Sstevel@tonic-gate CK_SLOT_ID_PTR slot_list; 2117c478bd9Sstevel@tonic-gate CK_SLOT_ID slot_id; 2127c478bd9Sstevel@tonic-gate CK_MECHANISM_INFO mech_info; 2137c478bd9Sstevel@tonic-gate CK_ULONG i; 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate if (hSession == NULL) { 2167c478bd9Sstevel@tonic-gate return (CKR_ARGUMENTS_BAD); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* initialize PKCS #11 */ 22090e0e8c4Sizick if (!pkcs11_initialized) { 2217c478bd9Sstevel@tonic-gate rv = C_Initialize(NULL); 22290e0e8c4Sizick if ((rv != CKR_OK) && 22390e0e8c4Sizick (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { 2247c478bd9Sstevel@tonic-gate return (rv); 2257c478bd9Sstevel@tonic-gate } 22690e0e8c4Sizick } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* get slot count */ 2297c478bd9Sstevel@tonic-gate rv = C_GetSlotList(0, NULL, &slotcount); 2307c478bd9Sstevel@tonic-gate if (rv != CKR_OK) { 2317c478bd9Sstevel@tonic-gate return (rv); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (slotcount == 0) { 2357c478bd9Sstevel@tonic-gate return (CKR_FUNCTION_FAILED); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* allocate memory for slot list */ 2407c478bd9Sstevel@tonic-gate slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); 2417c478bd9Sstevel@tonic-gate if (slot_list == NULL) { 2427c478bd9Sstevel@tonic-gate return (CKR_HOST_MEMORY); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { 2467c478bd9Sstevel@tonic-gate free(slot_list); 2477c478bd9Sstevel@tonic-gate return (rv); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* find slot with matching mechanism */ 2517c478bd9Sstevel@tonic-gate for (i = 0; i < slotcount; i++) { 2527c478bd9Sstevel@tonic-gate slot_id = slot_list[i]; 2537c478bd9Sstevel@tonic-gate if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) { 2547c478bd9Sstevel@tonic-gate /* found mechanism */ 2557c478bd9Sstevel@tonic-gate break; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate } 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate if (i == slotcount) { 2607c478bd9Sstevel@tonic-gate /* no matching mechanism found */ 2617c478bd9Sstevel@tonic-gate free(slot_list); 2627c478bd9Sstevel@tonic-gate return (CKR_MECHANISM_INVALID); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, 2667c478bd9Sstevel@tonic-gate NULL, hSession); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate free(slot_list); 2697c478bd9Sstevel@tonic-gate return (rv); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * SUNW_C_KeyToObject creates a secret key object for the given 2747c478bd9Sstevel@tonic-gate * mechanism from the rawkey data. 2757c478bd9Sstevel@tonic-gate */ 2767c478bd9Sstevel@tonic-gate CK_RV 2777c478bd9Sstevel@tonic-gate SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech, 2787c478bd9Sstevel@tonic-gate const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate CK_RV rv; 2827c478bd9Sstevel@tonic-gate CK_SESSION_INFO session_info; 2837c478bd9Sstevel@tonic-gate CK_SLOT_ID slot_id; 2847c478bd9Sstevel@tonic-gate CK_MECHANISM_INFO mech_info; 2857c478bd9Sstevel@tonic-gate CK_ULONG i, j; 2867c478bd9Sstevel@tonic-gate CK_KEY_TYPE keytype; 2877c478bd9Sstevel@tonic-gate CK_ULONG num_asym_mechs, num_mapping; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* template for creating generic secret key object */ 2907c478bd9Sstevel@tonic-gate CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate if ((hSession == NULL) || (obj == NULL) || 2937c478bd9Sstevel@tonic-gate (rawkey == NULL) || (rawkey_len == 0)) { 2947c478bd9Sstevel@tonic-gate return (CKR_ARGUMENTS_BAD); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * Check to make sure mechanism type is not for asymmetric key 2997c478bd9Sstevel@tonic-gate * only operations. This function is only applicable to 3007c478bd9Sstevel@tonic-gate * generating secret key. 3017c478bd9Sstevel@tonic-gate */ 3027c478bd9Sstevel@tonic-gate num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); 3037c478bd9Sstevel@tonic-gate for (i = 0; i < num_asym_mechs; i++) { 3047c478bd9Sstevel@tonic-gate if (mech == asymmetric_mechs[i]) { 3057c478bd9Sstevel@tonic-gate return (CKR_MECHANISM_INVALID); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate rv = C_GetSessionInfo(hSession, &session_info); 3107c478bd9Sstevel@tonic-gate if (rv != CKR_OK) { 3111c9bd843Sdinak return (rv); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate slot_id = session_info.slotID; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate i = 0; 3177c478bd9Sstevel@tonic-gate template[i].type = CKA_CLASS; 3187c478bd9Sstevel@tonic-gate template[i].pValue = &objclass; 3197c478bd9Sstevel@tonic-gate template[i].ulValueLen = sizeof (objclass); 3207c478bd9Sstevel@tonic-gate i++; 3217c478bd9Sstevel@tonic-gate 3227c478bd9Sstevel@tonic-gate /* get the key type for this mechanism */ 3237c478bd9Sstevel@tonic-gate if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) { 3247c478bd9Sstevel@tonic-gate return (rv); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate assert(i < NUM_SECRETKEY_ATTRS); 3287c478bd9Sstevel@tonic-gate template[i].type = CKA_KEY_TYPE; 3297c478bd9Sstevel@tonic-gate template[i].pValue = &keytype; 3307c478bd9Sstevel@tonic-gate template[i].ulValueLen = sizeof (keytype); 3317c478bd9Sstevel@tonic-gate i++; 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate rv = C_GetMechanismInfo(slot_id, mech, &mech_info); 3347c478bd9Sstevel@tonic-gate if (rv != CKR_OK) { 3351c9bd843Sdinak return (rv); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3381c9bd843Sdinak /* set the attribute type flag on object based on mechanism */ 3397c478bd9Sstevel@tonic-gate num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); 3407c478bd9Sstevel@tonic-gate for (j = 0; j < num_mapping; j++) { 3417c478bd9Sstevel@tonic-gate assert(i < NUM_SECRETKEY_ATTRS); 3427c478bd9Sstevel@tonic-gate template[i].type = mapping[j].attr; 3437c478bd9Sstevel@tonic-gate template[i].ulValueLen = sizeof (falsevalue); 3447c478bd9Sstevel@tonic-gate if (mech_info.flags & ((mapping[j]).flag)) { 3457c478bd9Sstevel@tonic-gate template[i].pValue = &truevalue; 3467c478bd9Sstevel@tonic-gate } else { 3477c478bd9Sstevel@tonic-gate template[i].pValue = &falsevalue; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate i++; 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate assert(i < NUM_SECRETKEY_ATTRS); 3537c478bd9Sstevel@tonic-gate template[i].type = CKA_TOKEN; 3547c478bd9Sstevel@tonic-gate template[i].pValue = &falsevalue; 3557c478bd9Sstevel@tonic-gate template[i].ulValueLen = sizeof (falsevalue); 3567c478bd9Sstevel@tonic-gate i++; 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate assert(i < NUM_SECRETKEY_ATTRS); 3597c478bd9Sstevel@tonic-gate template[i].type = CKA_VALUE; 3607c478bd9Sstevel@tonic-gate template[i].pValue = (CK_VOID_PTR)rawkey; 3617c478bd9Sstevel@tonic-gate template[i].ulValueLen = (CK_ULONG)rawkey_len; 3627c478bd9Sstevel@tonic-gate i++; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate rv = C_CreateObject(hSession, template, i, obj); 3651c9bd843Sdinak return (rv); 3661c9bd843Sdinak } 3671c9bd843Sdinak 3681c9bd843Sdinak 3691c9bd843Sdinak /* 3701c9bd843Sdinak * pkcs11_PasswdToPBKD2Object will create a secret key from the given string 3711c9bd843Sdinak * (e.g. passphrase) using PKCS#5 Password-Based Key Derivation Function 2 3721c9bd843Sdinak * (PBKD2). 3731c9bd843Sdinak * 3741c9bd843Sdinak * Session must be open. Salt and iterations use defaults. 3751c9bd843Sdinak */ 3761c9bd843Sdinak CK_RV 3771c9bd843Sdinak pkcs11_PasswdToPBKD2Object(CK_SESSION_HANDLE hSession, char *passphrase, 3781c9bd843Sdinak size_t passphrase_len, void *salt, size_t salt_len, CK_ULONG iterations, 3791c9bd843Sdinak CK_KEY_TYPE key_type, CK_ULONG key_len, CK_FLAGS key_flags, 3801c9bd843Sdinak CK_OBJECT_HANDLE_PTR obj) 3811c9bd843Sdinak { 3821c9bd843Sdinak CK_RV rv; 3831c9bd843Sdinak CK_PKCS5_PBKD2_PARAMS params; 3841c9bd843Sdinak CK_MECHANISM mechanism; 3851c9bd843Sdinak CK_KEY_TYPE asym_key_type; 3861c9bd843Sdinak CK_ULONG i, j, num_asym_mechs, num_fixed_secs, num_mapping; 3871c9bd843Sdinak CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; 3881c9bd843Sdinak 3891c9bd843Sdinak if (hSession == NULL || obj == NULL || 3901c9bd843Sdinak passphrase == NULL || passphrase_len == 0 || 3911c9bd843Sdinak iterations == 0UL) { 3921c9bd843Sdinak return (CKR_ARGUMENTS_BAD); 3931c9bd843Sdinak } 3941c9bd843Sdinak 3951c9bd843Sdinak /* 3961c9bd843Sdinak * Check to make sure key type is not asymmetric. This function 3971c9bd843Sdinak * is only applicable to generating secret key. 3981c9bd843Sdinak */ 3991c9bd843Sdinak num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); 4001c9bd843Sdinak for (i = 0; i < num_asym_mechs; i++) { 4011c9bd843Sdinak rv = pkcs11_mech2keytype(asymmetric_mechs[i], &asym_key_type); 4021c9bd843Sdinak assert(rv == CKR_OK); 4031c9bd843Sdinak if (key_type == asym_key_type) { 4041c9bd843Sdinak return (CKR_KEY_TYPE_INCONSISTENT); 4051c9bd843Sdinak } 4061c9bd843Sdinak } 4071c9bd843Sdinak 4081c9bd843Sdinak /* 4091c9bd843Sdinak * Key length must either be 0 or the correct size for PBKD of 4101c9bd843Sdinak * fixed-size secret keys. However, underlying key generation 4111c9bd843Sdinak * cannot have CKA_VALUE_LEN set for the key length attribute. 4121c9bd843Sdinak */ 4131c9bd843Sdinak num_fixed_secs = 4141c9bd843Sdinak sizeof (fixed_size_secrets) / sizeof (KEY_TYPE_SIZE_MAPPING); 4151c9bd843Sdinak for (i = 0; i < num_fixed_secs; i++) { 4161c9bd843Sdinak if (key_type == fixed_size_secrets[i].type) { 4171c9bd843Sdinak if (key_len == fixed_size_secrets[i].len) { 4181c9bd843Sdinak key_len = 0; 4191c9bd843Sdinak } 4201c9bd843Sdinak if (key_len == 0) { 4211c9bd843Sdinak break; 4221c9bd843Sdinak } 4231c9bd843Sdinak return (CKR_KEY_SIZE_RANGE); 4241c9bd843Sdinak } 4251c9bd843Sdinak } 4261c9bd843Sdinak 4271c9bd843Sdinak if (salt == NULL || salt_len == 0) { 4281c9bd843Sdinak params.saltSource = 0; 4291c9bd843Sdinak params.pSaltSourceData = NULL; 4301c9bd843Sdinak params.ulSaltSourceDataLen = 0; 4311c9bd843Sdinak } else { 4321c9bd843Sdinak params.saltSource = CKZ_SALT_SPECIFIED; 4331c9bd843Sdinak params.pSaltSourceData = salt; 4341c9bd843Sdinak params.ulSaltSourceDataLen = salt_len; 4351c9bd843Sdinak } 4361c9bd843Sdinak params.iterations = iterations; 4371c9bd843Sdinak params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1; 4381c9bd843Sdinak params.pPrfData = NULL; 4391c9bd843Sdinak params.ulPrfDataLen = 0; 4401c9bd843Sdinak params.pPassword = (CK_UTF8CHAR_PTR)passphrase; 4411c9bd843Sdinak params.ulPasswordLen = (CK_ULONG_PTR)&passphrase_len; 4421c9bd843Sdinak /* 4431c9bd843Sdinak * PKCS#11 spec error, ulPasswordLen should have been pulPasswordLen, 4441c9bd843Sdinak * or its type should have been CK_ULONG instead of CK_ULONG_PTR, 4451c9bd843Sdinak * but it's legacy now 4461c9bd843Sdinak */ 4471c9bd843Sdinak 4481c9bd843Sdinak mechanism.mechanism = CKM_PKCS5_PBKD2; 4491c9bd843Sdinak mechanism.pParameter = ¶ms; 4501c9bd843Sdinak mechanism.ulParameterLen = sizeof (params); 4511c9bd843Sdinak 4521c9bd843Sdinak i = 0; 4531c9bd843Sdinak template[i].type = CKA_CLASS; 4541c9bd843Sdinak template[i].pValue = &objclass; 4551c9bd843Sdinak template[i].ulValueLen = sizeof (objclass); 4561c9bd843Sdinak i++; 4571c9bd843Sdinak 4581c9bd843Sdinak assert(i < NUM_SECRETKEY_ATTRS); 4591c9bd843Sdinak template[i].type = CKA_KEY_TYPE; 4601c9bd843Sdinak template[i].pValue = &key_type; 4611c9bd843Sdinak template[i].ulValueLen = sizeof (key_type); 4621c9bd843Sdinak i++; 4631c9bd843Sdinak 4641c9bd843Sdinak assert(i < NUM_SECRETKEY_ATTRS); 4651c9bd843Sdinak template[i].type = CKA_TOKEN; 4661c9bd843Sdinak template[i].pValue = &falsevalue; 4671c9bd843Sdinak template[i].ulValueLen = sizeof (falsevalue); 4681c9bd843Sdinak i++; 4691c9bd843Sdinak 4701c9bd843Sdinak if (key_len != 0) { 4711c9bd843Sdinak assert(i < NUM_SECRETKEY_ATTRS); 4721c9bd843Sdinak template[i].type = CKA_VALUE_LEN; 4731c9bd843Sdinak template[i].pValue = &key_len; 4741c9bd843Sdinak template[i].ulValueLen = sizeof (key_len); 4751c9bd843Sdinak i++; 4761c9bd843Sdinak } 4771c9bd843Sdinak 4781c9bd843Sdinak /* 4791c9bd843Sdinak * C_GenerateKey may not implicitly set capability attributes, 4801c9bd843Sdinak * e.g. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, ... 4811c9bd843Sdinak */ 4821c9bd843Sdinak num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); 4831c9bd843Sdinak for (j = 0; j < num_mapping; j++) { 4841c9bd843Sdinak assert(i < NUM_SECRETKEY_ATTRS); 4851c9bd843Sdinak template[i].type = mapping[j].attr; 4861c9bd843Sdinak template[i].pValue = (key_flags & ((mapping[j]).flag)) ? 4871c9bd843Sdinak &truevalue : &falsevalue; 4881c9bd843Sdinak template[i].ulValueLen = sizeof (falsevalue); 4891c9bd843Sdinak i++; 4901c9bd843Sdinak } 4911c9bd843Sdinak 4921c9bd843Sdinak rv = C_GenerateKey(hSession, &mechanism, template, i, obj); 4931c9bd843Sdinak return (rv); 4941c9bd843Sdinak } 4951c9bd843Sdinak 4961c9bd843Sdinak /* 4971c9bd843Sdinak * pkcs11_ObjectToKey gets the rawkey data from a secret key object. 4981c9bd843Sdinak * The caller is responsible to free the allocated rawkey data. 4991c9bd843Sdinak * 5001c9bd843Sdinak * Optionally the object can be destroyed after the value is retrieved. 5011c9bd843Sdinak * As an example, after using pkcs11_PasswdToPBKD2Object() to create a 5021c9bd843Sdinak * secret key object from a passphrase, an app may call pkcs11_ObjectToKey 5031c9bd843Sdinak * to get the rawkey data. The intermediate object may no longer be needed 5041c9bd843Sdinak * and should be destroyed. 5051c9bd843Sdinak */ 5061c9bd843Sdinak CK_RV 5071c9bd843Sdinak pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE obj, 5081c9bd843Sdinak void **rawkey, size_t *rawkey_len, boolean_t destroy_obj) 5091c9bd843Sdinak { 5101c9bd843Sdinak CK_RV rv; 5111c9bd843Sdinak CK_ATTRIBUTE template; 5121c9bd843Sdinak 513*00756404SDarren J Moffat if (hSession == NULL) 514*00756404SDarren J Moffat return (CKR_SESSION_HANDLE_INVALID); 515*00756404SDarren J Moffat if (obj == NULL) 516*00756404SDarren J Moffat return (CKR_OBJECT_HANDLE_INVALID); 517*00756404SDarren J Moffat if (rawkey == NULL || rawkey_len == NULL) 5181c9bd843Sdinak return (CKR_ARGUMENTS_BAD); 5191c9bd843Sdinak 5201c9bd843Sdinak template.type = CKA_VALUE; 5211c9bd843Sdinak template.pValue = NULL; 5221c9bd843Sdinak template.ulValueLen = 0; 5231c9bd843Sdinak 5241c9bd843Sdinak /* First get the size of the rawkey */ 5251c9bd843Sdinak rv = C_GetAttributeValue(hSession, obj, &template, 1); 5267c478bd9Sstevel@tonic-gate if (rv != CKR_OK) { 5277c478bd9Sstevel@tonic-gate return (rv); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5301c9bd843Sdinak template.pValue = malloc(template.ulValueLen); 5311c9bd843Sdinak if (template.pValue == NULL) { 5321c9bd843Sdinak return (CKR_HOST_MEMORY); 5331c9bd843Sdinak } 5347c478bd9Sstevel@tonic-gate 5351c9bd843Sdinak /* Then get the rawkey data */ 5361c9bd843Sdinak rv = C_GetAttributeValue(hSession, obj, &template, 1); 5371c9bd843Sdinak if (rv != CKR_OK) { 5381c9bd843Sdinak free(template.pValue); 5391c9bd843Sdinak return (rv); 5401c9bd843Sdinak } 5411c9bd843Sdinak 5421c9bd843Sdinak if (destroy_obj) { 5431c9bd843Sdinak /* 5441c9bd843Sdinak * Could have asserted rv == CKR_OK, making threaded 5451c9bd843Sdinak * apps that share objects see stars. Here mercy is ok. 5461c9bd843Sdinak */ 5471c9bd843Sdinak (void) C_DestroyObject(hSession, obj); 5481c9bd843Sdinak } 5491c9bd843Sdinak 5501c9bd843Sdinak *rawkey = template.pValue; 5511c9bd843Sdinak *rawkey_len = template.ulValueLen; 5521c9bd843Sdinak 5531c9bd843Sdinak return (CKR_OK); 5541c9bd843Sdinak } 5551c9bd843Sdinak 5561c9bd843Sdinak /* 5571c9bd843Sdinak * pkcs11_PasswdToKey will create PKCS#5 PBKD2 rawkey data from the 5581c9bd843Sdinak * given passphrase. The caller is responsible to free the allocated 5591c9bd843Sdinak * rawkey data. 5601c9bd843Sdinak */ 5611c9bd843Sdinak CK_RV 5621c9bd843Sdinak pkcs11_PasswdToKey(CK_SESSION_HANDLE hSession, char *passphrase, 5631c9bd843Sdinak size_t passphrase_len, void *salt, size_t salt_len, CK_KEY_TYPE key_type, 5641c9bd843Sdinak CK_ULONG key_len, void **rawkey, size_t *rawkey_len) 5651c9bd843Sdinak { 5661c9bd843Sdinak CK_RV rv; 5671c9bd843Sdinak CK_OBJECT_HANDLE obj; 5681c9bd843Sdinak 5691c9bd843Sdinak rv = pkcs11_PasswdToPBKD2Object(hSession, passphrase, passphrase_len, 5701c9bd843Sdinak salt, salt_len, CK_PKCS5_PBKD2_ITERATIONS, key_type, key_len, 0, 5711c9bd843Sdinak &obj); 5721c9bd843Sdinak if (rv != CKR_OK) 5731c9bd843Sdinak return (rv); 5741c9bd843Sdinak rv = pkcs11_ObjectToKey(hSession, obj, rawkey, rawkey_len, B_TRUE); 5757c478bd9Sstevel@tonic-gate return (rv); 5767c478bd9Sstevel@tonic-gate } 577