xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelVerify.c (revision 4df55fde49134f9735f84011f23a767c75e393c7)
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 <stdlib.h>
28 #include <errno.h>
29 #include <sys/crypto/ioctl.h>
30 #include <security/cryptoki.h>
31 #include "kernelGlobal.h"
32 #include "kernelObject.h"
33 #include "kernelSession.h"
34 #include "kernelEmulate.h"
35 
36 CK_RV
C_VerifyInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)37 C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
38     CK_OBJECT_HANDLE hKey)
39 {
40 	CK_RV rv;
41 	kernel_session_t *session_p;
42 	kernel_object_t	*key_p;
43 	boolean_t ses_lock_held = B_FALSE;
44 	crypto_verify_init_t verify_init;
45 	crypto_mech_type_t k_mech_type;
46 	int r;
47 
48 	if (!kernel_initialized)
49 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
50 
51 	if (pMechanism == NULL) {
52 		return (CKR_ARGUMENTS_BAD);
53 	}
54 
55 	/* Get the kernel's internal mechanism number. */
56 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
57 	if (rv != CKR_OK)
58 		return (rv);
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 verification. */
73 	if (key_p->is_lib_obj && !(key_p->bool_attr_mask & VERIFY_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_Verify or C_VerifyFinal to verify a signature on data.
84 	 */
85 	session_p->verify.flags = CRYPTO_OPERATION_ACTIVE;
86 
87 	if (!key_p->is_lib_obj) {
88 		verify_init.vi_key.ck_format = CRYPTO_KEY_REFERENCE;
89 		verify_init.vi_key.ck_obj_id = key_p->k_handle;
90 	} else {
91 		if (key_p->class == CKO_SECRET_KEY) {
92 			verify_init.vi_key.ck_format = CRYPTO_KEY_RAW;
93 			verify_init.vi_key.ck_data =
94 			    get_symmetric_key_value(key_p);
95 			if (verify_init.vi_key.ck_data == NULL) {
96 				rv = CKR_HOST_MEMORY;
97 				goto clean_exit;
98 			}
99 			verify_init.vi_key.ck_length =
100 			    OBJ_SEC(key_p)->sk_value_len << 3;
101 
102 		} else if (key_p->key_type == CKK_RSA) {
103 			if (get_rsa_public_key(key_p, &verify_init.vi_key) !=
104 			    CKR_OK) {
105 				rv = CKR_HOST_MEMORY;
106 				goto clean_exit;
107 			}
108 		} else if (key_p->key_type == CKK_DSA) {
109 			if (get_dsa_public_key(key_p, &verify_init.vi_key) !=
110 			    CKR_OK) {
111 				rv = CKR_HOST_MEMORY;
112 				goto clean_exit;
113 			}
114 		} else if (key_p->key_type == CKK_EC) {
115 			if (get_ec_public_key(key_p, &verify_init.vi_key) !=
116 			    CKR_OK) {
117 				rv = CKR_HOST_MEMORY;
118 				goto clean_exit;
119 			}
120 		} else {
121 			rv = CKR_KEY_TYPE_INCONSISTENT;
122 			goto clean_exit;
123 		}
124 	}
125 
126 	verify_init.vi_session = session_p->k_session;
127 	(void) pthread_mutex_unlock(&session_p->session_mutex);
128 	ses_lock_held = B_FALSE;
129 	verify_init.vi_mech.cm_type = k_mech_type;
130 	verify_init.vi_mech.cm_param = pMechanism->pParameter;
131 	verify_init.vi_mech.cm_param_len = pMechanism->ulParameterLen;
132 
133 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_INIT, &verify_init)) < 0) {
134 		if (errno != EINTR)
135 			break;
136 	}
137 	if (r < 0) {
138 		rv = CKR_FUNCTION_FAILED;
139 	} else {
140 		rv = crypto2pkcs11_error_number(verify_init.vi_return_value);
141 	}
142 
143 	if (rv == CKR_OK && SLOT_HAS_LIMITED_HMAC(session_p) &&
144 	    is_hmac(pMechanism->mechanism)) {
145 		if (key_p->is_lib_obj && key_p->class == CKO_SECRET_KEY) {
146 			(void) pthread_mutex_lock(&session_p->session_mutex);
147 			session_p->verify.flags |= CRYPTO_EMULATE;
148 			(void) pthread_mutex_unlock(&session_p->session_mutex);
149 			rv = emulate_init(session_p, pMechanism,
150 			    &(verify_init.vi_key), OP_VERIFY);
151 		} else {
152 			rv = CKR_FUNCTION_FAILED;
153 		}
154 	}
155 
156 	/* free the memory allocated for verify_init.vi_key */
157 	if (key_p->is_lib_obj) {
158 		if (key_p->class == CKO_SECRET_KEY) {
159 			free(verify_init.vi_key.ck_data);
160 		} else {
161 			free_key_attributes(&verify_init.vi_key);
162 		}
163 	}
164 
165 	if (rv != CKR_OK) {
166 		(void) pthread_mutex_lock(&session_p->session_mutex);
167 		session_p->verify.flags &= ~CRYPTO_OPERATION_ACTIVE;
168 		ses_lock_held = B_TRUE;
169 	}
170 
171 clean_exit:
172 	OBJ_REFRELE(key_p);
173 	REFRELE(session_p, ses_lock_held);
174 	return (rv);
175 }
176 
177 
178 CK_RV
C_Verify(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)179 C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
180     CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
181 {
182 
183 	CK_RV rv;
184 	kernel_session_t *session_p;
185 	boolean_t ses_lock_held = B_FALSE;
186 	crypto_verify_t verify;
187 	int r;
188 
189 	if (!kernel_initialized)
190 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
191 
192 	/* Obatin the session pointer */
193 	rv = handle2session(hSession, &session_p);
194 	if (rv != CKR_OK)
195 		return (rv);
196 
197 	(void) pthread_mutex_lock(&session_p->session_mutex);
198 	ses_lock_held = B_TRUE;
199 
200 	/* Application must call C_VerifyInit before calling C_Verify. */
201 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
202 		REFRELE(session_p, ses_lock_held);
203 		return (CKR_OPERATION_NOT_INITIALIZED);
204 	}
205 
206 	/*
207 	 * C_Verify must be called without intervening C_VerifyUpdate
208 	 * calls.
209 	 */
210 	if (session_p->verify.flags & CRYPTO_OPERATION_UPDATE) {
211 		/*
212 		 * C_Verify can not be used to terminate a multi-part
213 		 * operation, so we'll leave the active verify operation
214 		 * flag on and let the application continue with the
215 		 * verify update operation.
216 		 */
217 		REFRELE(session_p, ses_lock_held);
218 		return (CKR_FUNCTION_FAILED);
219 	}
220 
221 	if (session_p->verify.flags & CRYPTO_EMULATE) {
222 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
223 		    (ulDataLen > SLOT_HMAC_MAX_INDATA_LEN(session_p))) {
224 			session_p->verify.flags |= CRYPTO_EMULATE_USING_SW;
225 			(void) pthread_mutex_unlock(&session_p->session_mutex);
226 			ses_lock_held = B_FALSE;
227 
228 			rv = do_soft_hmac_verify(get_spp(&session_p->verify),
229 			    pData, ulDataLen,
230 			    pSignature, ulSignatureLen, OP_SINGLE);
231 			goto clean_exit;
232 		} else {
233 			free_soft_ctx(get_sp(&session_p->verify), OP_VERIFY);
234 		}
235 	}
236 
237 	verify.cv_session = session_p->k_session;
238 	(void) pthread_mutex_unlock(&session_p->session_mutex);
239 	ses_lock_held = B_FALSE;
240 	verify.cv_datalen = ulDataLen;
241 	verify.cv_databuf = (char *)pData;
242 	verify.cv_signlen = ulSignatureLen;
243 	verify.cv_signbuf = (char *)pSignature;
244 
245 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY, &verify)) < 0) {
246 		if (errno != EINTR)
247 			break;
248 	}
249 	if (r < 0) {
250 		rv = CKR_FUNCTION_FAILED;
251 	} else {
252 		rv = crypto2pkcs11_error_number(verify.cv_return_value);
253 	}
254 
255 clean_exit:
256 	/*
257 	 * Always terminate the active verify operation.
258 	 * Application needs to call C_VerifyInit again for next
259 	 * verify operation.
260 	 */
261 	(void) pthread_mutex_lock(&session_p->session_mutex);
262 	ses_lock_held = B_TRUE;
263 
264 	REINIT_OPBUF(&session_p->verify);
265 	session_p->verify.flags = 0;
266 	REFRELE(session_p, ses_lock_held);
267 
268 	return (rv);
269 }
270 
271 
272 CK_RV
C_VerifyUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)273 C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
274     CK_ULONG ulPartLen)
275 {
276 
277 	CK_RV rv;
278 	kernel_session_t *session_p;
279 	boolean_t ses_lock_held = B_FALSE;
280 	crypto_verify_update_t verify_update;
281 	int r;
282 
283 	if (!kernel_initialized)
284 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
285 
286 	/* Obtain the session pointer */
287 	rv = handle2session(hSession, &session_p);
288 	if (rv != CKR_OK)
289 		return (rv);
290 
291 	if (pPart == NULL) {
292 		rv = CKR_ARGUMENTS_BAD;
293 		goto clean_exit;
294 	}
295 
296 	(void) pthread_mutex_lock(&session_p->session_mutex);
297 	ses_lock_held = B_TRUE;
298 
299 	/*
300 	 * Application must call C_VerifyInit before calling
301 	 * C_VerifyUpdate.
302 	 */
303 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
304 		REFRELE(session_p, ses_lock_held);
305 		return (CKR_OPERATION_NOT_INITIALIZED);
306 	}
307 
308 	session_p->verify.flags |= CRYPTO_OPERATION_UPDATE;
309 
310 	if (session_p->verify.flags & CRYPTO_EMULATE) {
311 		(void) pthread_mutex_unlock(&session_p->session_mutex);
312 		ses_lock_held = B_FALSE;
313 		rv = emulate_update(session_p, pPart, ulPartLen, OP_VERIFY);
314 		goto done;
315 	}
316 
317 	verify_update.vu_session = session_p->k_session;
318 	(void) pthread_mutex_unlock(&session_p->session_mutex);
319 	ses_lock_held = B_FALSE;
320 
321 	verify_update.vu_datalen = ulPartLen;
322 	verify_update.vu_databuf = (char *)pPart;
323 
324 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_UPDATE,
325 	    &verify_update)) < 0) {
326 		if (errno != EINTR)
327 			break;
328 	}
329 	if (r < 0) {
330 		rv = CKR_FUNCTION_FAILED;
331 	} else {
332 		rv = crypto2pkcs11_error_number(verify_update.vu_return_value);
333 	}
334 
335 done:
336 	if (rv == CKR_OK) {
337 		REFRELE(session_p, ses_lock_held);
338 		return (rv);
339 	}
340 
341 clean_exit:
342 	/*
343 	 * After an error occurred, terminate the current verify
344 	 * operation by resetting the active and update flags.
345 	 */
346 	(void) pthread_mutex_lock(&session_p->session_mutex);
347 	ses_lock_held = B_TRUE;
348 	REINIT_OPBUF(&session_p->verify);
349 	session_p->verify.flags = 0;
350 	REFRELE(session_p, ses_lock_held);
351 
352 	return (rv);
353 }
354 
355 
356 CK_RV
C_VerifyFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)357 C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
358     CK_ULONG ulSignatureLen)
359 {
360 
361 	CK_RV rv;
362 	kernel_session_t *session_p;
363 	boolean_t ses_lock_held = B_FALSE;
364 	crypto_verify_final_t verify_final;
365 	int r;
366 
367 	if (!kernel_initialized)
368 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
369 
370 	/* Obtain the session pointer */
371 	rv = handle2session(hSession, &session_p);
372 	if (rv != CKR_OK)
373 		return (rv);
374 
375 	(void) pthread_mutex_lock(&session_p->session_mutex);
376 	ses_lock_held = B_TRUE;
377 
378 	/*
379 	 * Application must call C_VerifyInit before calling
380 	 * C_VerifyFinal.
381 	 */
382 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
383 		REFRELE(session_p, ses_lock_held);
384 		return (CKR_OPERATION_NOT_INITIALIZED);
385 	}
386 
387 	/* The order of checks is important here */
388 	if (session_p->verify.flags & CRYPTO_EMULATE_USING_SW) {
389 		if (session_p->verify.flags & CRYPTO_EMULATE_UPDATE_DONE) {
390 			(void) pthread_mutex_unlock(&session_p->session_mutex);
391 			ses_lock_held = B_FALSE;
392 			rv = do_soft_hmac_verify(get_spp(&session_p->verify),
393 			    NULL, 0, pSignature, ulSignatureLen,
394 			    OP_FINAL);
395 		} else {
396 			/*
397 			 * We should not end up here even if an earlier
398 			 * C_VerifyFinal() call took the C_Verify() path as
399 			 * it never returns CKR_BUFFER_TOO_SMALL.
400 			 */
401 			(void) pthread_mutex_unlock(&session_p->session_mutex);
402 			ses_lock_held = B_FALSE;
403 			rv = CKR_ARGUMENTS_BAD;
404 		}
405 		goto clean_exit;
406 	} else if (session_p->verify.flags & CRYPTO_EMULATE) {
407 		digest_buf_t *bufp = session_p->verify.context;
408 
409 		/*
410 		 * We are emulating a single-part operation now.
411 		 * So, clear the flag.
412 		 */
413 		session_p->verify.flags &= ~CRYPTO_OPERATION_UPDATE;
414 		if (bufp == NULL || bufp->buf == NULL) {
415 			rv = CKR_ARGUMENTS_BAD;
416 			goto clean_exit;
417 		}
418 		REFRELE(session_p, ses_lock_held);
419 		rv = C_Verify(hSession, bufp->buf, bufp->indata_len,
420 		    pSignature, ulSignatureLen);
421 		return (rv);
422 	}
423 
424 	verify_final.vf_session = session_p->k_session;
425 	(void) pthread_mutex_unlock(&session_p->session_mutex);
426 	ses_lock_held = B_FALSE;
427 
428 	verify_final.vf_signlen = ulSignatureLen;
429 	verify_final.vf_signbuf = (char *)pSignature;
430 
431 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_FINAL, &verify_final)) < 0) {
432 		if (errno != EINTR)
433 			break;
434 	}
435 	if (r < 0) {
436 		rv = CKR_FUNCTION_FAILED;
437 	} else {
438 		rv = crypto2pkcs11_error_number(verify_final.vf_return_value);
439 	}
440 
441 clean_exit:
442 	/* Always terminate the active verify operation */
443 	(void) pthread_mutex_lock(&session_p->session_mutex);
444 	ses_lock_held = B_TRUE;
445 	REINIT_OPBUF(&session_p->verify);
446 	session_p->verify.flags = 0;
447 	REFRELE(session_p, ses_lock_held);
448 
449 	return (rv);
450 }
451 
452 
453 CK_RV
C_VerifyRecoverInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)454 C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
455     CK_OBJECT_HANDLE hKey)
456 {
457 
458 	CK_RV rv;
459 	kernel_session_t *session_p;
460 	kernel_object_t	*key_p;
461 	boolean_t ses_lock_held = B_FALSE;
462 	crypto_verify_recover_init_t vr_init;
463 	crypto_mech_type_t k_mech_type;
464 	int r;
465 
466 	if (!kernel_initialized)
467 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
468 
469 	if (pMechanism == NULL) {
470 		return (CKR_ARGUMENTS_BAD);
471 	}
472 
473 	/* Get the kernel's internal mechanism number. */
474 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
475 	if (rv != CKR_OK)
476 		return (rv);
477 
478 	/* Obtain the session pointer. */
479 	rv = handle2session(hSession, &session_p);
480 	if (rv != CKR_OK)
481 		return (rv);
482 
483 	/* Obtain the object pointer. */
484 	HANDLE2OBJECT(hKey, key_p, rv);
485 	if (rv != CKR_OK) {
486 		REFRELE(session_p, ses_lock_held);
487 		return (rv);
488 	}
489 
490 	/*
491 	 * Check to see if key object is a RSA key and if it supports
492 	 * verify_recover.
493 	 */
494 	if (key_p->is_lib_obj && !((key_p->key_type == CKK_RSA) &&
495 	    (key_p->bool_attr_mask & VERIFY_RECOVER_BOOL_ON))) {
496 		rv = CKR_KEY_TYPE_INCONSISTENT;
497 		goto clean_exit;
498 	}
499 
500 	(void) pthread_mutex_lock(&session_p->session_mutex);
501 	ses_lock_held = B_TRUE;
502 
503 	/*
504 	 * This active flag will remain ON until application calls
505 	 * C_VerifyRecover to verify a signature on data.
506 	 */
507 	session_p->verify.flags = CRYPTO_OPERATION_ACTIVE;
508 
509 	/* Set up the key data */
510 	if (!key_p->is_lib_obj) {
511 		vr_init.ri_key.ck_format = CRYPTO_KEY_REFERENCE;
512 		vr_init.ri_key.ck_obj_id = key_p->k_handle;
513 	} else {
514 		if (key_p->key_type == CKK_RSA) {
515 			if (get_rsa_public_key(key_p, &vr_init.ri_key) !=
516 			    CKR_OK) {
517 				rv = CKR_HOST_MEMORY;
518 				goto clean_exit;
519 			}
520 		} else {
521 			rv = CKR_KEY_TYPE_INCONSISTENT;
522 			goto clean_exit;
523 		}
524 	}
525 
526 	vr_init.ri_session = session_p->k_session;
527 	(void) pthread_mutex_unlock(&session_p->session_mutex);
528 	ses_lock_held = B_FALSE;
529 	vr_init.ri_mech.cm_type = k_mech_type;
530 	vr_init.ri_mech.cm_param = pMechanism->pParameter;
531 	vr_init.ri_mech.cm_param_len = pMechanism->ulParameterLen;
532 
533 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_RECOVER_INIT,
534 	    &vr_init)) < 0) {
535 		if (errno != EINTR)
536 			break;
537 	}
538 	if (r < 0) {
539 		rv = CKR_FUNCTION_FAILED;
540 	} else {
541 		rv = crypto2pkcs11_error_number(vr_init.ri_return_value);
542 	}
543 
544 	/* free the memory allocated for vr_init.ri_key */
545 	if (key_p->is_lib_obj) {
546 		free_key_attributes(&vr_init.ri_key);
547 	}
548 
549 	if (rv != CKR_OK) {
550 		(void) pthread_mutex_lock(&session_p->session_mutex);
551 		session_p->verify.flags &= ~CRYPTO_OPERATION_ACTIVE;
552 		ses_lock_held = B_TRUE;
553 	}
554 
555 clean_exit:
556 	OBJ_REFRELE(key_p);
557 	REFRELE(session_p, ses_lock_held);
558 	return (rv);
559 }
560 
561 
562 CK_RV
C_VerifyRecover(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)563 C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
564     CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
565 {
566 
567 	CK_RV rv;
568 	kernel_session_t *session_p;
569 	boolean_t ses_lock_held = B_FALSE;
570 	crypto_verify_recover_t verify_recover;
571 	int r;
572 
573 	if (!kernel_initialized)
574 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
575 
576 	/* Obtain the session pointer */
577 	rv = handle2session(hSession, &session_p);
578 	if (rv != CKR_OK)
579 		return (rv);
580 
581 	if (pSignature == NULL || pulDataLen == NULL) {
582 		rv = CKR_ARGUMENTS_BAD;
583 		goto clean_exit;
584 	}
585 
586 	(void) pthread_mutex_lock(&session_p->session_mutex);
587 	ses_lock_held = B_TRUE;
588 
589 	/*
590 	 * Application must call C_VerifyRecoverInit before calling
591 	 * C_Verify.
592 	 */
593 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
594 		REFRELE(session_p, ses_lock_held);
595 		return (CKR_OPERATION_NOT_INITIALIZED);
596 	}
597 
598 	verify_recover.vr_session = session_p->k_session;
599 	(void) pthread_mutex_unlock(&session_p->session_mutex);
600 	ses_lock_held = B_FALSE;
601 	verify_recover.vr_signlen = ulSignatureLen;
602 	verify_recover.vr_signbuf = (char *)pSignature;
603 	verify_recover.vr_datalen = *pulDataLen;
604 	verify_recover.vr_databuf = (char *)pData;
605 
606 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_RECOVER,
607 	    &verify_recover)) < 0) {
608 		if (errno != EINTR)
609 			break;
610 	}
611 	if (r < 0) {
612 		rv = CKR_FUNCTION_FAILED;
613 	} else {
614 		rv = crypto2pkcs11_error_number(
615 		    verify_recover.vr_return_value);
616 	}
617 
618 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
619 		*pulDataLen = verify_recover.vr_datalen;
620 
621 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
622 	    (rv == CKR_OK && pData == NULL)) {
623 		/*
624 		 * We will not terminate the active verify operation flag,
625 		 * when the application-supplied buffer is too small, or
626 		 * the application asks for the length of buffer to hold
627 		 * the recovered data.
628 		 */
629 		REFRELE(session_p, ses_lock_held);
630 		return (rv);
631 	}
632 
633 clean_exit:
634 	/*
635 	 * Always terminate the active verify operation.
636 	 * Application needs to call C_VerifyInit again for next
637 	 * verify operation.
638 	 */
639 	(void) pthread_mutex_lock(&session_p->session_mutex);
640 	session_p->verify.flags = 0;
641 	ses_lock_held = B_TRUE;
642 	REFRELE(session_p, ses_lock_held);
643 
644 	return (rv);
645 }
646