9642 PKCS#11 softtoken should use explicit_bzero
[unleashed.git] / usr / src / lib / pkcs11 / pkcs11_kernel / common / kernelKeys.c
blob1e35f0f5b44360dd3768abb2d53aca9ad60a716f
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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2018, Joyent, Inc.
27 #include <strings.h>
28 #include <errno.h>
29 #include <ecc_impl.h>
30 #include <security/cryptoki.h>
31 #include <sys/crypto/ioctl.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelObject.h"
36 static boolean_t
37 attribute_in_template(CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
39 int i;
41 for (i = 0; i < cnt; i++) {
42 if (t[i].type == type)
43 return (B_TRUE);
45 return (B_FALSE);
49 * This routine returns modulus bytes rounded up to the nearest 8 byte
50 * chunk. This is so we don't have to pass in max sized buffers for
51 * returned attributes. Every unnecessary byte that we pass in results
52 * in a kernel allocation.
54 static ulong_t
55 get_modulus_bytes(CK_ATTRIBUTE_PTR t, CK_ULONG cnt)
57 CK_ULONG modulus_len;
58 int i;
60 for (i = 0; i < cnt; i++) {
61 if (t[i].type == CKA_MODULUS_BITS) {
62 get_ulong_attr_from_template(&modulus_len, &t[i]);
63 /* convert from bit length to byte length */
64 modulus_len = (modulus_len - 1) / 64 + 1;
65 return (modulus_len * 8);
68 return (0);
72 * Remove specified attribute from array. Storage for the attribute's
73 * value is freed if 'free_attr' is TRUE. Attributes are shifted so they are
74 * contiguous within the array, i.e. the next attribute is shifted into
75 * the position of the removed attribute. Returns TRUE if specified
76 * attribute is removed.
78 static boolean_t
79 remove_one_attribute(CK_ATTRIBUTE_PTR t, CK_ULONG type, uint_t count,
80 boolean_t free_attr)
82 int i, j;
84 for (i = 0, j = 0; i < count; i++) {
85 if (t[i].type == type) {
86 if (free_attr) {
87 free(t[i].pValue);
89 continue;
91 if (i != j) {
92 t[j].type = t[i].type;
93 t[j].pValue = t[i].pValue;
94 t[j].ulValueLen = t[i].ulValueLen;
96 j++;
98 if (j == count)
99 return (B_FALSE);
101 /* safety */
102 t[j].pValue = NULL;
103 t[j].ulValueLen = 0;
104 return (B_TRUE);
107 static boolean_t
108 is_secret_key_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
110 int i;
111 for (i = 0; i < ulAttributeCount; i++) {
112 if (pTemplate[i].type == CKA_CLASS &&
113 *(CK_OBJECT_CLASS *)(pTemplate[i].pValue) ==
114 CKO_SECRET_KEY)
115 return (B_TRUE);
117 return (B_FALSE);
121 * Allocate a template with space for new_count entries and copy the
122 * specified template into the new template.
124 static CK_ATTRIBUTE_PTR
125 grow_template(CK_ATTRIBUTE_PTR old_template, CK_ULONG old_count,
126 CK_ULONG new_count)
128 CK_ATTRIBUTE_PTR new_template;
130 new_template = malloc(new_count * sizeof (CK_ATTRIBUTE));
131 if (new_template != NULL)
132 bcopy(old_template, new_template,
133 old_count * sizeof (CK_ATTRIBUTE));
134 return (new_template);
138 * For fixed length keys such as DES, return the length based on
139 * the key type. For variable length keys such as AES, take the
140 * length from the CKA_VALUE_LEN attribute.
142 static int
143 get_key_len_from_template(CK_MECHANISM_PTR pMechanism,
144 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,
145 kernel_object_t *basekey_p, ulong_t *key_len)
147 boolean_t fixed_len_key = B_FALSE;
148 ulong_t key_type;
149 int i;
151 for (i = 0; i < ulAttributeCount; i++) {
152 if (pTemplate[i].type == CKA_KEY_TYPE) {
153 get_ulong_attr_from_template(&key_type, &pTemplate[i]);
154 break;
157 /* CKA_KEY_TYPE must be present */
158 if (i == ulAttributeCount)
159 return (CKR_TEMPLATE_INCOMPLETE);
161 switch (key_type) {
162 case CKK_DES:
163 *key_len = 8;
164 fixed_len_key = B_TRUE;
165 break;
166 case CKK_DES3:
167 *key_len = 24;
168 fixed_len_key = B_TRUE;
169 break;
170 case CKK_AES:
171 case CKK_BLOWFISH:
172 for (i = 0; i < ulAttributeCount; i++) {
173 if (pTemplate[i].type == CKA_VALUE_LEN) {
174 get_ulong_attr_from_template(key_len,
175 &pTemplate[i]);
176 break;
179 /* CKA_VALUE_LEN must be present */
180 if (i == ulAttributeCount)
181 return (CKR_TEMPLATE_INCOMPLETE);
182 break;
183 case CKK_GENERIC_SECRET:
185 * The key will not be truncated, so we need to
186 * get the max length for the mechanism.
188 if (pMechanism->mechanism == CKM_DH_PKCS_DERIVE) {
189 CK_ATTRIBUTE tmp;
191 tmp.type = CKA_PRIME;
192 tmp.pValue = NULL;
194 /* get size of attribute */
195 if (kernel_get_attribute(basekey_p, &tmp) != CKR_OK) {
196 return (CKR_ARGUMENTS_BAD);
198 *key_len = tmp.ulValueLen;
199 } else if (pMechanism->mechanism == CKM_ECDH1_DERIVE) {
200 *key_len = EC_MAX_VALUE_LEN;
201 } else {
202 return (CKR_ARGUMENTS_BAD);
204 break;
205 default:
206 return (CKR_ATTRIBUTE_VALUE_INVALID);
209 if (fixed_len_key && attribute_in_template(CKA_VALUE_LEN,
210 pTemplate, ulAttributeCount))
211 return (CKR_TEMPLATE_INCONSISTENT);
213 return (CKR_OK);
216 /* find specified attribute src template and copy to dest */
217 static int
218 copy_attribute(CK_ULONG type, CK_ATTRIBUTE_PTR src, CK_ULONG src_cnt,
219 CK_ATTRIBUTE_PTR dst)
221 int rv, i;
223 for (i = 0; i < src_cnt; i++) {
224 if (src[i].type == type) {
225 rv = get_string_from_template(dst, &src[i]);
226 break;
230 * The public template didn't have attribute.
232 if (i == src_cnt) {
233 rv = CKR_TEMPLATE_INCOMPLETE;
235 return (rv);
238 static void
239 free_attributes(caddr_t p, uint_t *countp)
241 if (*countp > 0) {
242 free_object_attributes(p, *countp);
243 *countp = 0;
247 CK_RV
248 key_gen_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
249 CK_ULONG ulCount, kernel_session_t *session_p,
250 crypto_mech_type_t k_mech_type, kernel_object_t *new_objp)
252 crypto_nostore_generate_key_t obj_ngk;
253 char *key_buf = NULL;
254 CK_ATTRIBUTE_PTR newTemplate = NULL;
255 CK_BBOOL is_token_obj = FALSE;
256 CK_RV rv = CKR_OK;
257 ulong_t key_len = 0;
258 uint_t attr_count;
259 int r;
261 obj_ngk.ngk_in_count = 0;
262 obj_ngk.ngk_out_count = 0;
264 rv = get_key_len_from_template(pMechanism, pTemplate, ulCount,
265 NULL, &key_len);
266 if (rv != CRYPTO_SUCCESS)
267 goto failed_exit;
269 if ((key_buf = malloc(key_len)) == NULL) {
270 rv = CKR_HOST_MEMORY;
271 goto failed_exit;
274 attr_count = ulCount + 1;
275 newTemplate = grow_template(pTemplate, ulCount, attr_count);
276 if (newTemplate == NULL) {
277 rv = CKR_HOST_MEMORY;
278 goto failed_exit;
281 /* Now add the CKA_VALUE attribute to template */
282 newTemplate[ulCount].type = CKA_VALUE;
283 newTemplate[ulCount].pValue = (caddr_t)key_buf;
284 newTemplate[ulCount].ulValueLen = key_len;
286 rv = process_object_attributes(newTemplate, attr_count - 1,
287 &obj_ngk.ngk_in_attributes, &is_token_obj);
288 if (rv != CKR_OK) {
289 goto failed_exit;
291 rv = process_object_attributes(&newTemplate[ulCount],
292 1, &obj_ngk.ngk_out_attributes, &is_token_obj);
293 if (rv != CKR_OK) {
294 goto failed_exit;
297 /* Cannot create a token object with a READ-ONLY session. */
298 if (is_token_obj && session_p->ses_RO) {
299 rv = CKR_SESSION_READ_ONLY;
300 goto failed_exit;
303 /* Call the CRYPTO_NOSTORE_GENERATE_KEY ioctl */
304 obj_ngk.ngk_session = session_p->k_session;
305 obj_ngk.ngk_in_count = attr_count - 1;
306 obj_ngk.ngk_out_count = 1;
307 obj_ngk.ngk_mechanism.cm_type = k_mech_type;
308 obj_ngk.ngk_mechanism.cm_param = pMechanism->pParameter;
309 obj_ngk.ngk_mechanism.cm_param_len = pMechanism->ulParameterLen;
311 while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY,
312 &obj_ngk)) < 0) {
313 if (errno != EINTR)
314 break;
316 if (r < 0) {
317 rv = CKR_FUNCTION_FAILED;
318 } else {
319 rv = crypto2pkcs11_error_number(obj_ngk.ngk_return_value);
321 free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
322 if (rv != CKR_OK) {
323 goto failed_exit;
326 rv = get_object_attributes(&newTemplate[ulCount], 1,
327 obj_ngk.ngk_out_attributes);
328 free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
329 if (rv != CRYPTO_SUCCESS) {
330 goto failed_exit;
334 * CKA_VALUE_LEN is not stored with the secret key object,
335 * so we remove it by shifting attributes down one.
337 (void) remove_one_attribute(newTemplate, CKA_VALUE_LEN,
338 attr_count, B_FALSE);
340 rv = kernel_build_object(newTemplate, attr_count - 1,
341 new_objp, session_p, KERNEL_GEN_KEY);
342 if (rv != CRYPTO_SUCCESS) {
343 goto failed_exit;
345 new_objp->is_lib_obj = B_TRUE;
346 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
347 free(newTemplate);
348 freezero(key_buf, key_len);
349 return (CKR_OK);
351 failed_exit:
352 free_attributes(obj_ngk.ngk_in_attributes, &obj_ngk.ngk_in_count);
353 free_attributes(obj_ngk.ngk_out_attributes, &obj_ngk.ngk_out_count);
354 freezero(key_buf, key_len);
355 free(newTemplate);
356 return (rv);
359 CK_RV
360 C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
361 CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
363 CK_RV rv = CKR_OK;
364 kernel_session_t *session_p;
365 kernel_object_t *new_objp = NULL;
366 kernel_slot_t *pslot;
367 boolean_t ses_lock_held = B_FALSE;
368 CK_BBOOL is_pri_obj;
369 CK_BBOOL is_token_obj = FALSE;
370 crypto_mech_type_t k_mech_type;
371 int r;
373 if (!kernel_initialized)
374 return (CKR_CRYPTOKI_NOT_INITIALIZED);
376 /* Obtain the session pointer */
377 rv = handle2session(hSession, &session_p);
378 if (rv != CKR_OK)
379 return (rv);
381 if ((pMechanism == NULL) || (phKey == NULL)) {
382 rv = CKR_ARGUMENTS_BAD;
383 goto failed_exit;
386 if ((pTemplate == NULL) && (ulCount != 0)) {
387 rv = CKR_ARGUMENTS_BAD;
388 goto failed_exit;
391 /* Get the kernel's internal mechanism number. */
392 rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
393 if (rv != CKR_OK) {
394 goto failed_exit;
397 /* Create an object wrapper in the library first */
398 new_objp = calloc(1, sizeof (kernel_object_t));
399 if (new_objp == NULL) {
400 rv = CKR_HOST_MEMORY;
401 goto failed_exit;
405 * Special Case: if token does not support object creation,
406 * but does support key generation by value, then create a session
407 * object and initialize with value returned by token.
409 pslot = slot_table[session_p->ses_slotid];
410 if (!pslot->sl_func_list.fl_object_create) {
411 rv = key_gen_by_value(pMechanism, pTemplate, ulCount, session_p,
412 k_mech_type, new_objp);
413 if (rv != CKR_OK)
414 goto failed_exit;
415 } else {
416 crypto_object_generate_key_t obj_gk;
418 /* Process the attributes */
419 rv = process_object_attributes(pTemplate, ulCount,
420 &obj_gk.gk_attributes, &is_token_obj);
421 if (rv != CKR_OK) {
422 goto failed_exit;
424 /* Cannot create a token object with a READ-ONLY session. */
425 if (is_token_obj && session_p->ses_RO) {
426 free_object_attributes(obj_gk.gk_attributes, ulCount);
427 rv = CKR_SESSION_READ_ONLY;
428 goto failed_exit;
431 /* Call the CRYPTO_GENERATE_KEY ioctl */
432 obj_gk.gk_session = session_p->k_session;
433 obj_gk.gk_count = ulCount;
434 obj_gk.gk_mechanism.cm_type = k_mech_type;
435 obj_gk.gk_mechanism.cm_param = pMechanism->pParameter;
436 obj_gk.gk_mechanism.cm_param_len = pMechanism->ulParameterLen;
438 while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY,
439 &obj_gk)) < 0) {
440 if (errno != EINTR)
441 break;
443 if (r < 0) {
444 rv = CKR_FUNCTION_FAILED;
445 } else {
446 rv = crypto2pkcs11_error_number(obj_gk.gk_return_value);
449 free_object_attributes(obj_gk.gk_attributes, ulCount);
451 if (rv != CKR_OK) {
452 goto failed_exit;
455 /* Get the value of the CKA_PRIVATE attribute. */
456 rv = get_cka_private_value(session_p, obj_gk.gk_handle,
457 &is_pri_obj);
458 if (rv != CKR_OK) {
459 goto failed_exit;
463 * Store the kernel object handle in the object wrapper and
464 * initialize the library object.
466 new_objp->k_handle = obj_gk.gk_handle;
467 new_objp->is_lib_obj = B_FALSE;
468 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
469 new_objp->extra_attrlistp = NULL;
471 if (is_pri_obj)
472 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
473 else
474 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
476 if (is_token_obj)
477 new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
478 else
479 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
482 (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
483 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
486 * Add the new object to the slot's token object list if it is a
487 * a token object. Otherwise, add it to the session's object list.
489 if (is_token_obj) {
490 pslot = slot_table[session_p->ses_slotid];
491 kernel_add_token_object_to_slot(new_objp, pslot);
492 } else {
493 kernel_add_object_to_session(new_objp, session_p);
496 *phKey = (CK_OBJECT_HANDLE)new_objp;
497 REFRELE(session_p, ses_lock_held);
498 return (rv);
500 failed_exit:
501 if (new_objp != NULL) {
502 (void) free(new_objp);
505 REFRELE(session_p, ses_lock_held);
506 return (rv);
509 CK_RV
510 key_gen_rsa_by_value(CK_MECHANISM_PTR pMechanism,
511 CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
512 CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
513 kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
514 kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
516 crypto_nostore_generate_key_pair_t obj_nkp;
517 CK_ATTRIBUTE_PTR pubTemplate = NULL;
518 CK_ATTRIBUTE_PTR priTemplate = NULL;
519 CK_RV rv = CKR_OK;
520 CK_BBOOL is_token_obj1 = FALSE;
521 CK_BBOOL is_token_obj2 = FALSE;
522 uint_t pub_attr_count, pri_attr_count;
523 uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
524 char public_modulus[512];
525 char public_exponent[8];
526 char private_exponent[512];
527 char private_modulus[512];
528 char prime_1[512];
529 char prime_2[512];
530 char exponent_1[512];
531 char exponent_2[512];
532 char coefficient[512];
533 CK_ULONG pub_class = CKO_PUBLIC_KEY;
534 CK_ULONG pri_class = CKO_PRIVATE_KEY;
535 CK_ULONG key_type;
536 CK_ULONG modulus_bytes;
537 boolean_t has_class, has_key_type, has_pub_exponent;
538 int n, r;
540 obj_nkp.nkp_in_public_count = 0;
541 obj_nkp.nkp_out_public_count = 0;
542 obj_nkp.nkp_in_private_count = 0;
543 obj_nkp.nkp_out_private_count = 0;
545 /* modulus bits must be present when generating a RSA key pair */
546 if (!attribute_in_template(CKA_MODULUS_BITS, pPublicKeyTemplate,
547 ulPublicKeyAttributeCount)) {
548 rv = CKR_TEMPLATE_INCOMPLETE;
549 goto failed_exit;
552 modulus_bytes = get_modulus_bytes(pPublicKeyTemplate,
553 ulPublicKeyAttributeCount);
556 * Add CKA_MODULUS to the public template.
557 * This attribute must not be in the template.
559 if (attribute_in_template(CKA_MODULUS, pPublicKeyTemplate,
560 ulPublicKeyAttributeCount)) {
561 rv = CKR_TEMPLATE_INCONSISTENT;
562 goto failed_exit;
564 has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
565 ulPublicKeyAttributeCount);
566 has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
567 ulPublicKeyAttributeCount);
568 has_pub_exponent = attribute_in_template(CKA_PUBLIC_EXPONENT,
569 pPublicKeyTemplate, ulPublicKeyAttributeCount);
571 pub_attr_count = ulPublicKeyAttributeCount + 1;
572 if (!has_class)
573 pub_attr_count++;
574 if (!has_key_type)
575 pub_attr_count++;
576 if (!has_pub_exponent)
577 pub_attr_count++;
578 pubTemplate = grow_template(pPublicKeyTemplate,
579 ulPublicKeyAttributeCount, pub_attr_count);
580 if (pubTemplate == NULL) {
581 rv = CKR_HOST_MEMORY;
582 goto failed_exit;
585 n = ulPublicKeyAttributeCount;
586 if (!has_class) {
587 pubTemplate[n].type = CKA_CLASS;
588 pubTemplate[n].pValue = (caddr_t)&pub_class;
589 pubTemplate[n].ulValueLen = sizeof (pub_class);
590 n++;
592 if (!has_key_type) {
593 pubTemplate[n].type = CKA_KEY_TYPE;
594 key_type = CKK_RSA;
595 pubTemplate[n].pValue = (caddr_t)&key_type;
596 pubTemplate[n].ulValueLen = sizeof (key_type);
597 n++;
599 if (!has_pub_exponent) {
600 pubTemplate[n].type = CKA_PUBLIC_EXPONENT;
601 pubTemplate[n].pValue = (caddr_t)public_exponent;
602 pubTemplate[n].ulValueLen = modulus_bytes;
603 n++;
604 pub_out_attr_count++;
606 pubTemplate[n].type = CKA_MODULUS;
607 pubTemplate[n].pValue = (caddr_t)public_modulus;
608 pubTemplate[n].ulValueLen = modulus_bytes;
609 pub_out_attr_count++;
611 rv = process_object_attributes(pubTemplate,
612 pub_attr_count - pub_out_attr_count,
613 &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
614 if (rv != CKR_OK) {
615 goto failed_exit;
617 obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
619 rv = process_object_attributes(
620 &pubTemplate[pub_attr_count - pub_out_attr_count],
621 pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
622 &is_token_obj1);
623 if (rv != CKR_OK) {
624 goto failed_exit;
626 obj_nkp.nkp_out_public_count = pub_out_attr_count;
629 * Cannot create a token object with a READ-ONLY
630 * session.
632 if (is_token_obj1 && session_p->ses_RO) {
633 rv = CKR_SESSION_READ_ONLY;
634 goto failed_exit;
638 * Add CKA_MODULUS and CKA_PRIVATE_EXPONENT
639 * to the private template. These attributes
640 * must not be in the template.
642 if (attribute_in_template(CKA_PRIVATE_EXPONENT,
643 pPrivateKeyTemplate, ulPrivateKeyAttributeCount) ||
644 attribute_in_template(CKA_MODULUS,
645 pPrivateKeyTemplate, ulPrivateKeyAttributeCount)) {
646 rv = CKR_TEMPLATE_INCONSISTENT;
647 goto failed_exit;
649 has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
650 ulPrivateKeyAttributeCount);
651 has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
652 ulPrivateKeyAttributeCount);
654 pri_attr_count = ulPrivateKeyAttributeCount + 7;
655 if (!has_class)
656 pri_attr_count++;
657 if (!has_key_type)
658 pri_attr_count++;
660 /* allocate space for CKA_PUBLIC_EXPONENT */
661 priTemplate = grow_template(pPrivateKeyTemplate,
662 ulPrivateKeyAttributeCount, pri_attr_count + 1);
663 if (priTemplate == NULL) {
664 rv = CKR_HOST_MEMORY;
665 goto failed_exit;
667 n = ulPrivateKeyAttributeCount;
668 if (!has_class) {
669 priTemplate[n].type = CKA_CLASS;
670 priTemplate[n].pValue = (caddr_t)&pri_class;
671 priTemplate[n].ulValueLen = sizeof (pri_class);
672 n++;
674 if (!has_key_type) {
675 priTemplate[n].type = CKA_KEY_TYPE;
676 key_type = CKK_RSA;
677 priTemplate[n].pValue = (caddr_t)&key_type;
678 priTemplate[n].ulValueLen = sizeof (key_type);
679 n++;
681 priTemplate[n].type = CKA_MODULUS;
682 priTemplate[n].pValue = (caddr_t)private_modulus;
683 priTemplate[n].ulValueLen = modulus_bytes;
684 pri_out_attr_count++;
686 n++;
687 priTemplate[n].type = CKA_PRIVATE_EXPONENT;
688 priTemplate[n].pValue = (caddr_t)private_exponent;
689 priTemplate[n].ulValueLen = modulus_bytes;
690 pri_out_attr_count++;
692 n++;
693 priTemplate[n].type = CKA_PRIME_1;
694 priTemplate[n].pValue = (caddr_t)prime_1;
695 priTemplate[n].ulValueLen = modulus_bytes/2;
696 pri_out_attr_count++;
698 n++;
699 priTemplate[n].type = CKA_PRIME_2;
700 priTemplate[n].pValue = (caddr_t)prime_2;
701 priTemplate[n].ulValueLen = modulus_bytes/2;
702 pri_out_attr_count++;
704 n++;
705 priTemplate[n].type = CKA_EXPONENT_1;
706 priTemplate[n].pValue = (caddr_t)exponent_1;
707 priTemplate[n].ulValueLen = modulus_bytes/2;
708 pri_out_attr_count++;
710 n++;
711 priTemplate[n].type = CKA_EXPONENT_2;
712 priTemplate[n].pValue = (caddr_t)exponent_2;
713 priTemplate[n].ulValueLen = modulus_bytes/2;
714 pri_out_attr_count++;
716 n++;
717 priTemplate[n].type = CKA_COEFFICIENT;
718 priTemplate[n].pValue = (caddr_t)coefficient;
719 priTemplate[n].ulValueLen = modulus_bytes/2;
720 pri_out_attr_count++;
722 rv = process_object_attributes(priTemplate,
723 pri_attr_count - pri_out_attr_count,
724 &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
725 if (rv != CKR_OK) {
726 goto failed_exit;
728 obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
730 rv = process_object_attributes(
731 &priTemplate[pri_attr_count - pri_out_attr_count],
732 pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
733 &is_token_obj2);
734 if (rv != CKR_OK) {
735 goto failed_exit;
737 obj_nkp.nkp_out_private_count = pri_out_attr_count;
740 * The public key and the private key need to contain the same
741 * attribute values for CKA_TOKEN.
743 if (is_token_obj1 != is_token_obj2) {
744 rv = CKR_ATTRIBUTE_VALUE_INVALID;
745 goto failed_exit;
748 /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
749 obj_nkp.nkp_session = session_p-> k_session;
750 obj_nkp.nkp_mechanism.cm_type = k_mech_type;
751 obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
752 obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
754 while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
755 &obj_nkp)) < 0) {
756 if (errno != EINTR)
757 break;
759 if (r < 0) {
760 rv = CKR_FUNCTION_FAILED;
761 } else {
762 rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
764 free_attributes(obj_nkp.nkp_in_public_attributes,
765 &obj_nkp.nkp_in_public_count);
766 free_attributes(obj_nkp.nkp_in_private_attributes,
767 &obj_nkp.nkp_in_private_count);
769 if (rv != CKR_OK) {
770 goto failed_exit;
773 rv = get_object_attributes(
774 &pubTemplate[pub_attr_count - pub_out_attr_count],
775 pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
776 if (rv == CRYPTO_SUCCESS) {
777 rv = get_object_attributes(
778 &priTemplate[pri_attr_count - pri_out_attr_count],
779 pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
781 free_attributes(obj_nkp.nkp_out_public_attributes,
782 &obj_nkp.nkp_out_public_count);
783 free_attributes(obj_nkp.nkp_out_private_attributes,
784 &obj_nkp.nkp_out_private_count);
785 if (rv != CRYPTO_SUCCESS) {
786 goto failed_exit;
789 /* store generated modulus and public exponent */
790 rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
791 session_p, KERNEL_GEN_KEY);
792 if (rv != CRYPTO_SUCCESS) {
793 goto failed_exit;
797 * Copy CKA_PUBLIC_EXPONENT from the public template
798 * to the private template.
800 rv = copy_attribute(CKA_PUBLIC_EXPONENT, pubTemplate,
801 pub_attr_count, &priTemplate[pri_attr_count]);
802 if (rv != CRYPTO_SUCCESS) {
803 goto failed_exit;
806 rv = kernel_build_object(priTemplate, pri_attr_count + 1, new_pri_objp,
807 session_p, KERNEL_GEN_KEY);
808 (void) free(priTemplate[pri_attr_count].pValue);
809 if (rv != CRYPTO_SUCCESS) {
810 goto failed_exit;
812 (void) free(pubTemplate);
813 (void) free(priTemplate);
815 new_pub_objp->is_lib_obj = B_TRUE;
816 new_pri_objp->is_lib_obj = B_TRUE;
817 new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
818 new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
819 (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
820 new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
821 (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
822 new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
823 return (CKR_OK);
825 failed_exit:
826 free_attributes(obj_nkp.nkp_in_public_attributes,
827 &obj_nkp.nkp_in_public_count);
828 free_attributes(obj_nkp.nkp_out_public_attributes,
829 &obj_nkp.nkp_out_public_count);
830 free_attributes(obj_nkp.nkp_in_private_attributes,
831 &obj_nkp.nkp_in_private_count);
832 free_attributes(obj_nkp.nkp_out_private_attributes,
833 &obj_nkp.nkp_out_private_count);
834 if (pubTemplate != NULL) {
835 (void) free(pubTemplate);
837 if (priTemplate != NULL) {
838 (void) free(priTemplate);
840 return (rv);
843 CK_RV
844 key_gen_dh_by_value(CK_MECHANISM_PTR pMechanism,
845 CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
846 CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
847 kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
848 kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
850 crypto_nostore_generate_key_pair_t obj_nkp;
851 CK_ATTRIBUTE_PTR pubTemplate = NULL;
852 CK_ATTRIBUTE_PTR priTemplate = NULL;
853 CK_RV rv = CKR_OK;
854 CK_BBOOL is_token_obj1 = FALSE;
855 CK_BBOOL is_token_obj2 = FALSE;
856 uint_t pub_attr_count, pri_attr_count;
857 uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
858 char public_value[256];
859 char private_value[256];
860 CK_ULONG pub_class = CKO_PUBLIC_KEY;
861 CK_ULONG pri_class = CKO_PRIVATE_KEY;
862 CK_ULONG key_type;
863 boolean_t has_class, has_key_type;
864 int n, r;
866 obj_nkp.nkp_in_public_count = 0;
867 obj_nkp.nkp_out_public_count = 0;
868 obj_nkp.nkp_in_private_count = 0;
869 obj_nkp.nkp_out_private_count = 0;
872 * Add CKA_VALUE to the public template.
873 * This attribute must not be in the template.
875 if (attribute_in_template(CKA_VALUE, pPublicKeyTemplate,
876 ulPublicKeyAttributeCount)) {
877 rv = CKR_TEMPLATE_INCONSISTENT;
878 goto failed_exit;
880 has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
881 ulPublicKeyAttributeCount);
882 has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
883 ulPublicKeyAttributeCount);
885 pub_attr_count = ulPublicKeyAttributeCount + 1;
886 if (!has_class)
887 pub_attr_count++;
888 if (!has_key_type)
889 pub_attr_count++;
890 pubTemplate = grow_template(pPublicKeyTemplate,
891 ulPublicKeyAttributeCount, pub_attr_count);
892 if (pubTemplate == NULL) {
893 rv = CKR_HOST_MEMORY;
894 goto failed_exit;
897 n = ulPublicKeyAttributeCount;
898 if (!has_class) {
899 pubTemplate[n].type = CKA_CLASS;
900 pubTemplate[n].pValue = (caddr_t)&pub_class;
901 pubTemplate[n].ulValueLen = sizeof (pub_class);
902 n++;
904 if (!has_key_type) {
905 pubTemplate[n].type = CKA_KEY_TYPE;
906 key_type = CKK_DH;
907 pubTemplate[n].pValue = (caddr_t)&key_type;
908 pubTemplate[n].ulValueLen = sizeof (key_type);
909 n++;
911 pubTemplate[n].type = CKA_VALUE;
912 pubTemplate[n].pValue = (caddr_t)public_value;
913 pubTemplate[n].ulValueLen = sizeof (public_value);
914 pub_out_attr_count++;
916 rv = process_object_attributes(pubTemplate,
917 pub_attr_count - pub_out_attr_count,
918 &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
919 if (rv != CKR_OK) {
920 goto failed_exit;
922 obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
924 rv = process_object_attributes(
925 &pubTemplate[pub_attr_count - pub_out_attr_count],
926 pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
927 &is_token_obj1);
928 if (rv != CKR_OK) {
929 goto failed_exit;
931 obj_nkp.nkp_out_public_count = pub_out_attr_count;
934 * Cannot create a token object with a READ-ONLY
935 * session.
937 if (is_token_obj1 && session_p->ses_RO) {
938 rv = CKR_SESSION_READ_ONLY;
939 goto failed_exit;
943 * CKA_BASE, CKA_PRIME, and CKA_VALUE must not appear
944 * in private template.
946 if (attribute_in_template(CKA_BASE, pPrivateKeyTemplate,
947 ulPrivateKeyAttributeCount) ||
948 attribute_in_template(CKA_PRIME, pPrivateKeyTemplate,
949 ulPrivateKeyAttributeCount) ||
950 attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
951 ulPrivateKeyAttributeCount)) {
952 rv = CKR_TEMPLATE_INCONSISTENT;
953 goto failed_exit;
956 if (attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
957 ulPrivateKeyAttributeCount)) {
958 rv = CKR_TEMPLATE_INCONSISTENT;
959 goto failed_exit;
961 has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
962 ulPrivateKeyAttributeCount);
963 has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
964 ulPrivateKeyAttributeCount);
966 pri_attr_count = ulPrivateKeyAttributeCount + 1;
967 if (!has_class)
968 pri_attr_count++;
969 if (!has_key_type)
970 pri_attr_count++;
972 /* allocate space for CKA_BASE and CKA_PRIME */
973 priTemplate = grow_template(pPrivateKeyTemplate,
974 ulPrivateKeyAttributeCount, pri_attr_count + 2);
975 if (priTemplate == NULL) {
976 rv = CKR_HOST_MEMORY;
977 goto failed_exit;
979 n = ulPrivateKeyAttributeCount;
980 if (!has_class) {
981 priTemplate[n].type = CKA_CLASS;
982 priTemplate[n].pValue = (caddr_t)&pri_class;
983 priTemplate[n].ulValueLen = sizeof (pri_class);
984 n++;
986 if (!has_key_type) {
987 priTemplate[n].type = CKA_KEY_TYPE;
988 key_type = CKK_DH;
989 priTemplate[n].pValue = (caddr_t)&key_type;
990 priTemplate[n].ulValueLen = sizeof (key_type);
991 n++;
993 priTemplate[n].type = CKA_VALUE;
994 priTemplate[n].pValue = (caddr_t)private_value;
995 priTemplate[n].ulValueLen = sizeof (private_value);
996 pri_out_attr_count++;
998 rv = process_object_attributes(priTemplate,
999 pri_attr_count - pri_out_attr_count,
1000 &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1001 if (rv != CKR_OK) {
1002 goto failed_exit;
1004 obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1006 rv = process_object_attributes(
1007 &priTemplate[pri_attr_count - pri_out_attr_count],
1008 pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1009 &is_token_obj2);
1010 if (rv != CKR_OK) {
1011 goto failed_exit;
1013 obj_nkp.nkp_out_private_count = pri_out_attr_count;
1016 * The public key and the private key need to contain the same
1017 * attribute values for CKA_TOKEN.
1019 if (is_token_obj1 != is_token_obj2) {
1020 rv = CKR_ATTRIBUTE_VALUE_INVALID;
1021 goto failed_exit;
1024 /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1025 obj_nkp.nkp_session = session_p-> k_session;
1026 obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1027 obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1028 obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1030 while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1031 &obj_nkp)) < 0) {
1032 if (errno != EINTR)
1033 break;
1035 if (r < 0) {
1036 rv = CKR_FUNCTION_FAILED;
1037 } else {
1038 rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1040 free_attributes(obj_nkp.nkp_in_public_attributes,
1041 &obj_nkp.nkp_in_public_count);
1042 free_attributes(obj_nkp.nkp_in_private_attributes,
1043 &obj_nkp.nkp_in_private_count);
1045 if (rv != CKR_OK) {
1046 goto failed_exit;
1049 rv = get_object_attributes(
1050 &pubTemplate[pub_attr_count - pub_out_attr_count],
1051 pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1052 if (rv == CRYPTO_SUCCESS) {
1053 rv = get_object_attributes(
1054 &priTemplate[pri_attr_count - pri_out_attr_count],
1055 pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1057 free_attributes(obj_nkp.nkp_out_public_attributes,
1058 &obj_nkp.nkp_out_public_count);
1059 free_attributes(obj_nkp.nkp_out_private_attributes,
1060 &obj_nkp.nkp_out_private_count);
1062 if (rv != CRYPTO_SUCCESS) {
1063 goto failed_exit;
1066 rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1067 session_p, KERNEL_GEN_KEY);
1068 if (rv != CRYPTO_SUCCESS) {
1069 goto failed_exit;
1073 * Copy CKA_BASE and CKA_PRIME from the public template
1074 * to the private template.
1076 rv = copy_attribute(CKA_BASE, pubTemplate, pub_attr_count,
1077 &priTemplate[pri_attr_count]);
1078 if (rv != CRYPTO_SUCCESS) {
1079 goto failed_exit;
1081 rv = copy_attribute(CKA_PRIME, pubTemplate, pub_attr_count,
1082 &priTemplate[pri_attr_count + 1]);
1083 if (rv != CRYPTO_SUCCESS) {
1084 (void) free(priTemplate[pri_attr_count].pValue);
1085 goto failed_exit;
1088 /* +2 to account for CKA_BASE and CKA_PRIME */
1089 rv = kernel_build_object(priTemplate, pri_attr_count + 2,
1090 new_pri_objp, session_p, KERNEL_GEN_KEY);
1091 (void) free(priTemplate[pri_attr_count].pValue);
1092 (void) free(priTemplate[pri_attr_count + 1].pValue);
1093 if (rv != CRYPTO_SUCCESS) {
1094 goto failed_exit;
1096 (void) free(pubTemplate);
1097 (void) free(priTemplate);
1099 new_pub_objp->is_lib_obj = B_TRUE;
1100 new_pri_objp->is_lib_obj = B_TRUE;
1101 new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1102 new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1103 (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1104 new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1105 (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1106 new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1107 return (CKR_OK);
1109 failed_exit:
1110 free_attributes(obj_nkp.nkp_in_public_attributes,
1111 &obj_nkp.nkp_in_public_count);
1112 free_attributes(obj_nkp.nkp_out_public_attributes,
1113 &obj_nkp.nkp_out_public_count);
1114 free_attributes(obj_nkp.nkp_in_private_attributes,
1115 &obj_nkp.nkp_in_private_count);
1116 free_attributes(obj_nkp.nkp_out_private_attributes,
1117 &obj_nkp.nkp_out_private_count);
1118 if (pubTemplate != NULL) {
1119 (void) free(pubTemplate);
1121 if (priTemplate != NULL) {
1122 (void) free(priTemplate);
1124 return (rv);
1127 CK_RV
1128 key_gen_ec_by_value(CK_MECHANISM_PTR pMechanism,
1129 CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1130 CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1131 kernel_session_t *session_p, crypto_mech_type_t k_mech_type,
1132 kernel_object_t *new_pub_objp, kernel_object_t *new_pri_objp)
1134 crypto_nostore_generate_key_pair_t obj_nkp;
1135 CK_ATTRIBUTE_PTR pubTemplate = NULL;
1136 CK_ATTRIBUTE_PTR priTemplate = NULL;
1137 CK_RV rv = CKR_OK;
1138 CK_BBOOL is_token_obj1 = FALSE;
1139 CK_BBOOL is_token_obj2 = FALSE;
1140 uint_t pub_attr_count, pri_attr_count;
1141 uint_t pub_out_attr_count = 0, pri_out_attr_count = 0;
1142 char value[EC_MAX_VALUE_LEN];
1143 char point[EC_MAX_POINT_LEN];
1144 CK_ULONG pub_class = CKO_PUBLIC_KEY;
1145 CK_ULONG pri_class = CKO_PRIVATE_KEY;
1146 CK_ULONG key_type;
1147 boolean_t has_class, has_key_type;
1148 int n, r;
1150 obj_nkp.nkp_in_public_count = 0;
1151 obj_nkp.nkp_out_public_count = 0;
1152 obj_nkp.nkp_in_private_count = 0;
1153 obj_nkp.nkp_out_private_count = 0;
1156 * Add CKA_EC_POINT to the public template.
1157 * This is the generated value Q. This attribute
1158 * must not be in the template.
1160 if (attribute_in_template(CKA_EC_POINT, pPublicKeyTemplate,
1161 ulPublicKeyAttributeCount)) {
1162 rv = CKR_TEMPLATE_INCONSISTENT;
1163 goto failed_exit;
1165 has_class = attribute_in_template(CKA_CLASS, pPublicKeyTemplate,
1166 ulPublicKeyAttributeCount);
1167 has_key_type = attribute_in_template(CKA_KEY_TYPE, pPublicKeyTemplate,
1168 ulPublicKeyAttributeCount);
1170 pub_attr_count = ulPublicKeyAttributeCount + 1;
1171 if (!has_class)
1172 pub_attr_count++;
1173 if (!has_key_type)
1174 pub_attr_count++;
1175 pubTemplate = grow_template(pPublicKeyTemplate,
1176 ulPublicKeyAttributeCount, pub_attr_count);
1177 if (pubTemplate == NULL) {
1178 rv = CKR_HOST_MEMORY;
1179 goto failed_exit;
1182 n = ulPublicKeyAttributeCount;
1183 if (!has_class) {
1184 pubTemplate[n].type = CKA_CLASS;
1185 pubTemplate[n].pValue = (caddr_t)&pub_class;
1186 pubTemplate[n].ulValueLen = sizeof (pub_class);
1187 n++;
1189 if (!has_key_type) {
1190 pubTemplate[n].type = CKA_KEY_TYPE;
1191 key_type = CKK_EC;
1192 pubTemplate[n].pValue = (caddr_t)&key_type;
1193 pubTemplate[n].ulValueLen = sizeof (key_type);
1194 n++;
1196 pubTemplate[n].type = CKA_EC_POINT;
1197 pubTemplate[n].pValue = (caddr_t)point;
1198 pubTemplate[n].ulValueLen = sizeof (point);
1199 pub_out_attr_count++;
1201 rv = process_object_attributes(pubTemplate,
1202 pub_attr_count - pub_out_attr_count,
1203 &obj_nkp.nkp_in_public_attributes, &is_token_obj1);
1204 if (rv != CKR_OK) {
1205 goto failed_exit;
1207 obj_nkp.nkp_in_public_count = pub_attr_count - pub_out_attr_count;
1209 rv = process_object_attributes(
1210 &pubTemplate[pub_attr_count - pub_out_attr_count],
1211 pub_out_attr_count, &obj_nkp.nkp_out_public_attributes,
1212 &is_token_obj1);
1213 if (rv != CKR_OK) {
1214 goto failed_exit;
1216 obj_nkp.nkp_out_public_count = pub_out_attr_count;
1219 * Cannot create a token object with a READ-ONLY
1220 * session.
1222 if (is_token_obj1 && session_p->ses_RO) {
1223 rv = CKR_SESSION_READ_ONLY;
1224 goto failed_exit;
1228 * CKA_EC_PARAMS and CKA_VALUE must not appear in
1229 * private template.
1231 if (attribute_in_template(CKA_EC_PARAMS, pPrivateKeyTemplate,
1232 ulPrivateKeyAttributeCount) ||
1233 attribute_in_template(CKA_VALUE, pPrivateKeyTemplate,
1234 ulPrivateKeyAttributeCount)) {
1235 rv = CKR_TEMPLATE_INCONSISTENT;
1236 goto failed_exit;
1238 has_class = attribute_in_template(CKA_CLASS, pPrivateKeyTemplate,
1239 ulPrivateKeyAttributeCount);
1240 has_key_type = attribute_in_template(CKA_KEY_TYPE, pPrivateKeyTemplate,
1241 ulPrivateKeyAttributeCount);
1243 pri_attr_count = ulPrivateKeyAttributeCount + 1;
1244 if (!has_class)
1245 pri_attr_count++;
1246 if (!has_key_type)
1247 pri_attr_count++;
1249 /* allocate space for CKA_EC_PARAMS */
1250 priTemplate = grow_template(pPrivateKeyTemplate,
1251 ulPrivateKeyAttributeCount, pri_attr_count + 1);
1252 if (priTemplate == NULL) {
1253 rv = CKR_HOST_MEMORY;
1254 goto failed_exit;
1256 n = ulPrivateKeyAttributeCount;
1257 if (!has_class) {
1258 priTemplate[n].type = CKA_CLASS;
1259 priTemplate[n].pValue = (caddr_t)&pri_class;
1260 priTemplate[n].ulValueLen = sizeof (pri_class);
1261 n++;
1263 if (!has_key_type) {
1264 priTemplate[n].type = CKA_KEY_TYPE;
1265 key_type = CKK_EC;
1266 priTemplate[n].pValue = (caddr_t)&key_type;
1267 priTemplate[n].ulValueLen = sizeof (key_type);
1268 n++;
1270 priTemplate[n].type = CKA_VALUE;
1271 priTemplate[n].pValue = (caddr_t)value;
1272 priTemplate[n].ulValueLen = sizeof (value);
1273 pri_out_attr_count++;
1275 rv = process_object_attributes(priTemplate,
1276 pri_attr_count - pri_out_attr_count,
1277 &obj_nkp.nkp_in_private_attributes, &is_token_obj2);
1278 if (rv != CKR_OK) {
1279 goto failed_exit;
1281 obj_nkp.nkp_in_private_count = pri_attr_count - pri_out_attr_count;
1283 rv = process_object_attributes(
1284 &priTemplate[pri_attr_count - pri_out_attr_count],
1285 pri_out_attr_count, &obj_nkp.nkp_out_private_attributes,
1286 &is_token_obj2);
1287 if (rv != CKR_OK) {
1288 goto failed_exit;
1290 obj_nkp.nkp_out_private_count = pri_out_attr_count;
1293 * The public key and the private key need to contain the same
1294 * attribute values for CKA_TOKEN.
1296 if (is_token_obj1 != is_token_obj2) {
1297 rv = CKR_ATTRIBUTE_VALUE_INVALID;
1298 goto failed_exit;
1301 /* Call the CRYPTO_NOSTORE_GENERATE_KEY_PAIR ioctl. */
1302 obj_nkp.nkp_session = session_p-> k_session;
1303 obj_nkp.nkp_mechanism.cm_type = k_mech_type;
1304 obj_nkp.nkp_mechanism.cm_param = pMechanism->pParameter;
1305 obj_nkp.nkp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1307 while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_GENERATE_KEY_PAIR,
1308 &obj_nkp)) < 0) {
1309 if (errno != EINTR)
1310 break;
1312 if (r < 0) {
1313 rv = CKR_FUNCTION_FAILED;
1314 } else {
1315 rv = crypto2pkcs11_error_number(obj_nkp.nkp_return_value);
1317 free_attributes(obj_nkp.nkp_in_public_attributes,
1318 &obj_nkp.nkp_in_public_count);
1319 free_attributes(obj_nkp.nkp_in_private_attributes,
1320 &obj_nkp.nkp_in_private_count);
1322 if (rv != CKR_OK) {
1323 goto failed_exit;
1326 rv = get_object_attributes(
1327 &pubTemplate[pub_attr_count - pub_out_attr_count],
1328 pub_out_attr_count, obj_nkp.nkp_out_public_attributes);
1329 if (rv == CRYPTO_SUCCESS) {
1330 rv = get_object_attributes(
1331 &priTemplate[pri_attr_count - pri_out_attr_count],
1332 pri_out_attr_count, obj_nkp.nkp_out_private_attributes);
1334 free_attributes(obj_nkp.nkp_out_public_attributes,
1335 &obj_nkp.nkp_out_public_count);
1336 free_attributes(obj_nkp.nkp_out_private_attributes,
1337 &obj_nkp.nkp_out_private_count);
1338 if (rv != CRYPTO_SUCCESS) {
1339 goto failed_exit;
1342 rv = kernel_build_object(pubTemplate, pub_attr_count, new_pub_objp,
1343 session_p, KERNEL_GEN_KEY);
1344 if (rv != CRYPTO_SUCCESS) {
1345 goto failed_exit;
1349 * Copy CKA_EC_PARAMS from the public template to the
1350 * private template.
1352 rv = copy_attribute(CKA_EC_PARAMS, pubTemplate, pub_attr_count,
1353 &priTemplate[pri_attr_count]);
1354 if (rv != CRYPTO_SUCCESS) {
1355 goto failed_exit;
1358 /* +1 to account for CKA_EC_PARAMS */
1359 rv = kernel_build_object(priTemplate, pri_attr_count + 1,
1360 new_pri_objp, session_p, KERNEL_GEN_KEY);
1361 (void) free(priTemplate[pri_attr_count].pValue);
1362 if (rv != CRYPTO_SUCCESS) {
1363 goto failed_exit;
1365 (void) free(pubTemplate);
1366 (void) free(priTemplate);
1368 new_pub_objp->is_lib_obj = B_TRUE;
1369 new_pri_objp->is_lib_obj = B_TRUE;
1370 new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1371 new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1372 (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1373 new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1374 (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1375 new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1376 return (CKR_OK);
1378 failed_exit:
1379 free_attributes(obj_nkp.nkp_in_public_attributes,
1380 &obj_nkp.nkp_in_public_count);
1381 free_attributes(obj_nkp.nkp_out_public_attributes,
1382 &obj_nkp.nkp_out_public_count);
1383 free_attributes(obj_nkp.nkp_in_private_attributes,
1384 &obj_nkp.nkp_in_private_count);
1385 free_attributes(obj_nkp.nkp_out_private_attributes,
1386 &obj_nkp.nkp_out_private_count);
1387 if (pubTemplate != NULL) {
1388 (void) free(pubTemplate);
1390 if (priTemplate != NULL) {
1391 (void) free(priTemplate);
1393 return (rv);
1396 CK_RV
1397 C_GenerateKeyPair(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1398 CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
1399 CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
1400 CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
1402 CK_RV rv = CKR_OK;
1403 kernel_session_t *session_p;
1404 kernel_object_t *new_pub_objp = NULL;
1405 kernel_object_t *new_pri_objp = NULL;
1406 kernel_slot_t *pslot;
1407 boolean_t ses_lock_held = B_FALSE;
1408 CK_BBOOL is_pri_obj1;
1409 CK_BBOOL is_pri_obj2;
1410 CK_BBOOL is_token_obj1 = FALSE;
1411 CK_BBOOL is_token_obj2 = FALSE;
1412 crypto_mech_type_t k_mech_type;
1413 int r;
1414 CK_RV (*func)(CK_MECHANISM_PTR, CK_ATTRIBUTE_PTR, CK_ULONG,
1415 CK_ATTRIBUTE_PTR, CK_ULONG, kernel_session_t *, crypto_mech_type_t,
1416 kernel_object_t *, kernel_object_t *);
1418 if (!kernel_initialized)
1419 return (CKR_CRYPTOKI_NOT_INITIALIZED);
1421 /* Obtain the session pointer. */
1422 rv = handle2session(hSession, &session_p);
1423 if (rv != CKR_OK)
1424 return (rv);
1426 if ((pMechanism == NULL) || (phPublicKey == NULL) ||
1427 (phPrivateKey == NULL)) {
1428 rv = CKR_ARGUMENTS_BAD;
1429 goto failed_exit;
1432 if ((pPublicKeyTemplate == NULL) && (ulPublicKeyAttributeCount != 0)) {
1433 rv = CKR_ARGUMENTS_BAD;
1434 goto failed_exit;
1437 if ((pPrivateKeyTemplate == NULL) &&
1438 (ulPrivateKeyAttributeCount != 0)) {
1439 rv = CKR_ARGUMENTS_BAD;
1440 goto failed_exit;
1443 /* Get the kernel's internal mechanism number. */
1444 rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1445 if (rv != CKR_OK) {
1446 goto failed_exit;
1449 /* Create an object wrapper for the public key */
1450 new_pub_objp = calloc(1, sizeof (kernel_object_t));
1451 if (new_pub_objp == NULL) {
1452 rv = CKR_HOST_MEMORY;
1453 goto failed_exit;
1456 /* Create an object wrapper for the private key. */
1457 new_pri_objp = calloc(1, sizeof (kernel_object_t));
1458 if (new_pri_objp == NULL) {
1459 rv = CKR_HOST_MEMORY;
1460 goto failed_exit;
1464 * Special Case: if token does not support object creation,
1465 * but does support key generation by value, then create a session
1466 * object and initialize with values returned by token.
1468 pslot = slot_table[session_p->ses_slotid];
1469 if (!pslot->sl_func_list.fl_object_create) {
1470 switch (pMechanism->mechanism) {
1471 case CKM_RSA_PKCS_KEY_PAIR_GEN:
1472 func = key_gen_rsa_by_value;
1473 break;
1475 case CKM_DH_PKCS_KEY_PAIR_GEN:
1476 func = key_gen_dh_by_value;
1477 break;
1479 case CKM_EC_KEY_PAIR_GEN:
1480 func = key_gen_ec_by_value;
1481 break;
1483 default:
1484 rv = CKR_MECHANISM_INVALID;
1485 goto failed_exit;
1487 rv = (*func)(pMechanism, pPublicKeyTemplate,
1488 ulPublicKeyAttributeCount, pPrivateKeyTemplate,
1489 ulPrivateKeyAttributeCount, session_p, k_mech_type,
1490 new_pub_objp, new_pri_objp);
1491 if (rv != CKR_OK)
1492 goto failed_exit;
1493 } else {
1494 crypto_object_generate_key_pair_t obj_kp;
1496 /* Process the public key attributes. */
1497 rv = process_object_attributes(pPublicKeyTemplate,
1498 ulPublicKeyAttributeCount, &obj_kp.kp_public_attributes,
1499 &is_token_obj1);
1500 if (rv != CKR_OK) {
1501 goto failed_exit;
1504 /* Cannot create a token object with a READ-ONLY session. */
1505 if (is_token_obj1 && session_p->ses_RO) {
1506 free_object_attributes(obj_kp.kp_public_attributes,
1507 ulPublicKeyAttributeCount);
1508 rv = CKR_SESSION_READ_ONLY;
1509 goto failed_exit;
1512 /* Process the private key attributes. */
1513 rv = process_object_attributes(pPrivateKeyTemplate,
1514 ulPrivateKeyAttributeCount, &obj_kp.kp_private_attributes,
1515 &is_token_obj2);
1516 if (rv != CKR_OK) {
1517 free_object_attributes(obj_kp.kp_public_attributes,
1518 ulPublicKeyAttributeCount);
1519 goto failed_exit;
1523 * The public key and the private key need to contain the same
1524 * attribute values for CKA_TOKEN.
1526 if (is_token_obj1 != is_token_obj2) {
1527 free_object_attributes(obj_kp.kp_public_attributes,
1528 ulPublicKeyAttributeCount);
1529 free_object_attributes(obj_kp.kp_private_attributes,
1530 ulPrivateKeyAttributeCount);
1531 rv = CKR_ATTRIBUTE_VALUE_INVALID;
1532 goto failed_exit;
1535 /* Call the CRYPTO_GENERATE_KEY_PAIR ioctl. */
1536 obj_kp.kp_session = session_p-> k_session;
1537 obj_kp.kp_mechanism.cm_type = k_mech_type;
1538 obj_kp.kp_mechanism.cm_param = pMechanism->pParameter;
1539 obj_kp.kp_mechanism.cm_param_len = pMechanism->ulParameterLen;
1540 obj_kp.kp_public_count = ulPublicKeyAttributeCount;
1541 obj_kp.kp_private_count = ulPrivateKeyAttributeCount;
1543 while ((r = ioctl(kernel_fd, CRYPTO_GENERATE_KEY_PAIR,
1544 &obj_kp)) < 0) {
1545 if (errno != EINTR)
1546 break;
1548 if (r < 0) {
1549 rv = CKR_FUNCTION_FAILED;
1550 } else {
1551 rv = crypto2pkcs11_error_number(obj_kp.kp_return_value);
1553 free_object_attributes(obj_kp.kp_public_attributes,
1554 ulPublicKeyAttributeCount);
1555 free_object_attributes(obj_kp.kp_private_attributes,
1556 ulPrivateKeyAttributeCount);
1558 if (rv != CKR_OK)
1559 goto failed_exit;
1561 /* Get the CKA_PRIVATE value for the key pair. */
1562 rv = get_cka_private_value(session_p, obj_kp.kp_public_handle,
1563 &is_pri_obj1);
1564 if (rv != CKR_OK) {
1565 goto failed_exit;
1568 rv = get_cka_private_value(session_p, obj_kp.kp_private_handle,
1569 &is_pri_obj2);
1570 if (rv != CKR_OK) {
1571 goto failed_exit;
1575 * Store the kernel public key handle into the public key
1576 * object and finish the public key object initialization.
1578 new_pub_objp->is_lib_obj = B_FALSE;
1579 new_pub_objp->k_handle = obj_kp.kp_public_handle;
1580 new_pub_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1581 new_pub_objp->extra_attrlistp = NULL;
1583 if (is_pri_obj1)
1584 new_pub_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1585 else
1586 new_pub_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1588 if (is_token_obj1)
1589 new_pub_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1590 else
1591 new_pub_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1593 (void) pthread_mutex_init(&new_pub_objp->object_mutex, NULL);
1594 new_pub_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1597 * Store the kernel private key handle into the private key
1598 * object and finish the private key object initialization.
1600 new_pri_objp->is_lib_obj = B_FALSE;
1601 new_pri_objp->k_handle = obj_kp.kp_private_handle;
1602 new_pri_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1603 new_pri_objp->extra_attrlistp = NULL;
1605 if (is_pri_obj2)
1606 new_pri_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1607 else
1608 new_pri_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1610 if (is_token_obj2)
1611 new_pri_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1612 else
1613 new_pri_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1616 (void) pthread_mutex_init(&new_pri_objp->object_mutex, NULL);
1617 new_pri_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1620 * Add the new pub/pri objects to the slot's token list if they are
1621 * token objects. Otherwise, add them to the session's object list.
1623 if (is_token_obj1) { /* is_token_obj1 == is_token_obj2 */
1624 pslot = slot_table[session_p->ses_slotid];
1625 kernel_add_token_object_to_slot(new_pub_objp, pslot);
1626 kernel_add_token_object_to_slot(new_pri_objp, pslot);
1627 } else {
1628 kernel_add_object_to_session(new_pub_objp, session_p);
1629 kernel_add_object_to_session(new_pri_objp, session_p);
1632 *phPublicKey = (CK_OBJECT_HANDLE)new_pub_objp;
1633 *phPrivateKey = (CK_OBJECT_HANDLE)new_pri_objp;
1634 REFRELE(session_p, ses_lock_held);
1635 return (rv);
1637 failed_exit:
1638 if (new_pub_objp != NULL) {
1639 (void) free(new_pub_objp);
1641 if (new_pri_objp != NULL) {
1642 (void) free(new_pri_objp);
1644 REFRELE(session_p, ses_lock_held);
1645 return (rv);
1649 CK_RV
1650 C_WrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1651 CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
1652 CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
1654 CK_RV rv = CKR_OK;
1655 kernel_session_t *session_p;
1656 boolean_t ses_lock_held = B_FALSE;
1657 kernel_object_t *wrappingkey_p;
1658 kernel_object_t *key_p;
1659 crypto_mech_type_t k_mech_type;
1660 crypto_object_wrap_key_t obj_wrapkey;
1661 int r;
1663 if (!kernel_initialized)
1664 return (CKR_CRYPTOKI_NOT_INITIALIZED);
1666 if (pulWrappedKeyLen == NULL || pMechanism == NULL) {
1667 return (CKR_ARGUMENTS_BAD);
1671 * Obtain the session pointer. Also, increment the session
1672 * reference count.
1674 rv = handle2session(hSession, &session_p);
1675 if (rv != CKR_OK)
1676 return (rv);
1678 /* Get the kernel's internal mechanism number. */
1679 rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1680 if (rv != CKR_OK) {
1681 REFRELE(session_p, ses_lock_held);
1682 return (rv);
1685 /* Obtain the wrapping key object pointer. */
1686 HANDLE2OBJECT(hWrappingKey, wrappingkey_p, rv);
1687 if (rv != CKR_OK) {
1688 REFRELE(session_p, ses_lock_held);
1689 return (rv);
1692 /* Obtain the to_be_wrapped key object pointer. */
1693 HANDLE2OBJECT(hKey, key_p, rv);
1694 if (rv != CKR_OK) {
1695 OBJ_REFRELE(wrappingkey_p);
1696 REFRELE(session_p, ses_lock_held);
1697 return (rv);
1700 /* Make the CRYPTO_OBJECT_WRAP_KEY ioctl call. */
1701 obj_wrapkey.wk_session = session_p->k_session;
1702 obj_wrapkey.wk_mechanism.cm_type = k_mech_type;
1703 obj_wrapkey.wk_mechanism.cm_param = pMechanism->pParameter;
1704 obj_wrapkey.wk_mechanism.cm_param_len = pMechanism->ulParameterLen;
1705 obj_wrapkey.wk_wrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
1706 obj_wrapkey.wk_wrapping_key.ck_obj_id = wrappingkey_p->k_handle;
1707 obj_wrapkey.wk_object_handle = key_p->k_handle;
1708 obj_wrapkey.wk_wrapped_key_len = *pulWrappedKeyLen;
1709 obj_wrapkey.wk_wrapped_key = (char *)pWrappedKey;
1711 while ((r = ioctl(kernel_fd, CRYPTO_WRAP_KEY, &obj_wrapkey)) < 0) {
1712 if (errno != EINTR)
1713 break;
1715 if (r < 0) {
1716 rv = CKR_FUNCTION_FAILED;
1717 } else {
1718 rv = crypto2pkcs11_error_number(obj_wrapkey.wk_return_value);
1722 * Besides rv == CKR_OK, we will set the value of pulWrappedKeyLen
1723 * when the applciation-supplied wrapped key buffer is too small.
1724 * The situation that the application only asks for the length of
1725 * the wrapped key is covered in rv == CKR_OK.
1727 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
1728 *pulWrappedKeyLen = obj_wrapkey.wk_wrapped_key_len;
1731 OBJ_REFRELE(key_p);
1732 OBJ_REFRELE(wrappingkey_p);
1733 REFRELE(session_p, ses_lock_held);
1734 return (rv);
1738 CK_RV
1739 C_UnwrapKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
1740 CK_OBJECT_HANDLE hUnwrappingKey, CK_BYTE_PTR pWrappedKey,
1741 CK_ULONG ulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
1742 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
1744 CK_RV rv = CKR_OK;
1745 kernel_session_t *session_p;
1746 kernel_object_t *unwrappingkey_p;
1747 kernel_object_t *new_objp = NULL;
1748 kernel_slot_t *pslot;
1749 boolean_t ses_lock_held = B_FALSE;
1750 CK_BBOOL is_pri_obj;
1751 CK_BBOOL is_token_obj = FALSE;
1752 CK_MECHANISM_INFO info;
1753 uint32_t k_mi_flags;
1754 CK_BYTE *clear_key_val = NULL;
1755 CK_ULONG ulDataLen;
1756 CK_ATTRIBUTE_PTR newTemplate = NULL;
1757 crypto_mech_type_t k_mech_type;
1758 crypto_object_unwrap_key_t obj_unwrapkey;
1759 int r;
1761 if (!kernel_initialized)
1762 return (CKR_CRYPTOKI_NOT_INITIALIZED);
1764 if (pMechanism == NULL || pWrappedKey == NULL || phKey == NULL) {
1765 return (CKR_ARGUMENTS_BAD);
1768 if ((pTemplate == NULL) && (ulAttributeCount != 0)) {
1769 return (CKR_ARGUMENTS_BAD);
1772 /* Obtain the session pointer. */
1773 rv = handle2session(hSession, &session_p);
1774 if (rv != CKR_OK)
1775 return (rv);
1777 /* Obtain the wrapping key object pointer. */
1778 HANDLE2OBJECT(hUnwrappingKey, unwrappingkey_p, rv);
1779 if (rv != CKR_OK) {
1780 REFRELE(session_p, ses_lock_held);
1781 return (rv);
1785 * If the HW provider doesn't support C_UnwrapKey, we will try
1786 * to emulate it in the library.
1788 pslot = slot_table[session_p->ses_slotid];
1789 if ((!pslot->sl_func_list.fl_object_create) &&
1790 (!pslot->sl_func_list.fl_key_unwrap)) {
1791 rv = get_mechanism_info(pslot, pMechanism->mechanism, &info,
1792 &k_mi_flags);
1793 if (rv != CKR_OK) {
1794 goto failed_exit;
1798 * If the mechanism flag doesn't have CKF_UNWRAP, and it's
1799 * an unwrapping of a secret key object, then help this
1800 * out with a decryption followed by an object creation.
1802 if (!(k_mi_flags & CRYPTO_FG_UNWRAP) &&
1803 (k_mi_flags & CRYPTO_FG_DECRYPT) &&
1804 (is_secret_key_template(pTemplate, ulAttributeCount))) {
1806 /* First allocate space for the recovered key value */
1807 clear_key_val = malloc(ulWrappedKeyLen);
1808 if (clear_key_val == NULL) {
1809 rv = CKR_HOST_MEMORY;
1810 goto failed_exit;
1813 rv = kernel_decrypt_init(session_p, unwrappingkey_p,
1814 pMechanism);
1815 if (rv != CKR_OK) {
1816 goto failed_exit;
1819 ulDataLen = ulWrappedKeyLen;
1820 rv = kernel_decrypt(session_p, pWrappedKey,
1821 ulWrappedKeyLen, clear_key_val, &ulDataLen);
1822 if (rv != CKR_OK) {
1823 goto failed_exit;
1826 newTemplate = grow_template(pTemplate, ulAttributeCount,
1827 ulAttributeCount + 1);
1828 if (newTemplate == NULL) {
1829 rv = CKR_HOST_MEMORY;
1830 goto failed_exit;
1832 /* Now add the CKA_VALUE attribute to template */
1833 newTemplate[ulAttributeCount].type = CKA_VALUE;
1834 newTemplate[ulAttributeCount].pValue = clear_key_val;
1835 newTemplate[ulAttributeCount].ulValueLen = ulDataLen;
1837 /* Finally create the key, based on the new template */
1838 rv = kernel_add_object(newTemplate,
1839 ulAttributeCount + 1, phKey, session_p);
1840 (void) free(clear_key_val);
1841 (void) free(newTemplate);
1842 OBJ_REFRELE(unwrappingkey_p);
1843 REFRELE(session_p, ses_lock_held);
1844 return (rv);
1845 } else {
1846 rv = CKR_FUNCTION_FAILED;
1847 goto failed_exit;
1852 * If we come here, the HW provider must have registered the unwrapkey
1853 * entry. Therefore, the unwrap key will be performed in the HW
1854 * provider.
1856 rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
1857 if (rv != CKR_OK) {
1858 goto failed_exit;
1861 /* Create an object wrapper for the new key in the library first */
1862 new_objp = calloc(1, sizeof (kernel_object_t));
1863 if (new_objp == NULL) {
1864 rv = CKR_HOST_MEMORY;
1865 goto failed_exit;
1868 /* Process the attributes */
1869 rv = process_object_attributes(pTemplate, ulAttributeCount,
1870 &obj_unwrapkey.uk_attributes, &is_token_obj);
1871 if (rv != CKR_OK) {
1872 goto failed_exit;
1875 /* Cannot create a token object with a READ-ONLY session. */
1876 if (is_token_obj && session_p->ses_RO) {
1877 free_object_attributes(obj_unwrapkey.uk_attributes,
1878 ulAttributeCount);
1879 rv = CKR_SESSION_READ_ONLY;
1880 goto failed_exit;
1883 /* Make the CRYPTO_UNWRAP_KEY ioctl call. */
1884 obj_unwrapkey.uk_session = session_p->k_session;
1885 obj_unwrapkey.uk_mechanism.cm_type = k_mech_type;
1886 obj_unwrapkey.uk_mechanism.cm_param = pMechanism->pParameter;
1887 obj_unwrapkey.uk_mechanism.cm_param_len = pMechanism->ulParameterLen;
1888 obj_unwrapkey.uk_unwrapping_key.ck_format = CRYPTO_KEY_REFERENCE;
1889 obj_unwrapkey.uk_unwrapping_key.ck_obj_id = unwrappingkey_p->k_handle;
1890 obj_unwrapkey.uk_wrapped_key = (char *)pWrappedKey;
1891 obj_unwrapkey.uk_wrapped_key_len = ulWrappedKeyLen;
1892 obj_unwrapkey.uk_count = ulAttributeCount;
1894 while ((r = ioctl(kernel_fd, CRYPTO_UNWRAP_KEY, &obj_unwrapkey)) < 0) {
1895 if (errno != EINTR)
1896 break;
1898 if (r < 0) {
1899 rv = CKR_FUNCTION_FAILED;
1900 } else {
1901 rv = crypto2pkcs11_error_number(obj_unwrapkey.uk_return_value);
1904 free_object_attributes(obj_unwrapkey.uk_attributes, ulAttributeCount);
1905 if (rv != CKR_OK) {
1906 goto failed_exit;
1909 /* Get the CKA_PRIVATE value for the unwrapped key. */
1910 rv = get_cka_private_value(session_p, obj_unwrapkey.uk_object_handle,
1911 &is_pri_obj);
1912 if (rv != CKR_OK) {
1913 goto failed_exit;
1917 * Store the kernel object handle in the new key object wrapper and
1918 * initialize it.
1920 new_objp->k_handle = obj_unwrapkey.uk_object_handle;
1921 new_objp->is_lib_obj = B_FALSE;
1922 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
1923 new_objp->extra_attrlistp = NULL;
1925 if (is_pri_obj)
1926 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
1927 else
1928 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
1930 if (is_token_obj)
1931 new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
1932 else
1933 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
1935 (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
1936 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
1939 * Add the new object to the slot's token object list if it is a
1940 * a token object. Otherwise, add it to the session's object list.
1942 if (is_token_obj) {
1943 pslot = slot_table[session_p->ses_slotid];
1944 kernel_add_token_object_to_slot(new_objp, pslot);
1945 } else {
1946 kernel_add_object_to_session(new_objp, session_p);
1949 *phKey = (CK_OBJECT_HANDLE)new_objp;
1950 OBJ_REFRELE(unwrappingkey_p);
1951 REFRELE(session_p, ses_lock_held);
1952 return (rv);
1954 failed_exit:
1955 OBJ_REFRELE(unwrappingkey_p);
1956 if (new_objp != NULL)
1957 (void) free(new_objp);
1959 if (clear_key_val != NULL)
1960 (void) free(clear_key_val);
1962 if (newTemplate != NULL)
1963 (void) free(newTemplate);
1965 REFRELE(session_p, ses_lock_held);
1966 return (rv);
1970 * Get sufficient attributes from a base key to pass by value in a
1971 * crypto_key structure. Storage for attributes is allocated.
1972 * For EC public keys, it is CKA_EC_PARAMS and CKA_EC_POINT.
1973 * For EC private keys, it is CKA_EC_PARAMS and CKA_VALUE.
1975 static int
1976 get_base_key_attributes(kernel_object_t *base_key, crypto_key_t *key_by_value)
1978 CK_ATTRIBUTE tmp;
1979 crypto_object_attribute_t *attrs = NULL;
1980 biginteger_t *big;
1981 int i, count = 0, rv;
1983 switch (base_key->key_type) {
1984 case CKK_EC:
1985 count = 2;
1986 attrs = malloc(count * sizeof (crypto_object_attribute_t));
1987 if (attrs == NULL) {
1988 rv = CKR_HOST_MEMORY;
1989 goto out;
1991 bzero(attrs, count * sizeof (crypto_object_attribute_t));
1993 (void) pthread_mutex_lock(&base_key->object_mutex);
1995 if (!base_key->is_lib_obj) {
1996 rv = CRYPTO_ARGUMENTS_BAD;
1997 goto out;
2000 if (base_key->class != CKO_PUBLIC_KEY &&
2001 base_key->class != CKO_PRIVATE_KEY) {
2002 rv = CRYPTO_ARGUMENTS_BAD;
2003 goto out;
2007 * Both public and private EC keys should have
2008 * a CKA_EC_PARAMS attribute.
2010 tmp.type = CKA_EC_PARAMS;
2011 tmp.pValue = NULL;
2013 /* get size of attribute */
2014 rv = kernel_get_attribute(base_key, &tmp);
2015 if (rv != CKR_OK) {
2016 goto out;
2019 tmp.pValue = malloc(tmp.ulValueLen);
2020 if (tmp.pValue == NULL) {
2021 rv = CKR_HOST_MEMORY;
2022 goto out;
2024 rv = kernel_get_attribute(base_key, &tmp);
2025 if (rv != CKR_OK) {
2026 free(tmp.pValue);
2027 goto out;
2029 attrs[0].oa_type = tmp.type;
2030 attrs[0].oa_value = tmp.pValue;
2031 attrs[0].oa_value_len = tmp.ulValueLen;
2033 switch (base_key->class) {
2034 case CKO_PUBLIC_KEY:
2035 big = OBJ_PUB_EC_POINT(base_key);
2036 tmp.type = CKA_EC_POINT;
2037 break;
2039 case CKO_PRIVATE_KEY:
2040 big = OBJ_PRI_EC_VALUE(base_key);
2041 tmp.type = CKA_VALUE;
2042 break;
2044 default:
2045 rv = CKR_ATTRIBUTE_TYPE_INVALID;
2046 goto out;
2048 tmp.ulValueLen = big->big_value_len;
2049 tmp.pValue = malloc(tmp.ulValueLen);
2050 if (tmp.pValue == NULL) {
2051 rv = CKR_HOST_MEMORY;
2052 goto out;
2054 rv = kernel_get_attribute(base_key, &tmp);
2055 if (rv != CKR_OK) {
2056 free(tmp.pValue);
2057 goto out;
2059 attrs[1].oa_type = tmp.type;
2060 attrs[1].oa_value = tmp.pValue;
2061 attrs[1].oa_value_len = tmp.ulValueLen;
2062 key_by_value->ck_attrs = attrs;
2063 key_by_value->ck_count = 2;
2064 break;
2066 case CKK_DH:
2067 count = 3;
2068 attrs = malloc(count * sizeof (crypto_object_attribute_t));
2069 if (attrs == NULL) {
2070 rv = CKR_HOST_MEMORY;
2071 goto out;
2073 bzero(attrs, count * sizeof (crypto_object_attribute_t));
2075 (void) pthread_mutex_lock(&base_key->object_mutex);
2077 if (!base_key->is_lib_obj) {
2078 rv = CRYPTO_ARGUMENTS_BAD;
2079 goto out;
2082 if (base_key->class != CKO_PRIVATE_KEY) {
2083 rv = CRYPTO_ARGUMENTS_BAD;
2084 goto out;
2086 tmp.type = CKA_BASE;
2087 tmp.pValue = NULL;
2089 /* get size of attribute */
2090 rv = kernel_get_attribute(base_key, &tmp);
2091 if (rv != CKR_OK) {
2092 goto out;
2095 tmp.pValue = malloc(tmp.ulValueLen);
2096 if (tmp.pValue == NULL) {
2097 rv = CKR_HOST_MEMORY;
2098 goto out;
2100 rv = kernel_get_attribute(base_key, &tmp);
2101 if (rv != CKR_OK) {
2102 free(tmp.pValue);
2103 goto out;
2105 attrs[0].oa_type = tmp.type;
2106 attrs[0].oa_value = tmp.pValue;
2107 attrs[0].oa_value_len = tmp.ulValueLen;
2109 tmp.type = CKA_PRIME;
2110 tmp.pValue = NULL;
2112 /* get size of attribute */
2113 rv = kernel_get_attribute(base_key, &tmp);
2114 if (rv != CKR_OK) {
2115 goto out;
2118 tmp.pValue = malloc(tmp.ulValueLen);
2119 if (tmp.pValue == NULL) {
2120 rv = CKR_HOST_MEMORY;
2121 goto out;
2123 rv = kernel_get_attribute(base_key, &tmp);
2124 if (rv != CKR_OK) {
2125 free(tmp.pValue);
2126 goto out;
2128 attrs[1].oa_type = tmp.type;
2129 attrs[1].oa_value = tmp.pValue;
2130 attrs[1].oa_value_len = tmp.ulValueLen;
2132 big = OBJ_PRI_DH_VALUE(base_key);
2133 tmp.type = CKA_VALUE;
2135 tmp.ulValueLen = big->big_value_len;
2136 tmp.pValue = malloc(tmp.ulValueLen);
2137 if (tmp.pValue == NULL) {
2138 rv = CKR_HOST_MEMORY;
2139 goto out;
2141 rv = kernel_get_attribute(base_key, &tmp);
2142 if (rv != CKR_OK) {
2143 free(tmp.pValue);
2144 goto out;
2146 attrs[2].oa_type = tmp.type;
2147 attrs[2].oa_value = tmp.pValue;
2148 attrs[2].oa_value_len = tmp.ulValueLen;
2149 key_by_value->ck_attrs = attrs;
2150 key_by_value->ck_count = 3;
2151 break;
2153 default:
2154 rv = CKR_ATTRIBUTE_TYPE_INVALID;
2155 goto out;
2157 (void) pthread_mutex_unlock(&base_key->object_mutex);
2158 return (CKR_OK);
2160 out:
2161 (void) pthread_mutex_unlock(&base_key->object_mutex);
2162 if (attrs != NULL) {
2163 for (i = 0; i < count; i++) {
2164 if (attrs[i].oa_value != NULL)
2165 free(attrs[i].oa_value);
2167 free(attrs);
2169 return (rv);
2172 CK_RV
2173 derive_key_by_value(CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate,
2174 CK_ULONG ulAttributeCount, kernel_session_t *session_p,
2175 crypto_mech_type_t k_mech_type, kernel_object_t *basekey_p,
2176 kernel_object_t *new_objp)
2178 crypto_nostore_derive_key_t obj_ndk;
2179 char *key_buf = NULL;
2180 CK_ATTRIBUTE_PTR newTemplate = NULL;
2181 CK_BBOOL is_token_obj = FALSE;
2182 CK_RV rv = CKR_OK;
2183 CK_ULONG secret_class = CKO_SECRET_KEY;
2184 ulong_t key_len = 0;
2185 uint_t attr_count = 0;
2186 boolean_t removed;
2187 boolean_t has_class;
2188 int r, n;
2190 obj_ndk.ndk_in_count = 0;
2191 obj_ndk.ndk_out_count = 0;
2192 obj_ndk.ndk_base_key.ck_count = 0;
2194 rv = get_key_len_from_template(pMechanism, pTemplate, ulAttributeCount,
2195 basekey_p, &key_len);
2196 if (rv != CKR_OK) {
2197 goto failed_exit;
2200 if ((key_buf = malloc(key_len)) == NULL) {
2201 rv = CKR_HOST_MEMORY;
2202 goto failed_exit;
2205 has_class = attribute_in_template(CKA_CLASS, pTemplate,
2206 ulAttributeCount);
2208 attr_count = ulAttributeCount + 1;
2209 if (!has_class)
2210 attr_count++;
2212 newTemplate = grow_template(pTemplate, ulAttributeCount, attr_count);
2213 if (newTemplate == NULL) {
2214 rv = CKR_HOST_MEMORY;
2215 goto failed_exit;
2218 n = ulAttributeCount;
2219 if (!has_class) {
2220 newTemplate[n].type = CKA_CLASS;
2221 newTemplate[n].pValue = (caddr_t)&secret_class;
2222 newTemplate[n].ulValueLen = sizeof (secret_class);
2223 n++;
2226 /* Add CKA_VALUE to the template */
2227 newTemplate[n].type = CKA_VALUE;
2228 newTemplate[n].pValue = (caddr_t)key_buf;
2229 newTemplate[n].ulValueLen = key_len;
2231 rv = process_object_attributes(newTemplate, attr_count - 1,
2232 &obj_ndk.ndk_in_attributes, &is_token_obj);
2233 if (rv != CKR_OK) {
2234 goto failed_exit;
2236 obj_ndk.ndk_in_count = attr_count - 1;
2238 rv = process_object_attributes(&newTemplate[attr_count - 1],
2239 1, &obj_ndk.ndk_out_attributes, &is_token_obj);
2240 if (rv != CKR_OK) {
2241 goto failed_exit;
2243 obj_ndk.ndk_out_count = 1;
2245 /* Cannot create a token object with a READ-ONLY session. */
2246 if (is_token_obj && session_p->ses_RO) {
2247 rv = CKR_SESSION_READ_ONLY;
2248 goto failed_exit;
2251 obj_ndk.ndk_session = session_p->k_session;
2252 obj_ndk.ndk_mechanism.cm_type = k_mech_type;
2253 obj_ndk.ndk_mechanism.cm_param = pMechanism->pParameter;
2254 obj_ndk.ndk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2257 * Obtain the attributes of base key and pass them by value.
2259 rv = get_base_key_attributes(basekey_p, &obj_ndk.ndk_base_key);
2260 if (rv != CKR_OK) {
2261 goto failed_exit;
2264 obj_ndk.ndk_base_key.ck_format = CRYPTO_KEY_ATTR_LIST;
2266 while ((r = ioctl(kernel_fd, CRYPTO_NOSTORE_DERIVE_KEY,
2267 &obj_ndk)) < 0) {
2268 if (errno != EINTR)
2269 break;
2271 if (r < 0) {
2272 rv = CKR_FUNCTION_FAILED;
2273 } else {
2274 rv = crypto2pkcs11_error_number(obj_ndk.ndk_return_value);
2276 free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2277 free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2278 &obj_ndk.ndk_base_key.ck_count);
2279 if (rv != CKR_OK) {
2280 goto failed_exit;
2283 rv = get_object_attributes(&newTemplate[attr_count - 1],
2284 1, obj_ndk.ndk_out_attributes);
2285 free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2286 if (rv != CRYPTO_SUCCESS) {
2287 goto failed_exit;
2290 removed = remove_one_attribute(newTemplate, CKA_VALUE_LEN,
2291 attr_count, B_FALSE);
2293 rv = kernel_build_object(newTemplate, removed ? attr_count - 1 :
2294 attr_count, new_objp, session_p, KERNEL_GEN_KEY);
2295 if (rv != CRYPTO_SUCCESS) {
2296 goto failed_exit;
2299 free(key_buf);
2300 free(newTemplate);
2301 new_objp->is_lib_obj = B_TRUE;
2302 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2303 return (CKR_OK);
2305 failed_exit:
2306 if (key_buf != NULL)
2307 free(key_buf);
2308 if (newTemplate != NULL)
2309 free(newTemplate);
2310 free_attributes(obj_ndk.ndk_in_attributes, &obj_ndk.ndk_in_count);
2311 free_attributes(obj_ndk.ndk_out_attributes, &obj_ndk.ndk_out_count);
2312 free_attributes((caddr_t)obj_ndk.ndk_base_key.ck_attrs,
2313 &obj_ndk.ndk_base_key.ck_count);
2314 return (rv);
2317 CK_RV
2318 C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
2319 CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
2320 CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey)
2322 CK_RV rv = CKR_OK;
2323 kernel_session_t *session_p;
2324 kernel_object_t *basekey_p;
2325 kernel_object_t *new_objp;
2326 kernel_slot_t *pslot;
2327 boolean_t ses_lock_held = B_FALSE;
2328 CK_BBOOL is_pri_obj;
2329 CK_BBOOL is_token_obj = FALSE;
2330 crypto_mech_type_t k_mech_type;
2331 int r;
2333 if (!kernel_initialized)
2334 return (CKR_CRYPTOKI_NOT_INITIALIZED);
2336 /* Obtain the session pointer. */
2337 rv = handle2session(hSession, &session_p);
2338 if (rv != CKR_OK)
2339 return (rv);
2341 if (pMechanism == NULL) {
2342 REFRELE(session_p, ses_lock_held);
2343 return (CKR_ARGUMENTS_BAD);
2346 if ((pTemplate == NULL && ulAttributeCount != 0) ||
2347 (pTemplate != NULL && ulAttributeCount == 0)) {
2348 REFRELE(session_p, ses_lock_held);
2349 return (CKR_ARGUMENTS_BAD);
2352 /* Obtain the base key object pointer. */
2353 HANDLE2OBJECT(hBaseKey, basekey_p, rv);
2354 if (rv != CKR_OK) {
2355 REFRELE(session_p, ses_lock_held);
2356 return (rv);
2359 /* Get the kernel's internal mechanism number. */
2360 rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
2361 if (rv != CKR_OK) {
2362 goto failed_exit;
2365 /* Create an object wrapper in the library for the generated key. */
2366 new_objp = calloc(1, sizeof (kernel_object_t));
2367 if (new_objp == NULL) {
2368 rv = CKR_HOST_MEMORY;
2369 goto failed_exit;
2373 * Special Case: if token does not support object creation,
2374 * but does support key derivation by value, then create a session
2375 * object and initialize with values returned by token.
2377 pslot = slot_table[session_p->ses_slotid];
2378 if (!pslot->sl_func_list.fl_object_create) {
2379 rv = derive_key_by_value(pMechanism, pTemplate,
2380 ulAttributeCount, session_p, k_mech_type, basekey_p,
2381 new_objp);
2382 if (rv != CKR_OK)
2383 goto failed_exit;
2384 } else {
2385 crypto_derive_key_t obj_dk;
2387 rv = process_object_attributes(pTemplate, ulAttributeCount,
2388 &obj_dk.dk_attributes, &is_token_obj);
2389 if (rv != CKR_OK) {
2390 goto failed_exit;
2393 /* Cannot create a token object with a READ-ONLY session. */
2394 if (is_token_obj && session_p->ses_RO) {
2395 free_object_attributes(obj_dk.dk_attributes,
2396 ulAttributeCount);
2397 rv = CKR_SESSION_READ_ONLY;
2398 goto failed_exit;
2401 obj_dk.dk_session = session_p->k_session;
2402 obj_dk.dk_mechanism.cm_type = k_mech_type;
2403 obj_dk.dk_mechanism.cm_param = pMechanism->pParameter;
2404 obj_dk.dk_mechanism.cm_param_len = pMechanism->ulParameterLen;
2405 obj_dk.dk_base_key.ck_format = CRYPTO_KEY_REFERENCE;
2406 obj_dk.dk_base_key.ck_obj_id = basekey_p->k_handle;
2407 obj_dk.dk_count = ulAttributeCount;
2409 while ((r = ioctl(kernel_fd, CRYPTO_DERIVE_KEY, &obj_dk)) < 0) {
2410 if (errno != EINTR)
2411 break;
2413 if (r < 0) {
2414 rv = CKR_FUNCTION_FAILED;
2415 } else {
2416 rv = crypto2pkcs11_error_number(obj_dk.dk_return_value);
2419 free_object_attributes(obj_dk.dk_attributes, ulAttributeCount);
2420 if (rv != CKR_OK) {
2421 goto failed_exit;
2424 /* Get the CKA_PRIVATE value for the derived key. */
2425 rv = get_cka_private_value(session_p, obj_dk.dk_object_handle,
2426 &is_pri_obj);
2427 if (rv != CKR_OK) {
2428 goto failed_exit;
2432 * Store the kernel object handle into the new derived key
2433 * object and finish the object initialization.
2435 new_objp->is_lib_obj = B_FALSE;
2436 new_objp->k_handle = obj_dk.dk_object_handle;
2437 new_objp->session_handle = (CK_SESSION_HANDLE)session_p;
2438 new_objp->extra_attrlistp = NULL;
2440 if (is_pri_obj)
2441 new_objp->bool_attr_mask |= PRIVATE_BOOL_ON;
2442 else
2443 new_objp->bool_attr_mask &= ~PRIVATE_BOOL_ON;
2445 if (is_token_obj)
2446 new_objp->bool_attr_mask |= TOKEN_BOOL_ON;
2447 else
2448 new_objp->bool_attr_mask &= ~TOKEN_BOOL_ON;
2450 (void) pthread_mutex_init(&new_objp->object_mutex, NULL);
2451 new_objp->magic_marker = KERNELTOKEN_OBJECT_MAGIC;
2454 * Add the new derived object to the slot's token list if it is a
2455 * token object. Otherwise, add it to the session's object list.
2457 if (is_token_obj) {
2458 pslot = slot_table[session_p->ses_slotid];
2459 kernel_add_token_object_to_slot(new_objp, pslot);
2460 } else {
2461 kernel_add_object_to_session(new_objp, session_p);
2464 *phKey = (CK_OBJECT_HANDLE)new_objp;
2465 OBJ_REFRELE(basekey_p);
2466 REFRELE(session_p, ses_lock_held);
2467 return (rv);
2469 failed_exit:
2470 OBJ_REFRELE(basekey_p);
2471 if (new_objp != NULL) {
2472 (void) free(new_objp);
2475 REFRELE(session_p, ses_lock_held);
2476 return (rv);