PageRenderTime 55ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/lib/pkcs11/libpkcs11/common/pkcs11SUNWExtensions.c

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