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]
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
31 #include <sys/types.h>
32 #include <security/cryptoki.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
;
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
},
53 {CKA_VERIFY
, CKF_VERIFY
},
55 {CKA_UNWRAP
, CKF_UNWRAP
}
60 * List of mechanisms that only supports asymmetric key operations
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
{
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.
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
119 * If the function is called multiple times, it will return a new session
120 * without reinitializing the framework.
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
)
129 CK_SLOT_ID_PTR slot_list
;
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
)) {
147 rv
= C_GetSlotList(0, NULL
, &slotcount
);
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
) {
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
)) {
176 if (i
== slotcount
) {
177 /* no matching slot found */
179 return (rv
); /* this rv is from the criteria function */
182 rv
= C_OpenSession(slot_id
, CKF_SERIAL_SESSION
, NULL
,
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
195 * If the function is called multiple times, it will return a new session
196 * without reinitializing the framework.
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,
210 CK_SLOT_ID_PTR slot_list
;
212 CK_MECHANISM_INFO mech_info
;
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
)) {
229 rv
= C_GetSlotList(0, NULL
, &slotcount
);
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
) {
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 */
259 if (i
== slotcount
) {
260 /* no matching mechanism found */
262 return (CKR_MECHANISM_INVALID
);
265 rv
= C_OpenSession(slot_id
, CKF_SERIAL_SESSION
, NULL
,
273 * SUNW_C_KeyToObject creates a secret key object for the given
274 * mechanism from the rawkey data.
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
)
282 CK_SESSION_INFO session_info
;
284 CK_MECHANISM_INFO mech_info
;
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
== 0) || (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
);
314 slot_id
= session_info
.slotID
;
317 template[i
].type
= CKA_CLASS
;
318 template[i
].pValue
= &objclass
;
319 template[i
].ulValueLen
= sizeof (objclass
);
322 /* get the key type for this mechanism */
323 if ((rv
= pkcs11_mech2keytype(mech
, &keytype
)) != CKR_OK
) {
327 assert(i
< NUM_SECRETKEY_ATTRS
);
328 template[i
].type
= CKA_KEY_TYPE
;
329 template[i
].pValue
= &keytype
;
330 template[i
].ulValueLen
= sizeof (keytype
);
333 rv
= C_GetMechanismInfo(slot_id
, mech
, &mech_info
);
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
;
347 template[i
].pValue
= &falsevalue
;
352 assert(i
< NUM_SECRETKEY_ATTRS
);
353 template[i
].type
= CKA_TOKEN
;
354 template[i
].pValue
= &falsevalue
;
355 template[i
].ulValueLen
= sizeof (falsevalue
);
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
;
364 rv
= C_CreateObject(hSession
, template, i
, obj
);
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
374 * Session must be open. Salt and iterations use defaults.
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
)
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
== 0 || obj
== NULL
||
390 passphrase
== NULL
|| passphrase_len
== 0 ||
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.
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
) {
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;
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
= ¶ms
;
450 mechanism
.ulParameterLen
= sizeof (params
);
453 template[i
].type
= CKA_CLASS
;
454 template[i
].pValue
= &objclass
;
455 template[i
].ulValueLen
= sizeof (objclass
);
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
);
464 assert(i
< NUM_SECRETKEY_ATTRS
);
465 template[i
].type
= CKA_TOKEN
;
466 template[i
].pValue
= &falsevalue
;
467 template[i
].ulValueLen
= sizeof (falsevalue
);
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
);
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
);
492 rv
= C_GenerateKey(hSession
, &mechanism
, template, i
, obj
);
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.
507 pkcs11_ObjectToKey(CK_SESSION_HANDLE hSession
, CK_OBJECT_HANDLE obj
,
508 void **rawkey
, size_t *rawkey_len
, boolean_t destroy_obj
)
511 CK_ATTRIBUTE
template;
514 return (CKR_SESSION_HANDLE_INVALID
);
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);
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);
538 free(template.pValue
);
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
;
557 * pkcs11_PasswdToKey will create PKCS#5 PBKD2 rawkey data from the
558 * given passphrase. The caller is responsible to free the allocated
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
)
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,
574 rv
= pkcs11_ObjectToKey(hSession
, obj
, rawkey
, rawkey_len
, B_TRUE
);