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