dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / pkcs11 / pkcs11_kernel / common / kernelDigest.c
blobedad72075404f19e060c2e2c8e6f69cc12a49877
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
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <pthread.h>
28 #include <errno.h>
29 #include <sys/crypto/ioctl.h>
30 #include <security/cryptoki.h>
31 #include "kernelGlobal.h"
32 #include "kernelSession.h"
33 #include "kernelEmulate.h"
35 static CK_RV
36 common_digest_init(CK_SESSION_HANDLE hSession,
37 CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller)
39 CK_RV rv;
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;
44 int r;
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);
56 if (rv != CKR_OK)
57 return (rv);
60 * Obtain the session pointer. Also, increment the session
61 * reference count.
63 rv = handle2session(hSession, &session_p);
64 if (rv != CKR_OK)
65 return (rv);
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
74 * the message digest.
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);
85 return (rv);
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;
100 else
101 digest_init.di_mech.cm_param_len = 0;
103 while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) {
104 if (errno != EINTR)
105 break;
107 if (r < 0) {
108 rv = CKR_FUNCTION_FAILED;
109 } else {
110 rv = crypto2pkcs11_error_number(digest_init.di_return_value);
113 if (rv != CKR_OK) {
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);
123 return (rv);
127 * Decrement the session reference count.
128 * We do not hold the session lock.
130 REFRELE(session_p, ses_lock_held);
131 return (rv);
134 CK_RV
135 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
137 return (common_digest_init(hSession, pMechanism, B_TRUE));
140 CK_RV
141 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
142 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
144 CK_RV rv;
145 kernel_session_t *session_p;
146 boolean_t ses_lock_held = B_FALSE;
147 crypto_digest_t digest;
148 int r;
150 if (!kernel_initialized)
151 return (CKR_CRYPTOKI_NOT_INITIALIZED);
154 * Obtain the session pointer. Also, increment the session
155 * reference count.
157 rv = handle2session(hSession, &session_p);
158 if (rv != CKR_OK)
159 return (rv);
161 if (pData == NULL || pulDigestLen == NULL) {
162 rv = CKR_ARGUMENTS_BAD;
163 goto clean_exit;
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
183 * calls.
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);
220 goto done;
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);
228 if (rv != CKR_OK)
229 goto clean_exit;
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) {
244 if (errno != EINTR)
245 break;
247 if (r < 0) {
248 rv = CKR_FUNCTION_FAILED;
249 } else {
250 rv = crypto2pkcs11_error_number(digest.cd_return_value);
253 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
254 *pulDigestLen = digest.cd_digestlen;
256 done:
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);
269 return (rv);
272 clean_exit:
274 * Terminates the active digest operation.
275 * Application needs to call C_DigestInit again for next
276 * digest operation.
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);
291 return (rv);
294 CK_RV
295 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
296 CK_ULONG ulPartLen)
299 CK_RV rv;
300 kernel_session_t *session_p;
301 boolean_t ses_lock_held = B_FALSE;
302 crypto_digest_update_t digest_update;
303 int r;
305 if (!kernel_initialized)
306 return (CKR_CRYPTOKI_NOT_INITIALIZED);
309 * Obtain the session pointer. Also, increment the session
310 * reference count.
312 rv = handle2session(hSession, &session_p);
313 if (rv != CKR_OK)
314 return (rv);
316 if (pPart == NULL) {
317 rv = CKR_ARGUMENTS_BAD;
318 goto clean_exit;
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
327 * C_DigestUpdate.
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);
346 goto done;
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) {
357 if (errno != EINTR)
358 break;
360 if (r < 0) {
361 rv = CKR_FUNCTION_FAILED;
362 } else {
363 rv = crypto2pkcs11_error_number(digest_update.du_return_value);
366 done:
367 if (rv == CKR_OK) {
369 * Decrement the session reference count.
370 * We do not hold the session lock.
372 REFRELE(session_p, ses_lock_held);
373 return (CKR_OK);
376 clean_exit:
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);
393 return (rv);
397 CK_RV
398 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
401 CK_RV rv;
402 kernel_session_t *session_p;
403 kernel_object_t *key_p;
404 boolean_t ses_lock_held = B_FALSE;
405 CK_BYTE_PTR pPart;
406 CK_ULONG ulPartLen;
407 crypto_digest_key_t digest_key;
408 crypto_digest_update_t digest_update;
409 int r;
411 if (!kernel_initialized)
412 return (CKR_CRYPTOKI_NOT_INITIALIZED);
415 * Obtain the session pointer. Also, increment the session
416 * reference count.
418 rv = handle2session(hSession, &session_p);
419 if (rv != CKR_OK)
420 return (rv);
422 /* Obtain the object pointer. */
423 HANDLE2OBJECT(hKey, key_p, rv);
424 if (rv != CKR_OK) {
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);
430 return (rv);
433 /* Check the key type */
434 if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
435 rv = CKR_KEY_INDIGESTIBLE;
436 goto clean_exit;
440 * Application must call C_DigestInit before calling
441 * C_DigestKey.
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.
452 OBJ_REFRELE(key_p);
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
461 * by value.
463 if (key_p->is_lib_obj) {
464 digest_update.du_session = session_p->k_session;
465 } else {
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;
474 goto clean_exit;
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,
479 &digest_key)) < 0) {
480 if (errno != EINTR)
481 break;
483 if (r < 0) {
484 rv = CKR_FUNCTION_FAILED;
485 } else {
486 rv = crypto2pkcs11_error_number(
487 digest_key.dk_return_value);
489 } else {
490 ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
491 if (ulPartLen == 0) {
492 rv = CKR_KEY_SIZE_RANGE;
493 goto clean_exit;
496 pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
497 if (pPart == NULL) {
498 rv = CKR_KEY_HANDLE_INVALID;
499 goto clean_exit;
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);
509 goto done;
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) {
519 if (errno != EINTR)
520 break;
522 if (r < 0) {
523 rv = CKR_FUNCTION_FAILED;
524 } else {
525 rv = crypto2pkcs11_error_number(
526 digest_update.du_return_value);
530 done:
531 if (rv == CKR_OK) {
533 * Decrement the session reference count.
534 * We do not hold the session lock.
536 OBJ_REFRELE(key_p);
537 REFRELE(session_p, ses_lock_held);
538 return (CKR_OK);
541 clean_exit:
542 OBJ_REFRELE(key_p);
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);
558 return (rv);
562 CK_RV
563 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
564 CK_ULONG_PTR pulDigestLen)
567 CK_RV rv;
568 kernel_session_t *session_p;
569 boolean_t ses_lock_held = B_FALSE;
570 crypto_digest_final_t digest_final;
571 int r;
573 if (!kernel_initialized)
574 return (CKR_CRYPTOKI_NOT_INITIALIZED);
577 * Obtain the session pointer. Also, increment the session
578 * reference count.
580 rv = handle2session(hSession, &session_p);
581 if (rv != CKR_OK)
582 return (rv);
584 if (pulDigestLen == NULL) {
585 rv = CKR_ARGUMENTS_BAD;
586 goto clean_exit;
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
595 * C_DigestFinal.
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);
614 } else {
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;
625 goto clean_exit;
627 rv = do_soft_digest(get_spp(&session_p->digest),
628 NULL, bufp->buf, bufp->indata_len,
629 pDigest, pulDigestLen, OP_SINGLE);
631 goto done;
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;
642 goto clean_exit;
644 REFRELE(session_p, ses_lock_held);
645 rv = C_Digest(hSession, bufp->buf, bufp->indata_len,
646 pDigest, pulDigestLen);
647 return (rv);
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) {
657 if (errno != EINTR)
658 break;
660 if (r < 0) {
661 rv = CKR_FUNCTION_FAILED;
662 } else {
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;
669 done:
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);
682 return (rv);
685 clean_exit:
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);
699 return (rv);