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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 #include <sys/crypto/ioctl.h>
30 #include <security/cryptoki.h>
31 #include "kernelGlobal.h"
32 #include "kernelSession.h"
33 #include "kernelEmulate.h"
36 common_digest_init(CK_SESSION_HANDLE hSession
,
37 CK_MECHANISM_PTR pMechanism
, boolean_t is_external_caller
)
40 kernel_session_t
*session_p
;
41 boolean_t ses_lock_held
= B_FALSE
;
42 crypto_digest_init_t digest_init
;
43 crypto_mech_type_t k_mech_type
;
46 if (!kernel_initialized
)
47 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
49 if (pMechanism
== NULL
)
50 return (CKR_ARGUMENTS_BAD
);
53 * Get the kernel's internal mechanism number.
55 rv
= kernel_mech(pMechanism
->mechanism
, &k_mech_type
);
60 * Obtain the session pointer. Also, increment the session
63 rv
= handle2session(hSession
, &session_p
);
67 /* Acquire the session lock */
68 (void) pthread_mutex_lock(&session_p
->session_mutex
);
69 ses_lock_held
= B_TRUE
;
72 * This active flag will remain ON until application calls either
73 * C_Digest or C_DigestFinal to actually obtain the value of
76 session_p
->digest
.flags
|= CRYPTO_OPERATION_ACTIVE
;
78 if (SLOT_HAS_LIMITED_HASH(session_p
) && is_external_caller
) {
79 session_p
->digest
.mech
.mechanism
= pMechanism
->mechanism
;
80 session_p
->digest
.mech
.pParameter
= NULL
;
81 session_p
->digest
.mech
.ulParameterLen
= 0;
82 session_p
->digest
.flags
|= CRYPTO_EMULATE
;
83 rv
= emulate_buf_init(session_p
, EDIGEST_LENGTH
, OP_DIGEST
);
84 REFRELE(session_p
, ses_lock_held
);
88 digest_init
.di_session
= session_p
->k_session
;
89 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
90 ses_lock_held
= B_FALSE
;
91 digest_init
.di_mech
.cm_type
= k_mech_type
;
92 digest_init
.di_mech
.cm_param
= pMechanism
->pParameter
;
95 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call
96 * will have a clean input data.
98 if (pMechanism
->pParameter
!= NULL
)
99 digest_init
.di_mech
.cm_param_len
= pMechanism
->ulParameterLen
;
101 digest_init
.di_mech
.cm_param_len
= 0;
103 while ((r
= ioctl(kernel_fd
, CRYPTO_DIGEST_INIT
, &digest_init
)) < 0) {
108 rv
= CKR_FUNCTION_FAILED
;
110 rv
= crypto2pkcs11_error_number(digest_init
.di_return_value
);
114 (void) pthread_mutex_lock(&session_p
->session_mutex
);
115 ses_lock_held
= B_TRUE
;
116 session_p
->digest
.flags
&= ~CRYPTO_OPERATION_ACTIVE
;
118 * Decrement the session reference count.
119 * We hold the session lock, and REFRELE()
120 * will release the session lock for us.
122 REFRELE(session_p
, ses_lock_held
);
127 * Decrement the session reference count.
128 * We do not hold the session lock.
130 REFRELE(session_p
, ses_lock_held
);
135 C_DigestInit(CK_SESSION_HANDLE hSession
, CK_MECHANISM_PTR pMechanism
)
137 return (common_digest_init(hSession
, pMechanism
, B_TRUE
));
141 C_Digest(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pData
, CK_ULONG ulDataLen
,
142 CK_BYTE_PTR pDigest
, CK_ULONG_PTR pulDigestLen
)
145 kernel_session_t
*session_p
;
146 boolean_t ses_lock_held
= B_FALSE
;
147 crypto_digest_t digest
;
150 if (!kernel_initialized
)
151 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
154 * Obtain the session pointer. Also, increment the session
157 rv
= handle2session(hSession
, &session_p
);
161 if (pData
== NULL
|| pulDigestLen
== NULL
) {
162 rv
= CKR_ARGUMENTS_BAD
;
166 /* Acquire the session lock */
167 (void) pthread_mutex_lock(&session_p
->session_mutex
);
168 ses_lock_held
= B_TRUE
;
170 /* Application must call C_DigestInit before calling C_Digest */
171 if (!(session_p
->digest
.flags
& CRYPTO_OPERATION_ACTIVE
)) {
173 * Decrement the session reference count.
174 * We hold the session lock, and REFRELE()
175 * will release the session lock for us.
177 REFRELE(session_p
, ses_lock_held
);
178 return (CKR_OPERATION_NOT_INITIALIZED
);
182 * C_Digest must be called without intervening C_DigestUpdate
185 if (session_p
->digest
.flags
& CRYPTO_OPERATION_UPDATE
) {
187 * C_Digest can not be used to terminate a multi-part
188 * operation, so we'll leave the active digest operation
189 * flag on and let the application continue with the
190 * digest update operation.
192 * Decrement the session reference count.
193 * We hold the session lock, and REFRELE()
194 * will release the session lock for us.
196 REFRELE(session_p
, ses_lock_held
);
197 return (CKR_FUNCTION_FAILED
);
200 if (session_p
->digest
.flags
& CRYPTO_EMULATE
) {
201 crypto_active_op_t
*opp
;
202 CK_MECHANISM_PTR pMechanism
;
204 opp
= &(session_p
->digest
);
205 if (opp
->context
== NULL
) {
206 REFRELE(session_p
, ses_lock_held
);
207 return (CKR_ARGUMENTS_BAD
);
209 pMechanism
= &(opp
->mech
);
211 if ((ulDataLen
< SLOT_THRESHOLD(session_p
)) ||
212 (ulDataLen
> SLOT_HASH_MAX_INDATA_LEN(session_p
))) {
213 session_p
->digest
.flags
|= CRYPTO_EMULATE_USING_SW
;
214 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
215 ses_lock_held
= B_FALSE
;
217 rv
= do_soft_digest(get_spp(opp
), pMechanism
,
218 pData
, ulDataLen
, pDigest
, pulDigestLen
,
219 OP_INIT
| OP_SINGLE
);
221 } else if (!(session_p
->digest
.flags
&
222 CRYPTO_EMULATE_INIT_DONE
)) {
223 session_p
->digest
.flags
|= CRYPTO_EMULATE_INIT_DONE
;
224 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
225 ses_lock_held
= B_FALSE
;
227 rv
= common_digest_init(hSession
, pMechanism
, B_FALSE
);
230 (void) pthread_mutex_lock(&session_p
->session_mutex
);
231 ses_lock_held
= B_TRUE
;
235 digest
.cd_session
= session_p
->k_session
;
236 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
237 ses_lock_held
= B_FALSE
;
238 digest
.cd_datalen
= ulDataLen
;
239 digest
.cd_databuf
= (char *)pData
;
240 digest
.cd_digestbuf
= (char *)pDigest
;
241 digest
.cd_digestlen
= *pulDigestLen
;
243 while ((r
= ioctl(kernel_fd
, CRYPTO_DIGEST
, &digest
)) < 0) {
248 rv
= CKR_FUNCTION_FAILED
;
250 rv
= crypto2pkcs11_error_number(digest
.cd_return_value
);
253 if ((rv
== CKR_OK
) || (rv
== CKR_BUFFER_TOO_SMALL
))
254 *pulDigestLen
= digest
.cd_digestlen
;
257 if ((rv
== CKR_BUFFER_TOO_SMALL
) ||
258 (rv
== CKR_OK
&& pDigest
== NULL
)) {
260 * We will not terminate the active digest operation flag,
261 * when the application-supplied buffer is too small, or
262 * the application asks for the length of buffer to hold
263 * the message digest.
265 * Decrement the session reference count.
266 * We do not hold the session lock.
268 REFRELE(session_p
, ses_lock_held
);
274 * Terminates the active digest operation.
275 * Application needs to call C_DigestInit again for next
278 (void) pthread_mutex_lock(&session_p
->session_mutex
);
279 ses_lock_held
= B_TRUE
;
281 REINIT_OPBUF(&session_p
->digest
);
282 session_p
->digest
.flags
= 0;
285 * Decrement the session reference count.
286 * We hold the session lock, and REFRELE()
287 * will release the session lock for us.
289 REFRELE(session_p
, ses_lock_held
);
295 C_DigestUpdate(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pPart
,
300 kernel_session_t
*session_p
;
301 boolean_t ses_lock_held
= B_FALSE
;
302 crypto_digest_update_t digest_update
;
305 if (!kernel_initialized
)
306 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
309 * Obtain the session pointer. Also, increment the session
312 rv
= handle2session(hSession
, &session_p
);
317 rv
= CKR_ARGUMENTS_BAD
;
321 /* Acquire the session lock */
322 (void) pthread_mutex_lock(&session_p
->session_mutex
);
323 ses_lock_held
= B_TRUE
;
326 * Application must call C_DigestInit before calling
329 if (!(session_p
->digest
.flags
& CRYPTO_OPERATION_ACTIVE
)) {
331 * Decrement the session reference count.
332 * We hold the session lock, and REFRELE()
333 * will release the session lock for us.
335 REFRELE(session_p
, ses_lock_held
);
336 return (CKR_OPERATION_NOT_INITIALIZED
);
339 /* Set update flag to protect C_Digest */
340 session_p
->digest
.flags
|= CRYPTO_OPERATION_UPDATE
;
342 if (session_p
->digest
.flags
& CRYPTO_EMULATE
) {
343 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
344 ses_lock_held
= B_FALSE
;
345 rv
= emulate_update(session_p
, pPart
, ulPartLen
, OP_DIGEST
);
349 digest_update
.du_session
= session_p
->k_session
;
350 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
351 ses_lock_held
= B_FALSE
;
352 digest_update
.du_datalen
= ulPartLen
;
353 digest_update
.du_databuf
= (char *)pPart
;
355 while ((r
= ioctl(kernel_fd
, CRYPTO_DIGEST_UPDATE
,
356 &digest_update
)) < 0) {
361 rv
= CKR_FUNCTION_FAILED
;
363 rv
= crypto2pkcs11_error_number(digest_update
.du_return_value
);
369 * Decrement the session reference count.
370 * We do not hold the session lock.
372 REFRELE(session_p
, ses_lock_held
);
378 * After an error occurred, terminate the current digest
379 * operation by resetting the active and update flags.
381 (void) pthread_mutex_lock(&session_p
->session_mutex
);
382 ses_lock_held
= B_TRUE
;
383 REINIT_OPBUF(&session_p
->digest
);
384 session_p
->digest
.flags
= 0;
387 * Decrement the session reference count.
388 * We hold the session lock, and REFRELE()
389 * will release the session lock for us.
391 REFRELE(session_p
, ses_lock_held
);
398 C_DigestKey(CK_SESSION_HANDLE hSession
, CK_OBJECT_HANDLE hKey
)
402 kernel_session_t
*session_p
;
403 kernel_object_t
*key_p
;
404 boolean_t ses_lock_held
= B_FALSE
;
407 crypto_digest_key_t digest_key
;
408 crypto_digest_update_t digest_update
;
411 if (!kernel_initialized
)
412 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
415 * Obtain the session pointer. Also, increment the session
418 rv
= handle2session(hSession
, &session_p
);
422 /* Obtain the object pointer. */
423 HANDLE2OBJECT(hKey
, key_p
, rv
);
425 (void) pthread_mutex_lock(&session_p
->session_mutex
);
426 ses_lock_held
= B_TRUE
;
427 REINIT_OPBUF(&session_p
->digest
);
428 session_p
->digest
.flags
= 0;
429 REFRELE(session_p
, ses_lock_held
);
433 /* Check the key type */
434 if (key_p
->is_lib_obj
&& (key_p
->class != CKO_SECRET_KEY
)) {
435 rv
= CKR_KEY_INDIGESTIBLE
;
440 * Application must call C_DigestInit before calling
443 (void) pthread_mutex_lock(&session_p
->session_mutex
);
444 ses_lock_held
= B_TRUE
;
446 if (!(session_p
->digest
.flags
& CRYPTO_OPERATION_ACTIVE
)) {
448 * Decrement the session reference count.
449 * We hold the session lock, and REFRELE()
450 * will release the session lock for us.
453 REFRELE(session_p
, ses_lock_held
);
454 return (CKR_OPERATION_NOT_INITIALIZED
);
456 session_p
->digest
.flags
|= CRYPTO_OPERATION_UPDATE
;
459 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
460 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
463 if (key_p
->is_lib_obj
) {
464 digest_update
.du_session
= session_p
->k_session
;
466 digest_key
.dk_session
= session_p
->k_session
;
468 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
469 ses_lock_held
= B_FALSE
;
471 if (!key_p
->is_lib_obj
) {
472 if (session_p
->digest
.flags
& CRYPTO_EMULATE
) {
473 rv
= CKR_FUNCTION_NOT_SUPPORTED
;
476 digest_key
.dk_key
.ck_format
= CRYPTO_KEY_REFERENCE
;
477 digest_key
.dk_key
.ck_obj_id
= key_p
->k_handle
;
478 while ((r
= ioctl(kernel_fd
, CRYPTO_DIGEST_KEY
,
484 rv
= CKR_FUNCTION_FAILED
;
486 rv
= crypto2pkcs11_error_number(
487 digest_key
.dk_return_value
);
490 ulPartLen
= OBJ_SEC_VALUE_LEN(key_p
);
491 if (ulPartLen
== 0) {
492 rv
= CKR_KEY_SIZE_RANGE
;
496 pPart
= (CK_BYTE_PTR
) OBJ_SEC_VALUE(key_p
);
498 rv
= CKR_KEY_HANDLE_INVALID
;
502 (void) pthread_mutex_lock(&session_p
->session_mutex
);
503 ses_lock_held
= B_TRUE
;
504 if (session_p
->digest
.flags
& CRYPTO_EMULATE
) {
505 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
506 ses_lock_held
= B_FALSE
;
507 rv
= emulate_update(session_p
, pPart
,
508 ulPartLen
, OP_DIGEST
);
511 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
512 ses_lock_held
= B_FALSE
;
514 digest_update
.du_datalen
= ulPartLen
;
515 digest_update
.du_databuf
= (char *)pPart
;
517 while ((r
= ioctl(kernel_fd
, CRYPTO_DIGEST_UPDATE
,
518 &digest_update
)) < 0) {
523 rv
= CKR_FUNCTION_FAILED
;
525 rv
= crypto2pkcs11_error_number(
526 digest_update
.du_return_value
);
533 * Decrement the session reference count.
534 * We do not hold the session lock.
537 REFRELE(session_p
, ses_lock_held
);
544 * After an error occurred, terminate the current digest
545 * operation by resetting the active and update flags.
547 (void) pthread_mutex_lock(&session_p
->session_mutex
);
548 ses_lock_held
= B_TRUE
;
549 REINIT_OPBUF(&session_p
->digest
);
550 session_p
->digest
.flags
= 0;
553 * Decrement the session reference count.
554 * We hold the session lock, and REFRELE()
555 * will release the session lock for us.
557 REFRELE(session_p
, ses_lock_held
);
563 C_DigestFinal(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pDigest
,
564 CK_ULONG_PTR pulDigestLen
)
568 kernel_session_t
*session_p
;
569 boolean_t ses_lock_held
= B_FALSE
;
570 crypto_digest_final_t digest_final
;
573 if (!kernel_initialized
)
574 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
577 * Obtain the session pointer. Also, increment the session
580 rv
= handle2session(hSession
, &session_p
);
584 if (pulDigestLen
== NULL
) {
585 rv
= CKR_ARGUMENTS_BAD
;
589 /* Acquire the session lock */
590 (void) pthread_mutex_lock(&session_p
->session_mutex
);
591 ses_lock_held
= B_TRUE
;
594 * Application must call C_DigestInit before calling
597 if (!(session_p
->digest
.flags
& CRYPTO_OPERATION_ACTIVE
)) {
599 * Decrement the session reference count.
600 * We hold the session lock, and REFRELE()
601 * will release the session lock for us.
603 REFRELE(session_p
, ses_lock_held
);
604 return (CKR_OPERATION_NOT_INITIALIZED
);
607 /* The order of checks is important here */
608 if (session_p
->digest
.flags
& CRYPTO_EMULATE_USING_SW
) {
609 if (session_p
->digest
.flags
& CRYPTO_EMULATE_UPDATE_DONE
) {
610 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
611 ses_lock_held
= B_FALSE
;
612 rv
= do_soft_digest(get_spp(&session_p
->digest
),
613 NULL
, NULL
, 0, pDigest
, pulDigestLen
, OP_FINAL
);
616 * We end up here if an earlier C_DigestFinal() call
617 * took the C_Digest() path and it had returned
618 * CKR_BUFFER_TOO_SMALL.
620 digest_buf_t
*bufp
= session_p
->digest
.context
;
621 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
622 ses_lock_held
= B_FALSE
;
623 if (bufp
== NULL
|| bufp
->buf
== NULL
) {
624 rv
= CKR_ARGUMENTS_BAD
;
627 rv
= do_soft_digest(get_spp(&session_p
->digest
),
628 NULL
, bufp
->buf
, bufp
->indata_len
,
629 pDigest
, pulDigestLen
, OP_SINGLE
);
632 } else if (session_p
->digest
.flags
& CRYPTO_EMULATE
) {
633 digest_buf_t
*bufp
= session_p
->digest
.context
;
636 * We are emulating a single-part operation now.
637 * So, clear the flag.
639 session_p
->digest
.flags
&= ~CRYPTO_OPERATION_UPDATE
;
640 if (bufp
== NULL
|| bufp
->buf
== NULL
) {
641 rv
= CKR_ARGUMENTS_BAD
;
644 REFRELE(session_p
, ses_lock_held
);
645 rv
= C_Digest(hSession
, bufp
->buf
, bufp
->indata_len
,
646 pDigest
, pulDigestLen
);
650 digest_final
.df_session
= session_p
->k_session
;
651 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
652 ses_lock_held
= B_FALSE
;
653 digest_final
.df_digestlen
= *pulDigestLen
;
654 digest_final
.df_digestbuf
= (char *)pDigest
;
656 while ((r
= ioctl(kernel_fd
, CRYPTO_DIGEST_FINAL
, &digest_final
)) < 0) {
661 rv
= CKR_FUNCTION_FAILED
;
663 rv
= crypto2pkcs11_error_number(digest_final
.df_return_value
);
666 if ((rv
== CKR_OK
) || (rv
== CKR_BUFFER_TOO_SMALL
))
667 *pulDigestLen
= digest_final
.df_digestlen
;
670 if ((rv
== CKR_BUFFER_TOO_SMALL
) ||
671 (rv
== CKR_OK
&& pDigest
== NULL
)) {
673 * We will not terminate the active digest operation flag,
674 * when the application-supplied buffer is too small, or
675 * the application asks for the length of buffer to hold
676 * the message digest.
678 * Decrement the session reference count.
679 * We do not hold the session lock.
681 REFRELE(session_p
, ses_lock_held
);
686 /* Terminates the active digest operation */
687 (void) pthread_mutex_lock(&session_p
->session_mutex
);
688 ses_lock_held
= B_TRUE
;
689 REINIT_OPBUF(&session_p
->digest
);
690 session_p
->digest
.flags
= 0;
693 * Decrement the session reference count.
694 * We hold the session lock, and REFRELE()
695 * will release the session lock for us.
697 REFRELE(session_p
, ses_lock_held
);