8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / pkcs11 / libpkcs11 / common / pkcs11SUNWExtensions.c
blob68f997e103a3800e653380e36189673370bc3357
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Solaris specific functions to reduce the initialization
27 * overhead of using PKCS #11
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>
37 static CK_OBJECT_CLASS objclass = CKO_SECRET_KEY;
38 static CK_BBOOL falsevalue = FALSE;
39 static CK_BBOOL truevalue = TRUE;
41 #define NUM_SECRETKEY_ATTRS 12
43 typedef struct _ATTRTYPE_MECHINFO_MAPPING {
44 CK_ATTRIBUTE_TYPE attr;
45 CK_FLAGS flag;
46 } ATTRTYPE_MECHINFO_MAPPING;
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}
60 * List of mechanisms that only supports asymmetric key operations
61 * in PKCS #11 V2.11
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
73 typedef struct _KEY_TYPE_SIZE_MAPPING {
74 CK_KEY_TYPE type;
75 CK_ULONG len;
76 } KEY_TYPE_SIZE_MAPPING;
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.
83 * Discrete-sized keys, such as AES and Twofish, and variable sized
84 * keys, such as Blowfish, are not in this list.
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}
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.
97 boolean_t
98 match_mech(CK_SLOT_ID slot_id, void *args, CK_RV *rv)
100 CK_MECHANISM_INFO mech_info;
101 CK_MECHANISM_TYPE mech = (CK_MECHANISM_TYPE)args;
103 *rv = CKR_MECHANISM_INVALID;
104 return (C_GetMechanismInfo(slot_id, mech, &mech_info) == CKR_OK);
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.
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.
119 * If the function is called multiple times, it will return a new session
120 * without reinitializing the framework.
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)
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;
133 if (hSession == NULL || criteria == NULL) {
134 return (CKR_ARGUMENTS_BAD);
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);
146 /* get slot count */
147 rv = C_GetSlotList(0, NULL, &slotcount);
148 if (rv != CKR_OK) {
149 return (rv);
152 if (slotcount == 0) {
153 return (CKR_FUNCTION_FAILED);
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);
163 if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) {
164 free(slot_list);
165 return (rv);
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;
176 if (i == slotcount) {
177 /* no matching slot found */
178 free(slot_list);
179 return (rv); /* this rv is from the criteria function */
182 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL,
183 NULL, hSession);
185 free(slot_list);
186 return (rv);
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.
195 * If the function is called multiple times, it will return a new session
196 * without reinitializing the framework.
198 CK_RV
199 SUNW_C_GetMechSession(CK_MECHANISM_TYPE mech, CK_SESSION_HANDLE_PTR hSession)
202 * All the code in this function can be replaced with one line:
204 * return (pkcs11_GetCriteriaSession(match_mech, (void *)mech,
205 * hSession));
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;
215 if (hSession == NULL) {
216 return (CKR_ARGUMENTS_BAD);
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);
228 /* get slot count */
229 rv = C_GetSlotList(0, NULL, &slotcount);
230 if (rv != CKR_OK) {
231 return (rv);
234 if (slotcount == 0) {
235 return (CKR_FUNCTION_FAILED);
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);
245 if ((rv = C_GetSlotList(0, slot_list, &slotcount)) != CKR_OK) {
246 free(slot_list);
247 return (rv);
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;
259 if (i == slotcount) {
260 /* no matching mechanism found */
261 free(slot_list);
262 return (CKR_MECHANISM_INVALID);
265 rv = C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL,
266 NULL, hSession);
268 free(slot_list);
269 return (rv);
273 * SUNW_C_KeyToObject creates a secret key object for the given
274 * mechanism from the rawkey data.
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)
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;
289 /* template for creating generic secret key object */
290 CK_ATTRIBUTE template[NUM_SECRETKEY_ATTRS];
292 if ((hSession == NULL) || (obj == NULL) ||
293 (rawkey == NULL) || (rawkey_len == 0)) {
294 return (CKR_ARGUMENTS_BAD);
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.
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);
309 rv = C_GetSessionInfo(hSession, &session_info);
310 if (rv != CKR_OK) {
311 return (rv);
314 slot_id = session_info.slotID;
316 i = 0;
317 template[i].type = CKA_CLASS;
318 template[i].pValue = &objclass;
319 template[i].ulValueLen = sizeof (objclass);
320 i++;
322 /* get the key type for this mechanism */
323 if ((rv = pkcs11_mech2keytype(mech, &keytype)) != CKR_OK) {
324 return (rv);
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++;
333 rv = C_GetMechanismInfo(slot_id, mech, &mech_info);
334 if (rv != CKR_OK) {
335 return (rv);
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;
349 i++;
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++;
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++;
364 rv = C_CreateObject(hSession, template, i, obj);
365 return (rv);
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).
374 * Session must be open. Salt and iterations use defaults.
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)
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];
389 if (hSession == NULL || obj == NULL ||
390 passphrase == NULL || passphrase_len == 0 ||
391 iterations == 0UL) {
392 return (CKR_ARGUMENTS_BAD);
396 * Check to make sure key type is not asymmetric. This function
397 * is only applicable to generating secret key.
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);
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.
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;
420 if (key_len == 0) {
421 break;
423 return (CKR_KEY_SIZE_RANGE);
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;
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;
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
448 mechanism.mechanism = CKM_PKCS5_PBKD2;
449 mechanism.pParameter = &params;
450 mechanism.ulParameterLen = sizeof (params);
452 i = 0;
453 template[i].type = CKA_CLASS;
454 template[i].pValue = &objclass;
455 template[i].ulValueLen = sizeof (objclass);
456 i++;
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++;
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++;
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++;
479 * C_GenerateKey may not implicitly set capability attributes,
480 * e.g. CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, ...
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++;
492 rv = C_GenerateKey(hSession, &mechanism, template, i, obj);
493 return (rv);
497 * pkcs11_ObjectToKey gets the rawkey data from a secret key object.
498 * The caller is responsible to free the allocated rawkey data.
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.
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)
510 CK_RV rv;
511 CK_ATTRIBUTE template;
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);
520 template.type = CKA_VALUE;
521 template.pValue = NULL;
522 template.ulValueLen = 0;
524 /* First get the size of the rawkey */
525 rv = C_GetAttributeValue(hSession, obj, &template, 1);
526 if (rv != CKR_OK) {
527 return (rv);
530 template.pValue = malloc(template.ulValueLen);
531 if (template.pValue == NULL) {
532 return (CKR_HOST_MEMORY);
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);
542 if (destroy_obj) {
544 * Could have asserted rv == CKR_OK, making threaded
545 * apps that share objects see stars. Here mercy is ok.
547 (void) C_DestroyObject(hSession, obj);
550 *rawkey = template.pValue;
551 *rawkey_len = template.ulValueLen;
553 return (CKR_OK);
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.
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)
566 CK_RV rv;
567 CK_OBJECT_HANDLE obj;
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);