1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Solaris specific functions to reduce the initialization 30 * overhead of using PKCS #11 31 */ 32 33 #include <stdlib.h> 34 #include <sys/types.h> 35 #include <security/cryptoki.h> 36 #include <assert.h> 37 #include <cryptoutil.h> 38 #include <pkcs11Global.h> 39 40 static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; 41 static CK_BBOOL falsevalue = FALSE; 42 static CK_BBOOL truevalue = TRUE; 43 44 #define NUM_SECRETKEY_ATTRS 12 45 46 typedef struct _ATTRTYPE_MECHINFO_MAPPING { 47 CK_ATTRIBUTE_TYPE attr; 48 CK_FLAGS flag; 49 } ATTRTYPE_MECHINFO_MAPPING; 50 51 /* possible attribute types for creating key */ 52 ATTRTYPE_MECHINFO_MAPPING mapping[] = { 53 {CKA_ENCRYPT, CKF_ENCRYPT}, 54 {CKA_DECRYPT, CKF_DECRYPT}, 55 {CKA_SIGN, CKF_SIGN}, 56 {CKA_VERIFY, CKF_VERIFY}, 57 {CKA_WRAP, CKF_WRAP}, 58 {CKA_UNWRAP, CKF_UNWRAP} 59 }; 60 61 62 /* 63 * List of mechanisms that only supports asymmetric key operations 64 * in PKCS #11 V2.11 65 */ 66 CK_MECHANISM_TYPE asymmetric_mechs[] = { 67 CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509, 68 CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, 69 CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1, 70 CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN, 71 CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE, 72 CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE 73 }; 74 75 76 typedef struct _KEY_TYPE_SIZE_MAPPING { 77 CK_KEY_TYPE type; 78 CK_ULONG len; 79 } KEY_TYPE_SIZE_MAPPING; 80 81 /* 82 * List of secret key types that have fixed sizes and their sizes. 83 * These key types do not allow CKA_VALUE_LEN for key generation. 84 * The sizes are in bytes. 85 * 86 * Discrete-sized keys, such as AES and Twofish, and variable sized 87 * keys, such as Blowfish, are not in this list. 88 */ 89 KEY_TYPE_SIZE_MAPPING fixed_size_secrets[] = { 90 {CKK_DES, 8}, {CKK_DES2, 16}, {CKK_DES3, 24}, {CKK_IDEA, 16}, 91 {CKK_CDMF, 8}, {CKK_SKIPJACK, 12}, {CKK_BATON, 40}, {CKK_JUNIPER, 40} 92 }; 93 94 95 /* 96 * SUNW_C_GetMechSession will initialize the framework and do all 97 * of the neccessary work of calling C_GetSlotList(), C_GetMechanismInfo() 98 * C_OpenSession() to provide a session capable of providing the requested 99 * mechanism. 100 * 101 * If the function is called multiple times, it will return a new session 102 * without reinitializing the framework. 103 */ 104 CK_RV 105 SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession) 106 { 107 CK_RV rv; 108 CK_ULONG slotcount; 109 CK_SLOT_ID_PTR slot_list; 110 CK_SLOT_ID slot_id; 111 CK_MECHANISM_INFO mech_info; 112 CK_ULONG i; 113 114 if (hSession == NULL) { 115 return (CKR_ARGUMENTS_BAD); 116 } 117 118 /* initialize PKCS #11 */ 119 if (!pkcs11_initialized) { 120 rv = C_Initialize(NULL); 121 if ((rv != CKR_OK) && 122 (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { 123 return (rv); 124 } 125 } 126 127 /* get slot count */ 128 rv = C_GetSlotList(0, NULL, &slotcount); 129 if (rv != CKR_OK) { 130 return (rv); 131 } 132 133 if (slotcount == 0) { 134 return (CKR_FUNCTION_FAILED); 135 } 136 137 138 /* allocate memory for slot list */ 139 slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); 140 if (slot_list == NULL) { 141 return (CKR_HOST_MEMORY); 142 } 143 144 if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { 145 free(slot_list); 146 return (rv); 147 } 148 149 /* find slot with matching mechanism */ 150 for (i = 0; i < slotcount; i++) { 151 slot_id = slot_list[i]; 152 if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) { 153 /* found mechanism */ 154 break; 155 } 156 } 157 158 if (i == slotcount) { 159 /* no matching mechanism found */ 160 free(slot_list); 161 return (CKR_MECHANISM_INVALID); 162 } 163 164 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, 165 NULL, hSession); 166 167 free(slot_list); 168 return (rv); 169 } 170 171 /* 172 * SUNW_C_KeyToObject creates a secret key object for the given 173 * mechanism from the rawkey data. 174 */ 175 CK_RV 176 SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech, 177 const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj) 178 { 179 180 CK_RV rv; 181 CK_SESSION_INFO session_info; 182 CK_SLOT_ID slot_id; 183 CK_MECHANISM_INFO mech_info; 184 CK_ULONG i, j; 185 CK_KEY_TYPE keytype; 186 CK_ULONG num_asym_mechs, num_mapping; 187 188 /* template for creating generic secret key object */ 189 CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; 190 191 if ((hSession == NULL) || (obj == NULL) || 192 (rawkey == NULL) || (rawkey_len == 0)) { 193 return (CKR_ARGUMENTS_BAD); 194 } 195 196 /* 197 * Check to make sure mechanism type is not for asymmetric key 198 * only operations. This function is only applicable to 199 * generating secret key. 200 */ 201 num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); 202 for (i = 0; i < num_asym_mechs; i++) { 203 if (mech == asymmetric_mechs[i]) { 204 return (CKR_MECHANISM_INVALID); 205 } 206 } 207 208 rv = C_GetSessionInfo(hSession, &session_info); 209 if (rv != CKR_OK) { 210 return (rv); 211 } 212 213 slot_id = session_info.slotID; 214 215 i = 0; 216 template[i].type = CKA_CLASS; 217 template[i].pValue = &objclass; 218 template[i].ulValueLen = sizeof (objclass); 219 i++; 220 221 /* get the key type for this mechanism */ 222 if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) { 223 return (rv); 224 } 225 226 assert(i < NUM_SECRETKEY_ATTRS); 227 template[i].type = CKA_KEY_TYPE; 228 template[i].pValue = &keytype; 229 template[i].ulValueLen = sizeof (keytype); 230 i++; 231 232 rv = C_GetMechanismInfo(slot_id, mech, &mech_info); 233 if (rv != CKR_OK) { 234 return (rv); 235 } 236 237 /* set the attribute type flag on object based on mechanism */ 238 num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); 239 for (j = 0; j < num_mapping; j++) { 240 assert(i < NUM_SECRETKEY_ATTRS); 241 template[i].type = mapping[j].attr; 242 template[i].ulValueLen = sizeof (falsevalue); 243 if (mech_info.flags & ((mapping[j]).flag)) { 244 template[i].pValue = &truevalue; 245 } else { 246 template[i].pValue = &falsevalue; 247 } 248 i++; 249 } 250 251 assert(i < NUM_SECRETKEY_ATTRS); 252 template[i].type = CKA_TOKEN; 253 template[i].pValue = &falsevalue; 254 template[i].ulValueLen = sizeof (falsevalue); 255 i++; 256 257 assert(i < NUM_SECRETKEY_ATTRS); 258 template[i].type = CKA_VALUE; 259 template[i].pValue = (CK_VOID_PTR)rawkey; 260 template[i].ulValueLen = (CK_ULONG)rawkey_len; 261 i++; 262 263 rv = C_CreateObject(hSession, template, i, obj); 264 return (rv); 265 } 266 267 268 /* 269 * pkcs11_PasswdToPBKD2Object will create a secret key from the given string 270 * (e.g. passphrase) using PKCS#5 Password-Based Key Derivation Function 2 271 * (PBKD2). 272 * 273 * Session must be open. Salt and iterations use defaults. 274 */ 275 CK_RV 276 pkcs11_PasswdToPBKD2Object(CK_SESSION_HANDLE hSession, char *passphrase, 277 size_t passphrase_len, void *salt, size_t salt_len, CK_ULONG iterations, 278 CK_KEY_TYPE key_type, CK_ULONG key_len, CK_FLAGS key_flags, 279 CK_OBJECT_HANDLE_PTR obj) 280 { 281 CK_RV rv; 282 CK_PKCS5_PBKD2_PARAMS params; 283 CK_MECHANISM mechanism; 284 CK_KEY_TYPE asym_key_type; 285 CK_ULONG i, j, num_asym_mechs, num_fixed_secs, num_mapping; 286 CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; 287 288 if (hSession == NULL || obj == NULL || 289 passphrase == NULL || passphrase_len == 0 || 290 iterations == 0UL) { 291 return (CKR_ARGUMENTS_BAD); 292 } 293 294 /* 295 * Check to make sure key type is not asymmetric. This function 296 * is only applicable to generating secret key. 297 */ 298 num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); 299 for (i = 0; i < num_asym_mechs; i++) { 300 rv = pkcs11_mech2keytype(asymmetric_mechs[i], &asym_key_type); 301 assert(rv == CKR_OK); 302 if (key_type == asym_key_type) { 303 return (CKR_KEY_TYPE_INCONSISTENT); 304 } 305 } 306 307 /* 308 * Key length must either be 0 or the correct size for PBKD of 309 * fixed-size secret keys. However, underlying key generation 310 * cannot have CKA_VALUE_LEN set for the key length attribute. 311 */ 312 num_fixed_secs = 313 sizeof (fixed_size_secrets) / sizeof (KEY_TYPE_SIZE_MAPPING); 314 for (i = 0; i < num_fixed_secs; i++) { 315 if (key_type == fixed_size_secrets[i].type) { 316 if (key_len == fixed_size_secrets[i].len) { 317 key_len = 0; 318 } 319 if (key_len == 0) { 320 break; 321 } 322 return (CKR_KEY_SIZE_RANGE); 323 } 324 } 325 326 if (salt == NULL || salt_len == 0) { 327 params.saltSource = 0; 328 params.pSaltSourceData = NULL; 329 params.ulSaltSourceDataLen = 0; 330 } else { 331 params.saltSource = CKZ_SALT_SPECIFIED; 332 params.pSaltSourceData = salt; 333 params.ulSaltSourceDataLen = salt_len; 334 } 335 params.iterations = iterations; 336 params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1; 337 params.pPrfData = NULL; 338 params.ulPrfDataLen = 0; 339 params.pPassword = (CK_UTF8CHAR_PTR)passphrase; 340 params.ulPasswordLen = (CK_ULONG_PTR)&passphrase_len; 341 /* 342 * PKCS#11 spec error, ulPasswordLen should have been pulPasswordLen, 343 * or its type should have been CK_ULONG instead of CK_ULONG_PTR, 344 * but it's legacy now 345 */ 346 347 mechanism.mechanism = CKM_PKCS5_PBKD2; 348 mechanism.pParameter = ¶ms; 349 mechanism.ulParameterLen = sizeof (params); 350 351 i = 0; 352 template[i].type = CKA_CLASS; 353 template[i].pValue = &objclass; 354 template[i].ulValueLen = sizeof (objclass); 355 i++; 356 357 assert(i < NUM_SECRETKEY_ATTRS); 358 template[i].type = CKA_KEY_TYPE; 359 template[i].pValue = &key_type; 360 template[i].ulValueLen = sizeof (key_type); 361 i++; 362 363 assert(i < NUM_SECRETKEY_ATTRS); 364 template[i].type = CKA_TOKEN; 365 template[i].pValue = &falsevalue; 366 template[i].ulValueLen = sizeof (falsevalue); 367 i++; 368 369 if (key_len != 0) { 370 assert(i < NUM_SECRETKEY_ATTRS); 371 template[i].type = CKA_VALUE_LEN; 372 template[i].pValue = &key_len; 373 template[i].ulValueLen = sizeof (key_len); 374 i++; 375 } 376 377 /* 378 * C_GenerateKey may not implicitly set capability attributes, 379 * e.g. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, ... 380 */ 381 num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); 382 for (j = 0; j < num_mapping; j++) { 383 assert(i < NUM_SECRETKEY_ATTRS); 384 template[i].type = mapping[j].attr; 385 template[i].pValue = (key_flags & ((mapping[j]).flag)) ? 386 &truevalue : &falsevalue; 387 template[i].ulValueLen = sizeof (falsevalue); 388 i++; 389 } 390 391 rv = C_GenerateKey(hSession, &mechanism, template, i, obj); 392 return (rv); 393 } 394 395 /* 396 * pkcs11_ObjectToKey gets the rawkey data from a secret key object. 397 * The caller is responsible to free the allocated rawkey data. 398 * 399 * Optionally the object can be destroyed after the value is retrieved. 400 * As an example, after using pkcs11_PasswdToPBKD2Object() to create a 401 * secret key object from a passphrase, an app may call pkcs11_ObjectToKey 402 * to get the rawkey data. The intermediate object may no longer be needed 403 * and should be destroyed. 404 */ 405 CK_RV 406 pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE obj, 407 void **rawkey, size_t *rawkey_len, boolean_t destroy_obj) 408 { 409 CK_RV rv; 410 CK_ATTRIBUTE template; 411 412 if (hSession == NULL || rawkey == NULL || rawkey_len == NULL || 413 *rawkey_len == 0) { 414 return (CKR_ARGUMENTS_BAD); 415 } 416 417 template.type = CKA_VALUE; 418 template.pValue = NULL; 419 template.ulValueLen = 0; 420 421 /* First get the size of the rawkey */ 422 rv = C_GetAttributeValue(hSession, obj, &template, 1); 423 if (rv != CKR_OK) { 424 return (rv); 425 } 426 427 template.pValue = malloc(template.ulValueLen); 428 if (template.pValue == NULL) { 429 return (CKR_HOST_MEMORY); 430 } 431 432 /* Then get the rawkey data */ 433 rv = C_GetAttributeValue(hSession, obj, &template, 1); 434 if (rv != CKR_OK) { 435 free(template.pValue); 436 return (rv); 437 } 438 439 if (destroy_obj) { 440 /* 441 * Could have asserted rv == CKR_OK, making threaded 442 * apps that share objects see stars. Here mercy is ok. 443 */ 444 (void) C_DestroyObject(hSession, obj); 445 } 446 447 *rawkey = template.pValue; 448 *rawkey_len = template.ulValueLen; 449 450 return (CKR_OK); 451 } 452 453 /* 454 * pkcs11_PasswdToKey will create PKCS#5 PBKD2 rawkey data from the 455 * given passphrase. The caller is responsible to free the allocated 456 * rawkey data. 457 */ 458 CK_RV 459 pkcs11_PasswdToKey(CK_SESSION_HANDLE hSession, char *passphrase, 460 size_t passphrase_len, void *salt, size_t salt_len, CK_KEY_TYPE key_type, 461 CK_ULONG key_len, void **rawkey, size_t *rawkey_len) 462 { 463 CK_RV rv; 464 CK_OBJECT_HANDLE obj; 465 466 rv = pkcs11_PasswdToPBKD2Object(hSession, passphrase, passphrase_len, 467 salt, salt_len, CK_PKCS5_PBKD2_ITERATIONS, key_type, key_len, 0, 468 &obj); 469 if (rv != CKR_OK) 470 return (rv); 471 rv = pkcs11_ObjectToKey(hSession, obj, rawkey, rawkey_len, B_TRUE); 472 return (rv); 473 } 474