xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelVerify.c (revision 9a016c63ca347047a236dff12f0da83aac8981d1)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 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 <stdlib.h>
30 #include <errno.h>
31 #include <sys/crypto/ioctl.h>
32 #include <security/cryptoki.h>
33 #include "kernelGlobal.h"
34 #include "kernelObject.h"
35 #include "kernelSession.h"
36 
37 CK_RV
38 C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
39     CK_OBJECT_HANDLE hKey)
40 {
41 
42 	CK_RV rv;
43 	kernel_session_t *session_p;
44 	kernel_object_t	*key_p;
45 	boolean_t ses_lock_held = B_FALSE;
46 	crypto_verify_init_t verify_init;
47 	crypto_mech_type_t k_mech_type;
48 	int r;
49 
50 	if (!kernel_initialized)
51 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
52 
53 	if (pMechanism == NULL) {
54 		return (CKR_ARGUMENTS_BAD);
55 	}
56 
57 	/* Get the kernel's internal mechanism number. */
58 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
59 	if (rv != CKR_OK)
60 		return (rv);
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 verification. */
75 	if (key_p->is_lib_obj && !(key_p->bool_attr_mask & VERIFY_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_Verify or C_VerifyFinal to verify a signature on data.
86 	 */
87 	session_p->verify.flags = CRYPTO_OPERATION_ACTIVE;
88 
89 	if (!key_p->is_lib_obj) {
90 		verify_init.vi_key.ck_format = CRYPTO_KEY_REFERENCE;
91 		verify_init.vi_key.ck_obj_id = key_p->k_handle;
92 	} else {
93 		if (key_p->class == CKO_SECRET_KEY) {
94 			verify_init.vi_key.ck_format = CRYPTO_KEY_RAW;
95 			verify_init.vi_key.ck_data =
96 			    get_symmetric_key_value(key_p);
97 			if (verify_init.vi_key.ck_data == NULL) {
98 				rv = CKR_HOST_MEMORY;
99 				goto clean_exit;
100 			}
101 			verify_init.vi_key.ck_length =
102 			    OBJ_SEC(key_p)->sk_value_len << 3;
103 
104 		} else if (key_p->key_type == CKK_RSA) {
105 			if (get_rsa_public_key(key_p, &verify_init.vi_key) !=
106 			    CKR_OK) {
107 				rv = CKR_HOST_MEMORY;
108 				goto clean_exit;
109 			}
110 		} else if (key_p->key_type == CKK_DSA) {
111 			if (get_dsa_public_key(key_p, &verify_init.vi_key) !=
112 			    CKR_OK) {
113 				rv = CKR_HOST_MEMORY;
114 				goto clean_exit;
115 			}
116 		} else {
117 			rv = CKR_KEY_TYPE_INCONSISTENT;
118 			goto clean_exit;
119 		}
120 	}
121 
122 	verify_init.vi_session = session_p->k_session;
123 	(void) pthread_mutex_unlock(&session_p->session_mutex);
124 	ses_lock_held = B_FALSE;
125 	verify_init.vi_mech.cm_type = k_mech_type;
126 	verify_init.vi_mech.cm_param = pMechanism->pParameter;
127 	verify_init.vi_mech.cm_param_len = pMechanism->ulParameterLen;
128 
129 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_INIT, &verify_init)) < 0) {
130 		if (errno != EINTR)
131 			break;
132 	}
133 	if (r < 0) {
134 		rv = CKR_FUNCTION_FAILED;
135 	} else {
136 		rv = crypto2pkcs11_error_number(verify_init.vi_return_value);
137 	}
138 
139 	/* free the memory allocated for sign_init.si_key */
140 	if (key_p->is_lib_obj) {
141 		if (key_p->class == CKO_SECRET_KEY) {
142 			free(verify_init.vi_key.ck_data);
143 		} else if (key_p->key_type == CKK_RSA) {
144 			free_key_attributes(&verify_init.vi_key);
145 		}
146 	}
147 
148 	if (rv != CKR_OK) {
149 		(void) pthread_mutex_lock(&session_p->session_mutex);
150 		session_p->verify.flags &= ~CRYPTO_OPERATION_ACTIVE;
151 		ses_lock_held = B_TRUE;
152 	}
153 
154 clean_exit:
155 	OBJ_REFRELE(key_p);
156 	REFRELE(session_p, ses_lock_held);
157 	return (rv);
158 }
159 
160 
161 CK_RV
162 C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
163     CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
164 {
165 
166 	CK_RV rv;
167 	kernel_session_t *session_p;
168 	boolean_t ses_lock_held = B_FALSE;
169 	crypto_verify_t verify;
170 	int r;
171 
172 	if (!kernel_initialized)
173 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
174 
175 	/* Obatin the session pointer */
176 	rv = handle2session(hSession, &session_p);
177 	if (rv != CKR_OK)
178 		return (rv);
179 
180 	(void) pthread_mutex_lock(&session_p->session_mutex);
181 	ses_lock_held = B_TRUE;
182 
183 	/* Application must call C_VerifyInit before calling C_Verify. */
184 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
185 		REFRELE(session_p, ses_lock_held);
186 		return (CKR_OPERATION_NOT_INITIALIZED);
187 	}
188 
189 	/*
190 	 * C_Verify must be called without intervening C_VerifyUpdate
191 	 * calls.
192 	 */
193 	if (session_p->verify.flags & CRYPTO_OPERATION_UPDATE) {
194 		/*
195 		 * C_Verify can not be used to terminate a multi-part
196 		 * operation, so we'll leave the active verify operation
197 		 * flag on and let the application continue with the
198 		 * verify update operation.
199 		 */
200 		REFRELE(session_p, ses_lock_held);
201 		return (CKR_FUNCTION_FAILED);
202 	}
203 
204 	verify.cv_session = session_p->k_session;
205 	(void) pthread_mutex_unlock(&session_p->session_mutex);
206 	ses_lock_held = B_FALSE;
207 	verify.cv_datalen = ulDataLen;
208 	verify.cv_databuf = (char *)pData;
209 	verify.cv_signlen = ulSignatureLen;
210 	verify.cv_signbuf = (char *)pSignature;
211 
212 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY, &verify)) < 0) {
213 		if (errno != EINTR)
214 			break;
215 	}
216 	if (r < 0) {
217 		rv = CKR_FUNCTION_FAILED;
218 	} else {
219 		rv = crypto2pkcs11_error_number(verify.cv_return_value);
220 	}
221 
222 clean_exit:
223 	/*
224 	 * Always terminate the active verify operation.
225 	 * Application needs to call C_VerifyInit again for next
226 	 * verify operation.
227 	 */
228 	(void) pthread_mutex_lock(&session_p->session_mutex);
229 	session_p->verify.flags = 0;
230 	ses_lock_held = B_TRUE;
231 	REFRELE(session_p, ses_lock_held);
232 
233 	return (rv);
234 }
235 
236 
237 CK_RV
238 C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
239     CK_ULONG ulPartLen)
240 {
241 
242 	CK_RV rv;
243 	kernel_session_t *session_p;
244 	boolean_t ses_lock_held = B_FALSE;
245 	crypto_verify_update_t verify_update;
246 	int r;
247 
248 	if (!kernel_initialized)
249 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
250 
251 	/* Obtain the session pointer */
252 	rv = handle2session(hSession, &session_p);
253 	if (rv != CKR_OK)
254 		return (rv);
255 
256 	if (pPart == NULL) {
257 		rv = CKR_ARGUMENTS_BAD;
258 		goto clean_exit;
259 	}
260 
261 	(void) pthread_mutex_lock(&session_p->session_mutex);
262 	ses_lock_held = B_TRUE;
263 
264 	/*
265 	 * Application must call C_VerifyInit before calling
266 	 * C_VerifyUpdate.
267 	 */
268 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
269 		REFRELE(session_p, ses_lock_held);
270 		return (CKR_OPERATION_NOT_INITIALIZED);
271 	}
272 
273 	session_p->verify.flags |= CRYPTO_OPERATION_UPDATE;
274 
275 	verify_update.vu_session = session_p->k_session;
276 	(void) pthread_mutex_unlock(&session_p->session_mutex);
277 	ses_lock_held = B_FALSE;
278 
279 	verify_update.vu_datalen = ulPartLen;
280 	verify_update.vu_databuf = (char *)pPart;
281 
282 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_UPDATE,
283 	    &verify_update)) < 0) {
284 		if (errno != EINTR)
285 			break;
286 	}
287 	if (r < 0) {
288 		rv = CKR_FUNCTION_FAILED;
289 	} else {
290 		rv = crypto2pkcs11_error_number(verify_update.vu_return_value);
291 	}
292 
293 	if (rv == CKR_OK) {
294 		REFRELE(session_p, ses_lock_held);
295 		return (rv);
296 	}
297 
298 clean_exit:
299 	/*
300 	 * After an error occurred, terminate the current verify
301 	 * operation by resetting the active and update flags.
302 	 */
303 	(void) pthread_mutex_lock(&session_p->session_mutex);
304 	session_p->verify.flags = 0;
305 	ses_lock_held = B_TRUE;
306 	REFRELE(session_p, ses_lock_held);
307 
308 	return (rv);
309 }
310 
311 
312 CK_RV
313 C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
314     CK_ULONG ulSignatureLen)
315 {
316 
317 	CK_RV rv;
318 	kernel_session_t *session_p;
319 	boolean_t ses_lock_held = B_FALSE;
320 	crypto_verify_final_t verify_final;
321 	int r;
322 
323 	if (!kernel_initialized)
324 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
325 
326 	/* Obtain the session pointer */
327 	rv = handle2session(hSession, &session_p);
328 	if (rv != CKR_OK)
329 		return (rv);
330 
331 	(void) pthread_mutex_lock(&session_p->session_mutex);
332 	ses_lock_held = B_TRUE;
333 
334 	/*
335 	 * Application must call C_VerifyInit before calling
336 	 * C_VerifyFinal.
337 	 */
338 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
339 		REFRELE(session_p, ses_lock_held);
340 		return (CKR_OPERATION_NOT_INITIALIZED);
341 	}
342 
343 	verify_final.vf_session = session_p->k_session;
344 	(void) pthread_mutex_unlock(&session_p->session_mutex);
345 	ses_lock_held = B_FALSE;
346 
347 	verify_final.vf_signlen = ulSignatureLen;
348 	verify_final.vf_signbuf = (char *)pSignature;
349 
350 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_FINAL, &verify_final)) < 0) {
351 		if (errno != EINTR)
352 			break;
353 	}
354 	if (r < 0) {
355 		rv = CKR_FUNCTION_FAILED;
356 	} else {
357 		rv = crypto2pkcs11_error_number(verify_final.vf_return_value);
358 	}
359 
360 clean_exit:
361 	/* Always terminate the active verify operation */
362 	(void) pthread_mutex_lock(&session_p->session_mutex);
363 	session_p->verify.flags = 0;
364 	ses_lock_held = B_TRUE;
365 	REFRELE(session_p, ses_lock_held);
366 
367 	return (rv);
368 }
369 
370 
371 CK_RV
372 C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
373     CK_OBJECT_HANDLE hKey)
374 {
375 
376 	CK_RV rv;
377 	kernel_session_t *session_p;
378 	kernel_object_t	*key_p;
379 	boolean_t ses_lock_held = B_FALSE;
380 	crypto_verify_recover_init_t vr_init;
381 	crypto_mech_type_t k_mech_type;
382 	int r;
383 
384 	if (!kernel_initialized)
385 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
386 
387 	if (pMechanism == NULL) {
388 		return (CKR_ARGUMENTS_BAD);
389 	}
390 
391 	/* Get the kernel's internal mechanism number. */
392 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
393 	if (rv != CKR_OK)
394 		return (rv);
395 
396 	/* Obtain the session pointer. */
397 	rv = handle2session(hSession, &session_p);
398 	if (rv != CKR_OK)
399 		return (rv);
400 
401 	/* Obtain the object pointer. */
402 	HANDLE2OBJECT(hKey, key_p, rv);
403 	if (rv != CKR_OK) {
404 		REFRELE(session_p, ses_lock_held);
405 		return (rv);
406 	}
407 
408 	/*
409 	 * Check to see if key object is a RSA key and if it supports
410 	 * verify_recover.
411 	 */
412 	if (key_p->is_lib_obj && !((key_p->key_type == CKK_RSA) &&
413 	    (key_p->bool_attr_mask & VERIFY_RECOVER_BOOL_ON))) {
414 		rv = CKR_KEY_TYPE_INCONSISTENT;
415 		goto clean_exit;
416 	}
417 
418 	(void) pthread_mutex_lock(&session_p->session_mutex);
419 	ses_lock_held = B_TRUE;
420 
421 	/*
422 	 * This active flag will remain ON until application calls
423 	 * C_VerifyRecover to verify a signature on data.
424 	 */
425 	session_p->verify.flags = CRYPTO_OPERATION_ACTIVE;
426 
427 	/* Set up the key data */
428 	if (!key_p->is_lib_obj) {
429 		vr_init.ri_key.ck_format = CRYPTO_KEY_REFERENCE;
430 		vr_init.ri_key.ck_obj_id = key_p->k_handle;
431 	} else {
432 		if (key_p->key_type == CKK_RSA) {
433 			if (get_rsa_public_key(key_p, &vr_init.ri_key) !=
434 			    CKR_OK) {
435 				rv = CKR_HOST_MEMORY;
436 				goto clean_exit;
437 			}
438 		} else {
439 			rv = CKR_KEY_TYPE_INCONSISTENT;
440 			goto clean_exit;
441 		}
442 	}
443 
444 	vr_init.ri_session = session_p->k_session;
445 	(void) pthread_mutex_unlock(&session_p->session_mutex);
446 	ses_lock_held = B_FALSE;
447 	vr_init.ri_mech.cm_type = k_mech_type;
448 	vr_init.ri_mech.cm_param = pMechanism->pParameter;
449 	vr_init.ri_mech.cm_param_len = pMechanism->ulParameterLen;
450 
451 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_RECOVER_INIT,
452 	    &vr_init)) < 0) {
453 		if (errno != EINTR)
454 			break;
455 	}
456 	if (r < 0) {
457 		rv = CKR_FUNCTION_FAILED;
458 	} else {
459 		rv = crypto2pkcs11_error_number(vr_init.ri_return_value);
460 	}
461 
462 	/* free the memory allocated for vr_init.ri_key */
463 	if (key_p->is_lib_obj) {
464 		free_key_attributes(&vr_init.ri_key);
465 	}
466 
467 	if (rv != CKR_OK) {
468 		(void) pthread_mutex_lock(&session_p->session_mutex);
469 		session_p->verify.flags &= ~CRYPTO_OPERATION_ACTIVE;
470 		ses_lock_held = B_TRUE;
471 	}
472 
473 clean_exit:
474 	OBJ_REFRELE(key_p);
475 	REFRELE(session_p, ses_lock_held);
476 	return (rv);
477 }
478 
479 
480 CK_RV
481 C_VerifyRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
482     CK_ULONG ulSignatureLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
483 {
484 
485 	CK_RV rv;
486 	kernel_session_t *session_p;
487 	boolean_t ses_lock_held = B_FALSE;
488 	crypto_verify_recover_t verify_recover;
489 	int r;
490 
491 	if (!kernel_initialized)
492 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
493 
494 	/* Obtain the session pointer */
495 	rv = handle2session(hSession, &session_p);
496 	if (rv != CKR_OK)
497 		return (rv);
498 
499 	if (pSignature == NULL || pulDataLen == NULL) {
500 		rv = CKR_ARGUMENTS_BAD;
501 		goto clean_exit;
502 	}
503 
504 	(void) pthread_mutex_lock(&session_p->session_mutex);
505 	ses_lock_held = B_TRUE;
506 
507 	/*
508 	 * Application must call C_VerifyRecoverInit before calling
509 	 * C_Verify.
510 	 */
511 	if (!(session_p->verify.flags & CRYPTO_OPERATION_ACTIVE)) {
512 		REFRELE(session_p, ses_lock_held);
513 		return (CKR_OPERATION_NOT_INITIALIZED);
514 	}
515 
516 	verify_recover.vr_session = session_p->k_session;
517 	(void) pthread_mutex_unlock(&session_p->session_mutex);
518 	ses_lock_held = B_FALSE;
519 	verify_recover.vr_signlen = ulSignatureLen;
520 	verify_recover.vr_signbuf = (char *)pSignature;
521 	verify_recover.vr_datalen = *pulDataLen;
522 	verify_recover.vr_databuf = (char *)pData;
523 
524 	while ((r = ioctl(kernel_fd, CRYPTO_VERIFY_RECOVER,
525 	    &verify_recover)) < 0) {
526 		if (errno != EINTR)
527 			break;
528 	}
529 	if (r < 0) {
530 		rv = CKR_FUNCTION_FAILED;
531 	} else {
532 		rv = crypto2pkcs11_error_number(
533 		    verify_recover.vr_return_value);
534 	}
535 
536 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
537 		*pulDataLen = verify_recover.vr_datalen;
538 
539 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
540 	    (rv == CKR_OK && pData == NULL)) {
541 		/*
542 		 * We will not terminate the active verify operation flag,
543 		 * when the application-supplied buffer is too small, or
544 		 * the application asks for the length of buffer to hold
545 		 * the recovered data.
546 		 */
547 		REFRELE(session_p, ses_lock_held);
548 		return (rv);
549 	}
550 
551 clean_exit:
552 	/*
553 	 * Always terminate the active verify operation.
554 	 * Application needs to call C_VerifyInit again for next
555 	 * verify operation.
556 	 */
557 	(void) pthread_mutex_lock(&session_p->session_mutex);
558 	session_p->verify.flags = 0;
559 	ses_lock_held = B_TRUE;
560 	REFRELE(session_p, ses_lock_held);
561 
562 	return (rv);
563 }
564