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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * Solaris specific functions to reduce the initialization 27 * overhead of using PKCS #11 28 */ 29 30 #include <stdlib.h> 31 #include <sys/types.h> 32 #include <security/cryptoki.h> 33 #include <assert.h> 34 #include <cryptoutil.h> 35 #include <pkcs11Global.h> 36 37 static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY; 38 static CK_BBOOL falsevalue = FALSE; 39 static CK_BBOOL truevalue = TRUE; 40 41 #define NUM_SECRETKEY_ATTRS 12 42 43 typedef struct _ATTRTYPE_MECHINFO_MAPPING { 44 CK_ATTRIBUTE_TYPE attr; 45 CK_FLAGS flag; 46 } ATTRTYPE_MECHINFO_MAPPING; 47 48 /* possible attribute types for creating key */ 49 ATTRTYPE_MECHINFO_MAPPING mapping[] = { 50 {CKA_ENCRYPT, CKF_ENCRYPT}, 51 {CKA_DECRYPT, CKF_DECRYPT}, 52 {CKA_SIGN, CKF_SIGN}, 53 {CKA_VERIFY, CKF_VERIFY}, 54 {CKA_WRAP, CKF_WRAP}, 55 {CKA_UNWRAP, CKF_UNWRAP} 56 }; 57 58 59 /* 60 * List of mechanisms that only supports asymmetric key operations 61 * in PKCS #11 V2.11 62 */ 63 CK_MECHANISM_TYPE asymmetric_mechs[] = { 64 CKM_RSA_PKCS_KEY_PAIR_GEN, CKM_RSA_PKCS, CKM_RSA_9796, CKM_RSA_X_509, 65 CKM_RSA_PKCS_OAEP, CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, 66 CKM_RSA_PKCS_PSS, CKM_DSA_KEY_PAIR_GEN, CKM_DSA, CKM_DSA_SHA1, 67 CKM_DSA_PARAMETER_GEN, CKM_ECDSA_KEY_PAIR_GEN, CKM_EC_KEY_PAIR_GEN, 68 CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDH1_DERIVE, 69 CKM_ECDH1_COFACTOR_DERIVE, CKM_ECMQV_DERIVE 70 }; 71 72 73 typedef struct _KEY_TYPE_SIZE_MAPPING { 74 CK_KEY_TYPE type; 75 CK_ULONG len; 76 } KEY_TYPE_SIZE_MAPPING; 77 78 /* 79 * List of secret key types that have fixed sizes and their sizes. 80 * These key types do not allow CKA_VALUE_LEN for key generation. 81 * The sizes are in bytes. 82 * 83 * Discrete-sized keys, such as AES and Twofish, and variable sized 84 * keys, such as Blowfish, are not in this list. 85 */ 86 KEY_TYPE_SIZE_MAPPING fixed_size_secrets[] = { 87 {CKK_DES, 8}, {CKK_DES2, 16}, {CKK_DES3, 24}, {CKK_IDEA, 16}, 88 {CKK_CDMF, 8}, {CKK_SKIPJACK, 12}, {CKK_BATON, 40}, {CKK_JUNIPER, 40} 89 }; 90 91 /* 92 * match_mech is an example of many possible criteria functions. 93 * It matches the given mech type (in args) with the slot's mech info. 94 * If no match is found, pkcs11_GetCriteriaSession is asked to return 95 * CKR_MECHANISM_INVALID. 96 */ 97 boolean_t 98 match_mech(CK_SLOT_ID slot_id, void *args, CK_RV *rv) 99 { 100 CK_MECHANISM_INFO mech_info; 101 CK_MECHANISM_TYPE mech = (CK_MECHANISM_TYPE)args; 102 103 *rv = CKR_MECHANISM_INVALID; 104 return (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK); 105 } 106 107 /* 108 * pkcs11_GetCriteriaSession will initialize the framework and do all 109 * the necessary work of calling C_GetSlotList(), C_GetMechanismInfo() 110 * C_OpenSession() to create a session that meets all the criteria in 111 * the given function pointer. 112 * 113 * The criteria function must return a boolean value of true or false. 114 * The arguments to the function are the current slot id, an opaque 115 * args value that is passed through to the function, and the error 116 * value pkcs11_GetCriteriaSession should return if no slot id meets the 117 * criteria. 118 * 119 * If the function is called multiple times, it will return a new session 120 * without reinitializing the framework. 121 */ 122 CK_RV 123 pkcs11_GetCriteriaSession( 124 boolean_t (*criteria)(CK_SLOT_ID slot_id, void *args, CK_RV *rv), 125 void *args, CK_SESSION_HANDLE_PTR hSession) 126 { 127 CK_RV rv; 128 CK_ULONG slotcount; 129 CK_SLOT_ID_PTR slot_list; 130 CK_SLOT_ID slot_id; 131 CK_ULONG i; 132 133 if (hSession == NULL || criteria == NULL) { 134 return (CKR_ARGUMENTS_BAD); 135 } 136 137 /* initialize PKCS #11 */ 138 if (!pkcs11_initialized) { 139 rv = C_Initialize(NULL); 140 if ((rv != CKR_OK) && 141 (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { 142 return (rv); 143 } 144 } 145 146 /* get slot count */ 147 rv = C_GetSlotList(0, NULL, &slotcount); 148 if (rv != CKR_OK) { 149 return (rv); 150 } 151 152 if (slotcount == 0) { 153 return (CKR_FUNCTION_FAILED); 154 } 155 156 157 /* allocate memory for slot list */ 158 slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); 159 if (slot_list == NULL) { 160 return (CKR_HOST_MEMORY); 161 } 162 163 if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { 164 free(slot_list); 165 return (rv); 166 } 167 168 /* find slot with matching criteria */ 169 for (i = 0; i < slotcount; i++) { 170 slot_id = slot_list[i]; 171 if ((*criteria)(slot_id, args, &rv)) { 172 break; 173 } 174 } 175 176 if (i == slotcount) { 177 /* no matching slot found */ 178 free(slot_list); 179 return (rv); /* this rv is from the criteria function */ 180 } 181 182 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, 183 NULL, hSession); 184 185 free(slot_list); 186 return (rv); 187 } 188 189 /* 190 * SUNW_C_GetMechSession will initialize the framework and do all 191 * of the neccessary work of calling C_GetSlotList(), C_GetMechanismInfo() 192 * C_OpenSession() to create a session capable of providing the requested 193 * mechanism. 194 * 195 * If the function is called multiple times, it will return a new session 196 * without reinitializing the framework. 197 */ 198 CK_RV 199 SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession) 200 { 201 /* 202 * All the code in this function can be replaced with one line: 203 * 204 * return (pkcs11_GetCriteriaSession(match_mech, (void *)mech, 205 * hSession)); 206 * 207 */ 208 CK_RV rv; 209 CK_ULONG slotcount; 210 CK_SLOT_ID_PTR slot_list; 211 CK_SLOT_ID slot_id; 212 CK_MECHANISM_INFO mech_info; 213 CK_ULONG i; 214 215 if (hSession == NULL) { 216 return (CKR_ARGUMENTS_BAD); 217 } 218 219 /* initialize PKCS #11 */ 220 if (!pkcs11_initialized) { 221 rv = C_Initialize(NULL); 222 if ((rv != CKR_OK) && 223 (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) { 224 return (rv); 225 } 226 } 227 228 /* get slot count */ 229 rv = C_GetSlotList(0, NULL, &slotcount); 230 if (rv != CKR_OK) { 231 return (rv); 232 } 233 234 if (slotcount == 0) { 235 return (CKR_FUNCTION_FAILED); 236 } 237 238 239 /* allocate memory for slot list */ 240 slot_list = malloc(slotcount * sizeof (CK_SLOT_ID)); 241 if (slot_list == NULL) { 242 return (CKR_HOST_MEMORY); 243 } 244 245 if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) { 246 free(slot_list); 247 return (rv); 248 } 249 250 /* find slot with matching mechanism */ 251 for (i = 0; i < slotcount; i++) { 252 slot_id = slot_list[i]; 253 if (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK) { 254 /* found mechanism */ 255 break; 256 } 257 } 258 259 if (i == slotcount) { 260 /* no matching mechanism found */ 261 free(slot_list); 262 return (CKR_MECHANISM_INVALID); 263 } 264 265 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL, 266 NULL, hSession); 267 268 free(slot_list); 269 return (rv); 270 } 271 272 /* 273 * SUNW_C_KeyToObject creates a secret key object for the given 274 * mechanism from the rawkey data. 275 */ 276 CK_RV 277 SUNW_C_KeyToObject(CK_SESSION_HANDLE hSession, CK_MECHANISM_TYPE mech, 278 const void *rawkey, size_t rawkey_len, CK_OBJECT_HANDLE_PTR obj) 279 { 280 281 CK_RV rv; 282 CK_SESSION_INFO session_info; 283 CK_SLOT_ID slot_id; 284 CK_MECHANISM_INFO mech_info; 285 CK_ULONG i, j; 286 CK_KEY_TYPE keytype; 287 CK_ULONG num_asym_mechs, num_mapping; 288 289 /* template for creating generic secret key object */ 290 CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; 291 292 if ((hSession == NULL) || (obj == NULL) || 293 (rawkey == NULL) || (rawkey_len == 0)) { 294 return (CKR_ARGUMENTS_BAD); 295 } 296 297 /* 298 * Check to make sure mechanism type is not for asymmetric key 299 * only operations. This function is only applicable to 300 * generating secret key. 301 */ 302 num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); 303 for (i = 0; i < num_asym_mechs; i++) { 304 if (mech == asymmetric_mechs[i]) { 305 return (CKR_MECHANISM_INVALID); 306 } 307 } 308 309 rv = C_GetSessionInfo(hSession, &session_info); 310 if (rv != CKR_OK) { 311 return (rv); 312 } 313 314 slot_id = session_info.slotID; 315 316 i = 0; 317 template[i].type = CKA_CLASS; 318 template[i].pValue = &objclass; 319 template[i].ulValueLen = sizeof (objclass); 320 i++; 321 322 /* get the key type for this mechanism */ 323 if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) { 324 return (rv); 325 } 326 327 assert(i < NUM_SECRETKEY_ATTRS); 328 template[i].type = CKA_KEY_TYPE; 329 template[i].pValue = &keytype; 330 template[i].ulValueLen = sizeof (keytype); 331 i++; 332 333 rv = C_GetMechanismInfo(slot_id, mech, &mech_info); 334 if (rv != CKR_OK) { 335 return (rv); 336 } 337 338 /* set the attribute type flag on object based on mechanism */ 339 num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); 340 for (j = 0; j < num_mapping; j++) { 341 assert(i < NUM_SECRETKEY_ATTRS); 342 template[i].type = mapping[j].attr; 343 template[i].ulValueLen = sizeof (falsevalue); 344 if (mech_info.flags & ((mapping[j]).flag)) { 345 template[i].pValue = &truevalue; 346 } else { 347 template[i].pValue = &falsevalue; 348 } 349 i++; 350 } 351 352 assert(i < NUM_SECRETKEY_ATTRS); 353 template[i].type = CKA_TOKEN; 354 template[i].pValue = &falsevalue; 355 template[i].ulValueLen = sizeof (falsevalue); 356 i++; 357 358 assert(i < NUM_SECRETKEY_ATTRS); 359 template[i].type = CKA_VALUE; 360 template[i].pValue = (CK_VOID_PTR)rawkey; 361 template[i].ulValueLen = (CK_ULONG)rawkey_len; 362 i++; 363 364 rv = C_CreateObject(hSession, template, i, obj); 365 return (rv); 366 } 367 368 369 /* 370 * pkcs11_PasswdToPBKD2Object will create a secret key from the given string 371 * (e.g. passphrase) using PKCS#5 Password-Based Key Derivation Function 2 372 * (PBKD2). 373 * 374 * Session must be open. Salt and iterations use defaults. 375 */ 376 CK_RV 377 pkcs11_PasswdToPBKD2Object(CK_SESSION_HANDLE hSession, char *passphrase, 378 size_t passphrase_len, void *salt, size_t salt_len, CK_ULONG iterations, 379 CK_KEY_TYPE key_type, CK_ULONG key_len, CK_FLAGS key_flags, 380 CK_OBJECT_HANDLE_PTR obj) 381 { 382 CK_RV rv; 383 CK_PKCS5_PBKD2_PARAMS params; 384 CK_MECHANISM mechanism; 385 CK_KEY_TYPE asym_key_type; 386 CK_ULONG i, j, num_asym_mechs, num_fixed_secs, num_mapping; 387 CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS]; 388 389 if (hSession == NULL || obj == NULL || 390 passphrase == NULL || passphrase_len == 0 || 391 iterations == 0UL) { 392 return (CKR_ARGUMENTS_BAD); 393 } 394 395 /* 396 * Check to make sure key type is not asymmetric. This function 397 * is only applicable to generating secret key. 398 */ 399 num_asym_mechs = sizeof (asymmetric_mechs) / sizeof (CK_MECHANISM_TYPE); 400 for (i = 0; i < num_asym_mechs; i++) { 401 rv = pkcs11_mech2keytype(asymmetric_mechs[i], &asym_key_type); 402 assert(rv == CKR_OK); 403 if (key_type == asym_key_type) { 404 return (CKR_KEY_TYPE_INCONSISTENT); 405 } 406 } 407 408 /* 409 * Key length must either be 0 or the correct size for PBKD of 410 * fixed-size secret keys. However, underlying key generation 411 * cannot have CKA_VALUE_LEN set for the key length attribute. 412 */ 413 num_fixed_secs = 414 sizeof (fixed_size_secrets) / sizeof (KEY_TYPE_SIZE_MAPPING); 415 for (i = 0; i < num_fixed_secs; i++) { 416 if (key_type == fixed_size_secrets[i].type) { 417 if (key_len == fixed_size_secrets[i].len) { 418 key_len = 0; 419 } 420 if (key_len == 0) { 421 break; 422 } 423 return (CKR_KEY_SIZE_RANGE); 424 } 425 } 426 427 if (salt == NULL || salt_len == 0) { 428 params.saltSource = 0; 429 params.pSaltSourceData = NULL; 430 params.ulSaltSourceDataLen = 0; 431 } else { 432 params.saltSource = CKZ_SALT_SPECIFIED; 433 params.pSaltSourceData = salt; 434 params.ulSaltSourceDataLen = salt_len; 435 } 436 params.iterations = iterations; 437 params.prf = CKP_PKCS5_PBKD2_HMAC_SHA1; 438 params.pPrfData = NULL; 439 params.ulPrfDataLen = 0; 440 params.pPassword = (CK_UTF8CHAR_PTR)passphrase; 441 params.ulPasswordLen = (CK_ULONG_PTR)&passphrase_len; 442 /* 443 * PKCS#11 spec error, ulPasswordLen should have been pulPasswordLen, 444 * or its type should have been CK_ULONG instead of CK_ULONG_PTR, 445 * but it's legacy now 446 */ 447 448 mechanism.mechanism = CKM_PKCS5_PBKD2; 449 mechanism.pParameter = ¶ms; 450 mechanism.ulParameterLen = sizeof (params); 451 452 i = 0; 453 template[i].type = CKA_CLASS; 454 template[i].pValue = &objclass; 455 template[i].ulValueLen = sizeof (objclass); 456 i++; 457 458 assert(i < NUM_SECRETKEY_ATTRS); 459 template[i].type = CKA_KEY_TYPE; 460 template[i].pValue = &key_type; 461 template[i].ulValueLen = sizeof (key_type); 462 i++; 463 464 assert(i < NUM_SECRETKEY_ATTRS); 465 template[i].type = CKA_TOKEN; 466 template[i].pValue = &falsevalue; 467 template[i].ulValueLen = sizeof (falsevalue); 468 i++; 469 470 if (key_len != 0) { 471 assert(i < NUM_SECRETKEY_ATTRS); 472 template[i].type = CKA_VALUE_LEN; 473 template[i].pValue = &key_len; 474 template[i].ulValueLen = sizeof (key_len); 475 i++; 476 } 477 478 /* 479 * C_GenerateKey may not implicitly set capability attributes, 480 * e.g. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, ... 481 */ 482 num_mapping = sizeof (mapping) / sizeof (ATTRTYPE_MECHINFO_MAPPING); 483 for (j = 0; j < num_mapping; j++) { 484 assert(i < NUM_SECRETKEY_ATTRS); 485 template[i].type = mapping[j].attr; 486 template[i].pValue = (key_flags & ((mapping[j]).flag)) ? 487 &truevalue : &falsevalue; 488 template[i].ulValueLen = sizeof (falsevalue); 489 i++; 490 } 491 492 rv = C_GenerateKey(hSession, &mechanism, template, i, obj); 493 return (rv); 494 } 495 496 /* 497 * pkcs11_ObjectToKey gets the rawkey data from a secret key object. 498 * The caller is responsible to free the allocated rawkey data. 499 * 500 * Optionally the object can be destroyed after the value is retrieved. 501 * As an example, after using pkcs11_PasswdToPBKD2Object() to create a 502 * secret key object from a passphrase, an app may call pkcs11_ObjectToKey 503 * to get the rawkey data. The intermediate object may no longer be needed 504 * and should be destroyed. 505 */ 506 CK_RV 507 pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE obj, 508 void **rawkey, size_t *rawkey_len, boolean_t destroy_obj) 509 { 510 CK_RV rv; 511 CK_ATTRIBUTE template; 512 513 if (hSession == NULL) 514 return (CKR_SESSION_HANDLE_INVALID); 515 if (obj == NULL) 516 return (CKR_OBJECT_HANDLE_INVALID); 517 if (rawkey == NULL || rawkey_len == NULL) 518 return (CKR_ARGUMENTS_BAD); 519 520 template.type = CKA_VALUE; 521 template.pValue = NULL; 522 template.ulValueLen = 0; 523 524 /* First get the size of the rawkey */ 525 rv = C_GetAttributeValue(hSession, obj, &template, 1); 526 if (rv != CKR_OK) { 527 return (rv); 528 } 529 530 template.pValue = malloc(template.ulValueLen); 531 if (template.pValue == NULL) { 532 return (CKR_HOST_MEMORY); 533 } 534 535 /* Then get the rawkey data */ 536 rv = C_GetAttributeValue(hSession, obj, &template, 1); 537 if (rv != CKR_OK) { 538 free(template.pValue); 539 return (rv); 540 } 541 542 if (destroy_obj) { 543 /* 544 * Could have asserted rv == CKR_OK, making threaded 545 * apps that share objects see stars. Here mercy is ok. 546 */ 547 (void) C_DestroyObject(hSession, obj); 548 } 549 550 *rawkey = template.pValue; 551 *rawkey_len = template.ulValueLen; 552 553 return (CKR_OK); 554 } 555 556 /* 557 * pkcs11_PasswdToKey will create PKCS#5 PBKD2 rawkey data from the 558 * given passphrase. The caller is responsible to free the allocated 559 * rawkey data. 560 */ 561 CK_RV 562 pkcs11_PasswdToKey(CK_SESSION_HANDLE hSession, char *passphrase, 563 size_t passphrase_len, void *salt, size_t salt_len, CK_KEY_TYPE key_type, 564 CK_ULONG key_len, void **rawkey, size_t *rawkey_len) 565 { 566 CK_RV rv; 567 CK_OBJECT_HANDLE obj; 568 569 rv = pkcs11_PasswdToPBKD2Object(hSession, passphrase, passphrase_len, 570 salt, salt_len, CK_PKCS5_PBKD2_ITERATIONS, key_type, key_len, 0, 571 &obj); 572 if (rv != CKR_OK) 573 return (rv); 574 rv = pkcs11_ObjectToKey(hSession, obj, rawkey, rawkey_len, B_TRUE); 575 return (rv); 576 } 577