1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2018, Joyent, Inc.
26  */
27 
28 #include <pthread.h>
29 #include <errno.h>
30 #include <sys/crypto/ioctl.h>
31 #include <security/cryptoki.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelEmulate.h"
35 
36 static CK_RV
common_digest_init(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,boolean_t is_external_caller)37 common_digest_init(CK_SESSION_HANDLE hSession,
38     CK_MECHANISM_PTR pMechanism, boolean_t is_external_caller)
39 {
40 	CK_RV rv;
41 	kernel_session_t *session_p;
42 	boolean_t ses_lock_held = B_FALSE;
43 	crypto_digest_init_t digest_init;
44 	crypto_mech_type_t k_mech_type;
45 	int r;
46 
47 	if (!kernel_initialized)
48 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
49 
50 	if (pMechanism == NULL)
51 		return (CKR_ARGUMENTS_BAD);
52 
53 	/*
54 	 * Get the kernel's internal mechanism number.
55 	 */
56 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
57 	if (rv != CKR_OK)
58 		return (rv);
59 
60 	/*
61 	 * Obtain the session pointer. Also, increment the session
62 	 * reference count.
63 	 */
64 	rv = handle2session(hSession, &session_p);
65 	if (rv != CKR_OK)
66 		return (rv);
67 
68 	/* Acquire the session lock */
69 	(void) pthread_mutex_lock(&session_p->session_mutex);
70 	ses_lock_held = B_TRUE;
71 
72 	/*
73 	 * This active flag will remain ON until application calls either
74 	 * C_Digest or C_DigestFinal to actually obtain the value of
75 	 * the message digest.
76 	 */
77 	session_p->digest.flags |= CRYPTO_OPERATION_ACTIVE;
78 
79 	if (SLOT_HAS_LIMITED_HASH(session_p) && is_external_caller) {
80 		session_p->digest.mech.mechanism = pMechanism->mechanism;
81 		session_p->digest.mech.pParameter = NULL;
82 		session_p->digest.mech.ulParameterLen = 0;
83 		session_p->digest.flags |= CRYPTO_EMULATE;
84 		rv = emulate_buf_init(session_p, EDIGEST_LENGTH, OP_DIGEST);
85 		REFRELE(session_p, ses_lock_held);
86 		return (rv);
87 	}
88 
89 	digest_init.di_session = session_p->k_session;
90 	(void) pthread_mutex_unlock(&session_p->session_mutex);
91 	ses_lock_held = B_FALSE;
92 	digest_init.di_mech.cm_type = k_mech_type;
93 	digest_init.di_mech.cm_param = pMechanism->pParameter;
94 
95 	/*
96 	 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call
97 	 * will have a clean input data.
98 	 */
99 	if (pMechanism->pParameter != NULL)
100 		digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
101 	else
102 		digest_init.di_mech.cm_param_len = 0;
103 
104 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) {
105 		if (errno != EINTR)
106 			break;
107 	}
108 	if (r < 0) {
109 		rv = CKR_FUNCTION_FAILED;
110 	} else {
111 		rv = crypto2pkcs11_error_number(digest_init.di_return_value);
112 	}
113 
114 	if (rv != CKR_OK) {
115 		(void) pthread_mutex_lock(&session_p->session_mutex);
116 		ses_lock_held = B_TRUE;
117 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
118 		/*
119 		 * Decrement the session reference count.
120 		 * We hold the session lock, and REFRELE()
121 		 * will release the session lock for us.
122 		 */
123 		REFRELE(session_p, ses_lock_held);
124 		return (rv);
125 	}
126 
127 	/*
128 	 * Decrement the session reference count.
129 	 * We do not hold the session lock.
130 	 */
131 	REFRELE(session_p, ses_lock_held);
132 	return (rv);
133 }
134 
135 CK_RV
C_DigestInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism)136 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
137 {
138 	return (common_digest_init(hSession, pMechanism, B_TRUE));
139 }
140 
141 CK_RV
C_Digest(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)142 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
143     CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
144 {
145 	CK_RV rv;
146 	kernel_session_t *session_p;
147 	boolean_t ses_lock_held = B_FALSE;
148 	crypto_digest_t digest;
149 	int r;
150 
151 	if (!kernel_initialized)
152 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
153 
154 	/*
155 	 * Obtain the session pointer. Also, increment the session
156 	 * reference count.
157 	 */
158 	rv = handle2session(hSession, &session_p);
159 	if (rv != CKR_OK)
160 		return (rv);
161 
162 	if ((pData == NULL && ulDataLen != 0) || pulDigestLen == NULL) {
163 		rv = CKR_ARGUMENTS_BAD;
164 		goto clean_exit;
165 	}
166 
167 	/* Acquire the session lock */
168 	(void) pthread_mutex_lock(&session_p->session_mutex);
169 	ses_lock_held = B_TRUE;
170 
171 	/* Application must call C_DigestInit before calling C_Digest */
172 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
173 		/*
174 		 * Decrement the session reference count.
175 		 * We hold the session lock, and REFRELE()
176 		 * will release the session lock for us.
177 		 */
178 		REFRELE(session_p, ses_lock_held);
179 		return (CKR_OPERATION_NOT_INITIALIZED);
180 	}
181 
182 	/*
183 	 * C_Digest must be called without intervening C_DigestUpdate
184 	 * calls.
185 	 */
186 	if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) {
187 		/*
188 		 * C_Digest can not be used to terminate a multi-part
189 		 * operation, so we'll leave the active digest operation
190 		 * flag on and let the application continue with the
191 		 * digest update operation.
192 		 *
193 		 * Decrement the session reference count.
194 		 * We hold the session lock, and REFRELE()
195 		 * will release the session lock for us.
196 		 */
197 		REFRELE(session_p, ses_lock_held);
198 		return (CKR_FUNCTION_FAILED);
199 	}
200 
201 	if (session_p->digest.flags & CRYPTO_EMULATE) {
202 		crypto_active_op_t *opp;
203 		CK_MECHANISM_PTR pMechanism;
204 
205 		opp = &(session_p->digest);
206 		if (opp->context == NULL) {
207 			REFRELE(session_p, ses_lock_held);
208 			return (CKR_ARGUMENTS_BAD);
209 		}
210 		pMechanism = &(opp->mech);
211 
212 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
213 		    (ulDataLen > SLOT_HASH_MAX_INDATA_LEN(session_p))) {
214 			session_p->digest.flags |= CRYPTO_EMULATE_USING_SW;
215 			(void) pthread_mutex_unlock(&session_p->session_mutex);
216 			ses_lock_held = B_FALSE;
217 
218 			rv = do_soft_digest(get_spp(opp), pMechanism,
219 			    pData, ulDataLen, pDigest, pulDigestLen,
220 			    OP_INIT | OP_SINGLE);
221 			goto done;
222 		} else if (!(session_p->digest.flags &
223 		    CRYPTO_EMULATE_INIT_DONE)) {
224 			session_p->digest.flags |= CRYPTO_EMULATE_INIT_DONE;
225 			(void) pthread_mutex_unlock(&session_p->session_mutex);
226 			ses_lock_held = B_FALSE;
227 
228 			rv = common_digest_init(hSession, pMechanism, B_FALSE);
229 			if (rv != CKR_OK)
230 				goto clean_exit;
231 			(void) pthread_mutex_lock(&session_p->session_mutex);
232 			ses_lock_held = B_TRUE;
233 		}
234 	}
235 
236 	digest.cd_session = session_p->k_session;
237 	(void) pthread_mutex_unlock(&session_p->session_mutex);
238 	ses_lock_held = B_FALSE;
239 	digest.cd_datalen =  ulDataLen;
240 	digest.cd_databuf = (char *)pData;
241 	digest.cd_digestbuf = (char *)pDigest;
242 	digest.cd_digestlen = *pulDigestLen;
243 
244 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) {
245 		if (errno != EINTR)
246 			break;
247 	}
248 	if (r < 0) {
249 		rv = CKR_FUNCTION_FAILED;
250 	} else {
251 		rv = crypto2pkcs11_error_number(digest.cd_return_value);
252 	}
253 
254 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
255 		*pulDigestLen = digest.cd_digestlen;
256 
257 done:
258 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
259 	    (rv == CKR_OK && pDigest == NULL)) {
260 		/*
261 		 * We will not terminate the active digest operation flag,
262 		 * when the application-supplied buffer is too small, or
263 		 * the application asks for the length of buffer to hold
264 		 * the message digest.
265 		 *
266 		 * Decrement the session reference count.
267 		 * We do not hold the session lock.
268 		 */
269 		REFRELE(session_p, ses_lock_held);
270 		return (rv);
271 	}
272 
273 clean_exit:
274 	/*
275 	 * Terminates the active digest operation.
276 	 * Application needs to call C_DigestInit again for next
277 	 * digest operation.
278 	 */
279 	(void) pthread_mutex_lock(&session_p->session_mutex);
280 	ses_lock_held = B_TRUE;
281 
282 	REINIT_OPBUF(&session_p->digest);
283 	session_p->digest.flags = 0;
284 
285 	/*
286 	 * Decrement the session reference count.
287 	 * We hold the session lock, and REFRELE()
288 	 * will release the session lock for us.
289 	 */
290 	REFRELE(session_p, ses_lock_held);
291 
292 	return (rv);
293 }
294 
295 CK_RV
C_DigestUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)296 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
297     CK_ULONG ulPartLen)
298 {
299 
300 	CK_RV rv;
301 	kernel_session_t *session_p;
302 	boolean_t ses_lock_held = B_FALSE;
303 	crypto_digest_update_t digest_update;
304 	int r;
305 
306 	if (!kernel_initialized)
307 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
308 
309 	/*
310 	 * Obtain the session pointer. Also, increment the session
311 	 * reference count.
312 	 */
313 	rv = handle2session(hSession, &session_p);
314 	if (rv != CKR_OK)
315 		return (rv);
316 
317 	if (pPart == NULL) {
318 		rv = CKR_ARGUMENTS_BAD;
319 		goto clean_exit;
320 	}
321 
322 	/* Acquire the session lock */
323 	(void) pthread_mutex_lock(&session_p->session_mutex);
324 	ses_lock_held = B_TRUE;
325 
326 	/*
327 	 * Application must call C_DigestInit before calling
328 	 * C_DigestUpdate.
329 	 */
330 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
331 		/*
332 		 * Decrement the session reference count.
333 		 * We hold the session lock, and REFRELE()
334 		 * will release the session lock for us.
335 		 */
336 		REFRELE(session_p, ses_lock_held);
337 		return (CKR_OPERATION_NOT_INITIALIZED);
338 	}
339 
340 	/* Set update flag to protect C_Digest */
341 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
342 
343 	if (session_p->digest.flags & CRYPTO_EMULATE) {
344 		(void) pthread_mutex_unlock(&session_p->session_mutex);
345 		ses_lock_held = B_FALSE;
346 		rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST);
347 		goto done;
348 	}
349 
350 	digest_update.du_session = session_p->k_session;
351 	(void) pthread_mutex_unlock(&session_p->session_mutex);
352 	ses_lock_held = B_FALSE;
353 	digest_update.du_datalen =  ulPartLen;
354 	digest_update.du_databuf = (char *)pPart;
355 
356 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
357 	    &digest_update)) < 0) {
358 		if (errno != EINTR)
359 			break;
360 	}
361 	if (r < 0) {
362 		rv = CKR_FUNCTION_FAILED;
363 	} else {
364 		rv = crypto2pkcs11_error_number(digest_update.du_return_value);
365 	}
366 
367 done:
368 	if (rv == CKR_OK) {
369 		/*
370 		 * Decrement the session reference count.
371 		 * We do not hold the session lock.
372 		 */
373 		REFRELE(session_p, ses_lock_held);
374 		return (CKR_OK);
375 	}
376 
377 clean_exit:
378 	/*
379 	 * After an error occurred, terminate the current digest
380 	 * operation by resetting the active and update flags.
381 	 */
382 	(void) pthread_mutex_lock(&session_p->session_mutex);
383 	ses_lock_held = B_TRUE;
384 	REINIT_OPBUF(&session_p->digest);
385 	session_p->digest.flags = 0;
386 
387 	/*
388 	 * Decrement the session reference count.
389 	 * We hold the session lock, and REFRELE()
390 	 * will release the session lock for us.
391 	 */
392 	REFRELE(session_p, ses_lock_held);
393 
394 	return (rv);
395 }
396 
397 
398 CK_RV
C_DigestKey(CK_SESSION_HANDLE hSession,CK_OBJECT_HANDLE hKey)399 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
400 {
401 
402 	CK_RV		rv;
403 	kernel_session_t	*session_p;
404 	kernel_object_t	*key_p;
405 	boolean_t ses_lock_held = B_FALSE;
406 	CK_BYTE_PTR	pPart;
407 	CK_ULONG	ulPartLen;
408 	crypto_digest_key_t digest_key;
409 	crypto_digest_update_t digest_update;
410 	int r;
411 
412 	if (!kernel_initialized)
413 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
414 
415 	/*
416 	 * Obtain the session pointer. Also, increment the session
417 	 * reference count.
418 	 */
419 	rv = handle2session(hSession, &session_p);
420 	if (rv != CKR_OK)
421 		return (rv);
422 
423 	/* Obtain the object pointer. */
424 	HANDLE2OBJECT(hKey, key_p, rv);
425 	if (rv != CKR_OK) {
426 		(void) pthread_mutex_lock(&session_p->session_mutex);
427 		ses_lock_held = B_TRUE;
428 		REINIT_OPBUF(&session_p->digest);
429 		session_p->digest.flags = 0;
430 		REFRELE(session_p, ses_lock_held);
431 		return (rv);
432 	}
433 
434 	/* Check the key type */
435 	if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
436 		rv = CKR_KEY_INDIGESTIBLE;
437 		goto clean_exit;
438 	}
439 
440 	/*
441 	 * Application must call C_DigestInit before calling
442 	 * C_DigestKey.
443 	 */
444 	(void) pthread_mutex_lock(&session_p->session_mutex);
445 	ses_lock_held = B_TRUE;
446 
447 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
448 		/*
449 		 * Decrement the session reference count.
450 		 * We hold the session lock, and REFRELE()
451 		 * will release the session lock for us.
452 		 */
453 		OBJ_REFRELE(key_p);
454 		REFRELE(session_p, ses_lock_held);
455 		return (CKR_OPERATION_NOT_INITIALIZED);
456 	}
457 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
458 
459 	/*
460 	 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
461 	 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
462 	 * by value.
463 	 */
464 	if (key_p->is_lib_obj) {
465 		digest_update.du_session = session_p->k_session;
466 	} else {
467 		digest_key.dk_session = session_p->k_session;
468 	}
469 	(void) pthread_mutex_unlock(&session_p->session_mutex);
470 	ses_lock_held = B_FALSE;
471 
472 	if (!key_p->is_lib_obj) {
473 		if (session_p->digest.flags & CRYPTO_EMULATE) {
474 			rv = CKR_FUNCTION_NOT_SUPPORTED;
475 			goto clean_exit;
476 		}
477 		digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE;
478 		digest_key.dk_key.ck_obj_id = key_p->k_handle;
479 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY,
480 		    &digest_key)) < 0) {
481 			if (errno != EINTR)
482 				break;
483 		}
484 		if (r < 0) {
485 			rv = CKR_FUNCTION_FAILED;
486 		} else {
487 			rv = crypto2pkcs11_error_number(
488 			    digest_key.dk_return_value);
489 		}
490 	} else {
491 		ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
492 		if (ulPartLen == 0) {
493 			rv = CKR_KEY_SIZE_RANGE;
494 			goto clean_exit;
495 		}
496 
497 		pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
498 		if (pPart == NULL) {
499 			rv = CKR_KEY_HANDLE_INVALID;
500 			goto clean_exit;
501 		}
502 
503 		(void) pthread_mutex_lock(&session_p->session_mutex);
504 		ses_lock_held = B_TRUE;
505 		if (session_p->digest.flags & CRYPTO_EMULATE) {
506 			(void) pthread_mutex_unlock(&session_p->session_mutex);
507 			ses_lock_held = B_FALSE;
508 			rv = emulate_update(session_p, pPart,
509 			    ulPartLen, OP_DIGEST);
510 			goto done;
511 		}
512 		(void) pthread_mutex_unlock(&session_p->session_mutex);
513 		ses_lock_held = B_FALSE;
514 
515 		digest_update.du_datalen = ulPartLen;
516 		digest_update.du_databuf = (char *)pPart;
517 
518 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
519 		    &digest_update)) < 0) {
520 			if (errno != EINTR)
521 				break;
522 		}
523 		if (r < 0) {
524 			rv = CKR_FUNCTION_FAILED;
525 		} else {
526 			rv = crypto2pkcs11_error_number(
527 			    digest_update.du_return_value);
528 		}
529 	}
530 
531 done:
532 	if (rv == CKR_OK) {
533 		/*
534 		 * Decrement the session reference count.
535 		 * We do not hold the session lock.
536 		 */
537 		OBJ_REFRELE(key_p);
538 		REFRELE(session_p, ses_lock_held);
539 		return (CKR_OK);
540 	}
541 
542 clean_exit:
543 	OBJ_REFRELE(key_p);
544 	/*
545 	 * After an error occurred, terminate the current digest
546 	 * operation by resetting the active and update flags.
547 	 */
548 	(void) pthread_mutex_lock(&session_p->session_mutex);
549 	ses_lock_held = B_TRUE;
550 	REINIT_OPBUF(&session_p->digest);
551 	session_p->digest.flags = 0;
552 
553 	/*
554 	 * Decrement the session reference count.
555 	 * We hold the session lock, and REFRELE()
556 	 * will release the session lock for us.
557 	 */
558 	REFRELE(session_p, ses_lock_held);
559 	return (rv);
560 }
561 
562 
563 CK_RV
C_DigestFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)564 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
565     CK_ULONG_PTR pulDigestLen)
566 {
567 
568 	CK_RV rv;
569 	kernel_session_t *session_p;
570 	boolean_t ses_lock_held = B_FALSE;
571 	crypto_digest_final_t digest_final;
572 	int r;
573 
574 	if (!kernel_initialized)
575 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
576 
577 	/*
578 	 * Obtain the session pointer. Also, increment the session
579 	 * reference count.
580 	 */
581 	rv = handle2session(hSession, &session_p);
582 	if (rv != CKR_OK)
583 		return (rv);
584 
585 	if (pulDigestLen == NULL) {
586 		rv = CKR_ARGUMENTS_BAD;
587 		goto clean_exit;
588 	}
589 
590 	/* Acquire the session lock */
591 	(void) pthread_mutex_lock(&session_p->session_mutex);
592 	ses_lock_held = B_TRUE;
593 
594 	/*
595 	 * Application must call C_DigestInit before calling
596 	 * C_DigestFinal.
597 	 */
598 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
599 		/*
600 		 * Decrement the session reference count.
601 		 * We hold the session lock, and REFRELE()
602 		 * will release the session lock for us.
603 		 */
604 		REFRELE(session_p, ses_lock_held);
605 		return (CKR_OPERATION_NOT_INITIALIZED);
606 	}
607 
608 	/* The order of checks is important here */
609 	if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) {
610 		if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) {
611 			(void) pthread_mutex_unlock(&session_p->session_mutex);
612 			ses_lock_held = B_FALSE;
613 			rv = do_soft_digest(get_spp(&session_p->digest),
614 			    NULL, NULL, 0, pDigest, pulDigestLen, OP_FINAL);
615 		} else {
616 			/*
617 			 * We end up here if an earlier C_DigestFinal() call
618 			 * took the C_Digest() path and it had returned
619 			 * CKR_BUFFER_TOO_SMALL.
620 			 */
621 			digest_buf_t *bufp = session_p->digest.context;
622 			(void) pthread_mutex_unlock(&session_p->session_mutex);
623 			ses_lock_held = B_FALSE;
624 			if (bufp == NULL || bufp->buf == NULL) {
625 				rv = CKR_ARGUMENTS_BAD;
626 				goto clean_exit;
627 			}
628 			rv = do_soft_digest(get_spp(&session_p->digest),
629 			    NULL, bufp->buf, bufp->indata_len,
630 			    pDigest, pulDigestLen, OP_SINGLE);
631 		}
632 		goto done;
633 	} else if (session_p->digest.flags & CRYPTO_EMULATE) {
634 		digest_buf_t *bufp = session_p->digest.context;
635 
636 		/*
637 		 * We are emulating a single-part operation now.
638 		 * So, clear the flag.
639 		 */
640 		session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE;
641 		if (bufp == NULL || bufp->buf == NULL) {
642 			rv = CKR_ARGUMENTS_BAD;
643 			goto clean_exit;
644 		}
645 		REFRELE(session_p, ses_lock_held);
646 		rv = C_Digest(hSession, bufp->buf, bufp->indata_len,
647 		    pDigest, pulDigestLen);
648 		return (rv);
649 	}
650 
651 	digest_final.df_session = session_p->k_session;
652 	(void) pthread_mutex_unlock(&session_p->session_mutex);
653 	ses_lock_held = B_FALSE;
654 	digest_final.df_digestlen = *pulDigestLen;
655 	digest_final.df_digestbuf = (char *)pDigest;
656 
657 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) {
658 		if (errno != EINTR)
659 			break;
660 	}
661 	if (r < 0) {
662 		rv = CKR_FUNCTION_FAILED;
663 	} else {
664 		rv = crypto2pkcs11_error_number(digest_final.df_return_value);
665 	}
666 
667 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
668 		*pulDigestLen = digest_final.df_digestlen;
669 
670 done:
671 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
672 	    (rv == CKR_OK && pDigest == NULL)) {
673 		/*
674 		 * We will not terminate the active digest operation flag,
675 		 * when the application-supplied buffer is too small, or
676 		 * the application asks for the length of buffer to hold
677 		 * the message digest.
678 		 *
679 		 * Decrement the session reference count.
680 		 * We do not hold the session lock.
681 		 */
682 		REFRELE(session_p, ses_lock_held);
683 		return (rv);
684 	}
685 
686 clean_exit:
687 	/* Terminates the active digest operation */
688 	(void) pthread_mutex_lock(&session_p->session_mutex);
689 	ses_lock_held = B_TRUE;
690 	REINIT_OPBUF(&session_p->digest);
691 	session_p->digest.flags = 0;
692 
693 	/*
694 	 * Decrement the session reference count.
695 	 * We hold the session lock, and REFRELE()
696 	 * will release the session lock for us.
697 	 */
698 	REFRELE(session_p, ses_lock_held);
699 
700 	return (rv);
701 }
702