xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelSign.c (revision 2a8d6eba033e4713ab12b61178f0513f1f075482)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <errno.h>
30 #include <security/cryptoki.h>
31 #include <sys/crypto/ioctl.h>
32 #include "kernelGlobal.h"
33 #include "kernelObject.h"
34 #include "kernelSession.h"
35 #include "kernelEmulate.h"
36 
37 CK_RV
38 C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
39     CK_OBJECT_HANDLE hKey)
40 {
41 	CK_RV rv;
42 	kernel_session_t *session_p;
43 	kernel_object_t *key_p;
44 	boolean_t ses_lock_held = B_FALSE;
45 	crypto_sign_init_t sign_init;
46 	crypto_mech_type_t k_mech_type;
47 	int r;
48 
49 	if (!kernel_initialized)
50 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
51 
52 	if (pMechanism == NULL) {
53 		return (CKR_ARGUMENTS_BAD);
54 	}
55 
56 	/* Get the kernel's internal mechanism number. */
57 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
58 	if (rv != CKR_OK) {
59 		return (rv);
60 	}
61 
62 	/* Obtain the session pointer. */
63 	rv = handle2session(hSession, &session_p);
64 	if (rv != CKR_OK)
65 		return (rv);
66 
67 	/* Obtain the object pointer. */
68 	HANDLE2OBJECT(hKey, key_p, rv);
69 	if (rv != CKR_OK) {
70 		REFRELE(session_p, ses_lock_held);
71 		return (rv);
72 	}
73 
74 	/* Check to see if key object supports signature. */
75 	if (key_p->is_lib_obj && !(key_p->bool_attr_mask & SIGN_BOOL_ON)) {
76 		rv = CKR_KEY_TYPE_INCONSISTENT;
77 		goto clean_exit;
78 	}
79 
80 	(void) pthread_mutex_lock(&session_p->session_mutex);
81 	ses_lock_held = B_TRUE;
82 
83 	/*
84 	 * This active flag will remain ON until application calls either
85 	 * C_Sign or C_SignFinal to actually obtain the signature.
86 	 */
87 	session_p->sign.flags = CRYPTO_OPERATION_ACTIVE;
88 	sign_init.si_session = session_p->k_session;
89 	(void) pthread_mutex_unlock(&session_p->session_mutex);
90 	ses_lock_held = B_FALSE;
91 
92 	if (!key_p->is_lib_obj) {
93 		sign_init.si_key.ck_format = CRYPTO_KEY_REFERENCE;
94 		sign_init.si_key.ck_obj_id = key_p->k_handle;
95 	} else {
96 		if (key_p->class == CKO_SECRET_KEY) {
97 			sign_init.si_key.ck_format = CRYPTO_KEY_RAW;
98 			sign_init.si_key.ck_data =
99 			    get_symmetric_key_value(key_p);
100 			if (sign_init.si_key.ck_data == NULL) {
101 				rv = CKR_HOST_MEMORY;
102 				goto clean_exit;
103 			}
104 			sign_init.si_key.ck_length =
105 			    OBJ_SEC(key_p)->sk_value_len << 3;
106 
107 		} else if (key_p->key_type == CKK_RSA) {
108 			rv = get_rsa_private_key(key_p, &sign_init.si_key);
109 			if (rv != CKR_OK) {
110 				goto clean_exit;
111 			}
112 		} else if (key_p->key_type == CKK_DSA) {
113 			rv = get_dsa_private_key(key_p, &sign_init.si_key);
114 			if (rv != CKR_OK) {
115 				goto clean_exit;
116 			}
117 		} else if (key_p->key_type == CKK_EC) {
118 			rv = get_ec_private_key(key_p, &sign_init.si_key);
119 			if (rv != CKR_OK) {
120 				goto clean_exit;
121 			}
122 		} else {
123 			rv = CKR_KEY_TYPE_INCONSISTENT;
124 			goto clean_exit;
125 		}
126 	}
127 
128 	sign_init.si_mech.cm_type = k_mech_type;
129 	sign_init.si_mech.cm_param = pMechanism->pParameter;
130 	sign_init.si_mech.cm_param_len = pMechanism->ulParameterLen;
131 
132 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_INIT, &sign_init)) < 0) {
133 		if (errno != EINTR)
134 			break;
135 	}
136 	if (r < 0) {
137 		rv = CKR_FUNCTION_FAILED;
138 	} else {
139 		rv = crypto2pkcs11_error_number(sign_init.si_return_value);
140 	}
141 
142 	if (rv == CKR_OK && SLOT_HAS_LIMITED_HASH(session_p) &&
143 	    is_hmac(pMechanism->mechanism)) {
144 		if (key_p->is_lib_obj && key_p->class == CKO_SECRET_KEY) {
145 			(void) pthread_mutex_lock(&session_p->session_mutex);
146 			session_p->sign.flags |= CRYPTO_EMULATE;
147 			(void) pthread_mutex_unlock(&session_p->session_mutex);
148 			rv = emulate_init(session_p, pMechanism,
149 			    &(sign_init.si_key), OP_SIGN);
150 		} else {
151 			rv = CKR_ARGUMENTS_BAD;
152 		}
153 	}
154 
155 	if (key_p->is_lib_obj) {
156 		if (key_p->class == CKO_SECRET_KEY) {
157 			free(sign_init.si_key.ck_data);
158 		} else {
159 			free_key_attributes(&sign_init.si_key);
160 		}
161 	}
162 
163 	if (rv != CKR_OK) {
164 		(void) pthread_mutex_lock(&session_p->session_mutex);
165 		session_p->sign.flags &= ~CRYPTO_OPERATION_ACTIVE;
166 		ses_lock_held = B_TRUE;
167 	}
168 
169 clean_exit:
170 	OBJ_REFRELE(key_p);
171 	REFRELE(session_p, ses_lock_held);
172 	return (rv);
173 }
174 
175 
176 CK_RV
177 C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
178     CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
179 {
180 
181 	CK_RV rv;
182 	kernel_session_t *session_p;
183 	boolean_t ses_lock_held = B_FALSE;
184 	crypto_sign_t sign;
185 	int r;
186 
187 	if (!kernel_initialized)
188 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
189 
190 	/* Obtain the session pointer */
191 	rv = handle2session(hSession, &session_p);
192 	if (rv != CKR_OK)
193 		return (rv);
194 
195 	if (pulSignatureLen == NULL) {
196 		rv = CKR_ARGUMENTS_BAD;
197 		goto clean_exit;
198 	}
199 
200 	(void) pthread_mutex_lock(&session_p->session_mutex);
201 	ses_lock_held = B_TRUE;
202 
203 	/* Application must call C_SignInit before calling C_Sign. */
204 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
205 		REFRELE(session_p, ses_lock_held);
206 		return (CKR_OPERATION_NOT_INITIALIZED);
207 	}
208 
209 	/*
210 	 * C_Sign must be called without intervening C_SignUpdate
211 	 * calls.
212 	 */
213 	if (session_p->sign.flags & CRYPTO_OPERATION_UPDATE) {
214 		/*
215 		 * C_Sign can not be used to terminate a multi-part
216 		 * operation, so we'll leave the active sign operation
217 		 * flag on and let the application continue with the
218 		 * sign update operation.
219 		 */
220 		REFRELE(session_p, ses_lock_held);
221 		return (CKR_FUNCTION_FAILED);
222 	}
223 
224 	if (session_p->sign.flags & CRYPTO_EMULATE) {
225 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
226 		    (ulDataLen > SLOT_MAX_INDATA_LEN(session_p))) {
227 			session_p->sign.flags |= CRYPTO_EMULATE_USING_SW;
228 			(void) pthread_mutex_unlock(&session_p->session_mutex);
229 
230 			rv = do_soft_hmac_sign(get_spp(&session_p->sign),
231 			    pData, ulDataLen,
232 			    pSignature, pulSignatureLen, OP_SINGLE);
233 			goto done;
234 		} else {
235 			free_soft_ctx(get_sp(&session_p->sign), OP_SIGN);
236 		}
237 	}
238 
239 	sign.cs_session = session_p->k_session;
240 	(void) pthread_mutex_unlock(&session_p->session_mutex);
241 	ses_lock_held = B_FALSE;
242 
243 	sign.cs_datalen = ulDataLen;
244 	sign.cs_databuf = (char *)pData;
245 	sign.cs_signlen = *pulSignatureLen;
246 	sign.cs_signbuf = (char *)pSignature;
247 
248 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN, &sign)) < 0) {
249 		if (errno != EINTR)
250 			break;
251 	}
252 	if (r < 0) {
253 		rv = CKR_FUNCTION_FAILED;
254 	} else {
255 		rv = crypto2pkcs11_error_number(sign.cs_return_value);
256 	}
257 
258 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
259 		*pulSignatureLen = sign.cs_signlen;
260 
261 done:
262 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
263 	    (rv == CKR_OK && pSignature == NULL)) {
264 		/*
265 		 * We will not terminate the active sign operation flag,
266 		 * when the application-supplied buffer is too small, or
267 		 * the application asks for the length of buffer to hold
268 		 * the signature.
269 		 */
270 		REFRELE(session_p, ses_lock_held);
271 		return (rv);
272 	}
273 
274 clean_exit:
275 	/*
276 	 * Terminates the active sign operation.
277 	 * Application needs to call C_SignInit again for next
278 	 * sign operation.
279 	 */
280 	(void) pthread_mutex_lock(&session_p->session_mutex);
281 
282 	REINIT_OPBUF(&session_p->sign);
283 	session_p->sign.flags = 0;
284 	ses_lock_held = B_TRUE;
285 	REFRELE(session_p, ses_lock_held);
286 
287 	return (rv);
288 }
289 
290 
291 CK_RV
292 C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
293     CK_ULONG ulPartLen)
294 {
295 
296 	CK_RV rv;
297 	kernel_session_t *session_p;
298 	boolean_t ses_lock_held = B_FALSE;
299 	crypto_sign_update_t sign_update;
300 	int r;
301 
302 	if (!kernel_initialized)
303 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
304 
305 	/* Obtain the session pointer */
306 	rv = handle2session(hSession, &session_p);
307 	if (rv != CKR_OK)
308 		return (rv);
309 
310 	if (pPart == NULL) {
311 		rv = CKR_ARGUMENTS_BAD;
312 		goto clean_exit;
313 	}
314 
315 	(void) pthread_mutex_lock(&session_p->session_mutex);
316 	ses_lock_held = B_TRUE;
317 
318 	/*
319 	 * Application must call C_SignInit before calling
320 	 * C_SignUpdate.
321 	 */
322 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
323 		REFRELE(session_p, ses_lock_held);
324 		return (CKR_OPERATION_NOT_INITIALIZED);
325 	}
326 
327 	session_p->sign.flags |= CRYPTO_OPERATION_UPDATE;
328 
329 	if (session_p->sign.flags & CRYPTO_EMULATE) {
330 		(void) pthread_mutex_unlock(&session_p->session_mutex);
331 		rv = emulate_update(session_p, pPart, ulPartLen, OP_SIGN);
332 		goto done;
333 	}
334 
335 	sign_update.su_session = session_p->k_session;
336 	(void) pthread_mutex_unlock(&session_p->session_mutex);
337 	ses_lock_held = B_FALSE;
338 
339 	sign_update.su_datalen = ulPartLen;
340 	sign_update.su_databuf = (char *)pPart;
341 
342 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_UPDATE, &sign_update)) < 0) {
343 		if (errno != EINTR)
344 			break;
345 	}
346 	if (r < 0) {
347 		rv = CKR_FUNCTION_FAILED;
348 	} else {
349 		rv = crypto2pkcs11_error_number(sign_update.su_return_value);
350 	}
351 
352 done:
353 	if (rv == CKR_OK) {
354 		REFRELE(session_p, ses_lock_held);
355 		return (rv);
356 	}
357 
358 clean_exit:
359 	/*
360 	 * After an error occurred, terminate the current sign
361 	 * operation by resetting the active and update flags.
362 	 */
363 	(void) pthread_mutex_lock(&session_p->session_mutex);
364 	REINIT_OPBUF(&session_p->sign);
365 	session_p->sign.flags = 0;
366 	ses_lock_held = B_TRUE;
367 	REFRELE(session_p, ses_lock_held);
368 
369 	return (rv);
370 }
371 
372 
373 CK_RV
374 C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
375     CK_ULONG_PTR pulSignatureLen)
376 {
377 
378 	CK_RV rv;
379 	kernel_session_t *session_p;
380 	boolean_t ses_lock_held = B_FALSE;
381 	crypto_sign_final_t sign_final;
382 	int r;
383 
384 	if (!kernel_initialized)
385 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
386 
387 	/* Obtain the session pointer */
388 	rv = handle2session(hSession, &session_p);
389 	if (rv != CKR_OK)
390 		return (rv);
391 
392 	if (pulSignatureLen == NULL) {
393 		rv = CKR_ARGUMENTS_BAD;
394 		goto clean_exit;
395 	}
396 
397 	(void) pthread_mutex_lock(&session_p->session_mutex);
398 	ses_lock_held = B_TRUE;
399 
400 	/*
401 	 * Application must call C_SignInit before calling
402 	 * C_SignFinal.
403 	 */
404 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
405 		REFRELE(session_p, ses_lock_held);
406 		return (CKR_OPERATION_NOT_INITIALIZED);
407 	}
408 
409 	/* The order of checks is important here */
410 	if (session_p->sign.flags & CRYPTO_EMULATE_USING_SW) {
411 		if (session_p->sign.flags & CRYPTO_EMULATE_UPDATE_DONE) {
412 			(void) pthread_mutex_unlock(&session_p->session_mutex);
413 			rv = do_soft_hmac_sign(get_spp(&session_p->sign),
414 			    NULL, 0, pSignature, pulSignatureLen, OP_FINAL);
415 		} else {
416 			/*
417 			 * We end up here if an earlier C_SignFinal() call
418 			 * took the C_Sign() path and it had returned
419 			 * CKR_BUFFER_TOO_SMALL.
420 			 */
421 			digest_buf_t *bufp = session_p->sign.context;
422 			(void) pthread_mutex_unlock(&session_p->session_mutex);
423 			if (bufp == NULL || bufp->buf == NULL) {
424 				rv = CKR_ARGUMENTS_BAD;
425 				goto clean_exit;
426 			}
427 			rv = do_soft_hmac_sign(get_spp(&session_p->sign),
428 			    bufp->buf, bufp->indata_len,
429 			    pSignature, pulSignatureLen, OP_SINGLE);
430 		}
431 		goto done;
432 	} else if (session_p->sign.flags & CRYPTO_EMULATE) {
433 		digest_buf_t *bufp = session_p->sign.context;
434 
435 		/*
436 		 * We are emulating a single-part operation now.
437 		 * So, clear the flag.
438 		 */
439 		session_p->sign.flags &= ~CRYPTO_OPERATION_UPDATE;
440 		if (bufp == NULL || bufp->buf == NULL) {
441 			rv = CKR_ARGUMENTS_BAD;
442 			goto clean_exit;
443 		}
444 		REFRELE(session_p, ses_lock_held);
445 		rv = C_Sign(hSession, bufp->buf, bufp->indata_len,
446 		    pSignature, pulSignatureLen);
447 		return (rv);
448 	}
449 
450 	sign_final.sf_session = session_p->k_session;
451 	(void) pthread_mutex_unlock(&session_p->session_mutex);
452 	ses_lock_held = B_FALSE;
453 
454 	sign_final.sf_signlen = *pulSignatureLen;
455 	sign_final.sf_signbuf = (char *)pSignature;
456 
457 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_FINAL, &sign_final)) < 0) {
458 		if (errno != EINTR)
459 			break;
460 	}
461 	if (r < 0) {
462 		rv = CKR_FUNCTION_FAILED;
463 	} else {
464 		rv = crypto2pkcs11_error_number(sign_final.sf_return_value);
465 	}
466 
467 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
468 		*pulSignatureLen = sign_final.sf_signlen;
469 
470 done:
471 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
472 	    (rv == CKR_OK && pSignature == NULL)) {
473 		/*
474 		 * We will not terminate the active sign operation flag,
475 		 * when the application-supplied buffer is too small, or
476 		 * the application asks for the length of buffer to hold
477 		 * the signature.
478 		 */
479 		REFRELE(session_p, ses_lock_held);
480 		return (rv);
481 	}
482 
483 clean_exit:
484 	/* Terminates the active sign operation */
485 	(void) pthread_mutex_lock(&session_p->session_mutex);
486 	REINIT_OPBUF(&session_p->sign);
487 	session_p->sign.flags = 0;
488 	ses_lock_held = B_TRUE;
489 	REFRELE(session_p, ses_lock_held);
490 
491 	return (rv);
492 }
493 
494 
495 CK_RV
496 C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
497     CK_OBJECT_HANDLE hKey)
498 {
499 
500 	CK_RV rv;
501 	kernel_session_t *session_p;
502 	kernel_object_t *key_p;
503 	boolean_t ses_lock_held = B_FALSE;
504 	crypto_sign_recover_init_t sr_init;
505 	crypto_mech_type_t k_mech_type;
506 	int r;
507 
508 	if (!kernel_initialized)
509 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
510 
511 	if (pMechanism == NULL) {
512 		return (CKR_ARGUMENTS_BAD);
513 	}
514 
515 	/* Get the kernel's internal mechanism number. */
516 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
517 	if (rv != CKR_OK)
518 		return (rv);
519 
520 	/* Obtain the session pointer. */
521 	rv = handle2session(hSession, &session_p);
522 	if (rv != CKR_OK)
523 		return (rv);
524 
525 	/* Obtain the object pointer. */
526 	HANDLE2OBJECT(hKey, key_p, rv);
527 	if (rv != CKR_OK) {
528 		REFRELE(session_p, ses_lock_held);
529 		return (rv);
530 	}
531 
532 	/*
533 	 * Check to see if key object is a RSA key and if it supports
534 	 * sign_recover.
535 	 */
536 	if (key_p->is_lib_obj && !((key_p->key_type == CKK_RSA) &&
537 	    (key_p->bool_attr_mask & SIGN_RECOVER_BOOL_ON))) {
538 		rv = CKR_KEY_TYPE_INCONSISTENT;
539 		goto clean_exit;
540 	}
541 
542 	(void) pthread_mutex_lock(&session_p->session_mutex);
543 	ses_lock_held = B_TRUE;
544 
545 	/*
546 	 * This active flag will remain ON until application calls
547 	 * C_SignRecover to actually obtain the signature.
548 	 */
549 	session_p->sign.flags = CRYPTO_OPERATION_ACTIVE;
550 
551 	/* Set up the key data */
552 	if (!key_p->is_lib_obj) {
553 		sr_init.ri_key.ck_format = CRYPTO_KEY_REFERENCE;
554 		sr_init.ri_key.ck_obj_id = key_p->k_handle;
555 	} else {
556 		if (key_p->key_type == CKK_RSA) {
557 			if (get_rsa_private_key(key_p, &sr_init.ri_key) !=
558 			    CKR_OK) {
559 				rv = CKR_HOST_MEMORY;
560 				goto clean_exit;
561 			}
562 		} else {
563 			rv = CKR_KEY_TYPE_INCONSISTENT;
564 			goto clean_exit;
565 		}
566 	}
567 
568 	sr_init.ri_session = session_p->k_session;
569 	(void) pthread_mutex_unlock(&session_p->session_mutex);
570 	ses_lock_held = B_FALSE;
571 	sr_init.ri_mech.cm_type = k_mech_type;
572 	sr_init.ri_mech.cm_param = pMechanism->pParameter;
573 	sr_init.ri_mech.cm_param_len = pMechanism->ulParameterLen;
574 
575 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_RECOVER_INIT, &sr_init)) < 0) {
576 		if (errno != EINTR)
577 			break;
578 	}
579 	if (r < 0) {
580 		rv = CKR_FUNCTION_FAILED;
581 	} else {
582 		rv = crypto2pkcs11_error_number(sr_init.ri_return_value);
583 	}
584 
585 	if (key_p->is_lib_obj) {
586 		free_key_attributes(&sr_init.ri_key);
587 	}
588 
589 	if (rv != CKR_OK) {
590 		(void) pthread_mutex_lock(&session_p->session_mutex);
591 		session_p->sign.flags &= ~CRYPTO_OPERATION_ACTIVE;
592 		ses_lock_held = B_TRUE;
593 	}
594 
595 clean_exit:
596 	OBJ_REFRELE(key_p);
597 	REFRELE(session_p, ses_lock_held);
598 	return (rv);
599 }
600 
601 
602 CK_RV
603 C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
604     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
605 {
606 
607 	CK_RV rv;
608 	kernel_session_t *session_p;
609 	boolean_t ses_lock_held = B_FALSE;
610 	crypto_sign_recover_t sign_recover;
611 	int r;
612 
613 	if (!kernel_initialized)
614 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
615 
616 	/* Obatin the session pointer */
617 	rv = handle2session(hSession, &session_p);
618 	if (rv != CKR_OK)
619 		return (rv);
620 
621 	if (pulSignatureLen == NULL) {
622 		rv = CKR_ARGUMENTS_BAD;
623 		goto clean_exit;
624 	}
625 
626 	(void) pthread_mutex_lock(&session_p->session_mutex);
627 	ses_lock_held = B_TRUE;
628 
629 	/* Application must call C_SignInit before calling C_Sign. */
630 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
631 		REFRELE(session_p, ses_lock_held);
632 		return (CKR_OPERATION_NOT_INITIALIZED);
633 	}
634 
635 	sign_recover.sr_session = session_p->k_session;
636 	(void) pthread_mutex_unlock(&session_p->session_mutex);
637 	ses_lock_held = B_FALSE;
638 
639 	sign_recover.sr_datalen = ulDataLen;
640 	sign_recover.sr_databuf = (char *)pData;
641 	sign_recover.sr_signlen = *pulSignatureLen;
642 	sign_recover.sr_signbuf = (char *)pSignature;
643 
644 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_RECOVER, &sign_recover)) < 0) {
645 		if (errno != EINTR)
646 			break;
647 	}
648 	if (r < 0) {
649 		rv = CKR_FUNCTION_FAILED;
650 	} else {
651 		rv = crypto2pkcs11_error_number(sign_recover.sr_return_value);
652 	}
653 
654 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
655 		*pulSignatureLen = sign_recover.sr_signlen;
656 
657 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
658 	    (rv == CKR_OK && pSignature == NULL)) {
659 		/*
660 		 * We will not terminate the active sign operation flag,
661 		 * when the application-supplied buffer is too small, or
662 		 * the application asks for the length of buffer to hold
663 		 * the signature.
664 		 */
665 		REFRELE(session_p, ses_lock_held);
666 		return (rv);
667 	}
668 
669 clean_exit:
670 	/*
671 	 * Terminates the active sign operation.
672 	 * Application needs to call C_SignInit again for next
673 	 * sign operation.
674 	 */
675 	(void) pthread_mutex_lock(&session_p->session_mutex);
676 	session_p->sign.flags = 0;
677 	ses_lock_held = B_TRUE;
678 	REFRELE(session_p, ses_lock_held);
679 
680 	return (rv);
681 }
682