xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelSign.c (revision 54719d5edb7521bb3a321ad8bd9ebc251d61a1a0)
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 <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 
36 CK_RV
37 C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
38     CK_OBJECT_HANDLE hKey)
39 {
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 {
118 			rv = CKR_KEY_TYPE_INCONSISTENT;
119 			goto clean_exit;
120 		}
121 	}
122 
123 	sign_init.si_mech.cm_type = k_mech_type;
124 	sign_init.si_mech.cm_param = pMechanism->pParameter;
125 	sign_init.si_mech.cm_param_len = pMechanism->ulParameterLen;
126 
127 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_INIT, &sign_init)) < 0) {
128 		if (errno != EINTR)
129 			break;
130 	}
131 	if (r < 0) {
132 		rv = CKR_FUNCTION_FAILED;
133 	} else {
134 		rv = crypto2pkcs11_error_number(sign_init.si_return_value);
135 	}
136 
137 	if (key_p->is_lib_obj) {
138 		if (key_p->class == CKO_SECRET_KEY) {
139 			free(sign_init.si_key.ck_data);
140 		} else if (key_p->key_type == CKK_RSA) {
141 			free_key_attributes(&sign_init.si_key);
142 		} else if (key_p->key_type == CKK_DSA) {
143 			free_key_attributes(&sign_init.si_key);
144 		}
145 	}
146 
147 	if (rv != CKR_OK) {
148 		(void) pthread_mutex_lock(&session_p->session_mutex);
149 		session_p->sign.flags &= ~CRYPTO_OPERATION_ACTIVE;
150 		ses_lock_held = B_TRUE;
151 	}
152 
153 clean_exit:
154 	OBJ_REFRELE(key_p);
155 	REFRELE(session_p, ses_lock_held);
156 	return (rv);
157 }
158 
159 
160 CK_RV
161 C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
162     CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
163 {
164 
165 	CK_RV rv;
166 	kernel_session_t *session_p;
167 	boolean_t ses_lock_held = B_FALSE;
168 	crypto_sign_t sign;
169 	int r;
170 
171 	if (!kernel_initialized)
172 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
173 
174 	/* Obtain the session pointer */
175 	rv = handle2session(hSession, &session_p);
176 	if (rv != CKR_OK)
177 		return (rv);
178 
179 	if (pulSignatureLen == NULL) {
180 		rv = CKR_ARGUMENTS_BAD;
181 		goto clean_exit;
182 	}
183 
184 	(void) pthread_mutex_lock(&session_p->session_mutex);
185 	ses_lock_held = B_TRUE;
186 
187 	/* Application must call C_SignInit before calling C_Sign. */
188 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
189 		REFRELE(session_p, ses_lock_held);
190 		return (CKR_OPERATION_NOT_INITIALIZED);
191 	}
192 
193 	/*
194 	 * C_Sign must be called without intervening C_SignUpdate
195 	 * calls.
196 	 */
197 	if (session_p->sign.flags & CRYPTO_OPERATION_UPDATE) {
198 		/*
199 		 * C_Sign can not be used to terminate a multi-part
200 		 * operation, so we'll leave the active sign operation
201 		 * flag on and let the application continue with the
202 		 * sign update operation.
203 		 */
204 		REFRELE(session_p, ses_lock_held);
205 		return (CKR_FUNCTION_FAILED);
206 	}
207 
208 	sign.cs_session = session_p->k_session;
209 	(void) pthread_mutex_unlock(&session_p->session_mutex);
210 	ses_lock_held = B_FALSE;
211 
212 	sign.cs_datalen = ulDataLen;
213 	sign.cs_databuf = (char *)pData;
214 	sign.cs_signlen = *pulSignatureLen;
215 	sign.cs_signbuf = (char *)pSignature;
216 
217 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN, &sign)) < 0) {
218 		if (errno != EINTR)
219 			break;
220 	}
221 	if (r < 0) {
222 		rv = CKR_FUNCTION_FAILED;
223 	} else {
224 		rv = crypto2pkcs11_error_number(sign.cs_return_value);
225 	}
226 
227 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
228 		*pulSignatureLen = sign.cs_signlen;
229 
230 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
231 	    (rv == CKR_OK && pSignature == NULL)) {
232 		/*
233 		 * We will not terminate the active sign operation flag,
234 		 * when the application-supplied buffer is too small, or
235 		 * the application asks for the length of buffer to hold
236 		 * the signature.
237 		 */
238 		REFRELE(session_p, ses_lock_held);
239 		return (rv);
240 	}
241 
242 clean_exit:
243 	/*
244 	 * Terminates the active sign operation.
245 	 * Application needs to call C_SignInit again for next
246 	 * sign operation.
247 	 */
248 	(void) pthread_mutex_lock(&session_p->session_mutex);
249 	session_p->sign.flags = 0;
250 	ses_lock_held = B_TRUE;
251 	REFRELE(session_p, ses_lock_held);
252 
253 	return (rv);
254 }
255 
256 
257 CK_RV
258 C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
259     CK_ULONG ulPartLen)
260 {
261 
262 	CK_RV rv;
263 	kernel_session_t *session_p;
264 	boolean_t ses_lock_held = B_FALSE;
265 	crypto_sign_update_t sign_update;
266 	int r;
267 
268 	if (!kernel_initialized)
269 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
270 
271 	/* Obtain the session pointer */
272 	rv = handle2session(hSession, &session_p);
273 	if (rv != CKR_OK)
274 		return (rv);
275 
276 	if (pPart == NULL) {
277 		rv = CKR_ARGUMENTS_BAD;
278 		goto clean_exit;
279 	}
280 
281 	(void) pthread_mutex_lock(&session_p->session_mutex);
282 	ses_lock_held = B_TRUE;
283 
284 	/*
285 	 * Application must call C_SignInit before calling
286 	 * C_SignUpdate.
287 	 */
288 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
289 		REFRELE(session_p, ses_lock_held);
290 		return (CKR_OPERATION_NOT_INITIALIZED);
291 	}
292 
293 	session_p->sign.flags |= CRYPTO_OPERATION_UPDATE;
294 
295 	sign_update.su_session = session_p->k_session;
296 	(void) pthread_mutex_unlock(&session_p->session_mutex);
297 	ses_lock_held = B_FALSE;
298 
299 	sign_update.su_datalen = ulPartLen;
300 	sign_update.su_databuf = (char *)pPart;
301 
302 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_UPDATE, &sign_update)) < 0) {
303 		if (errno != EINTR)
304 			break;
305 	}
306 	if (r < 0) {
307 		rv = CKR_FUNCTION_FAILED;
308 	} else {
309 		rv = crypto2pkcs11_error_number(sign_update.su_return_value);
310 	}
311 
312 	if (rv == CKR_OK) {
313 		REFRELE(session_p, ses_lock_held);
314 		return (rv);
315 	}
316 
317 clean_exit:
318 	/*
319 	 * After an error occurred, terminate the current sign
320 	 * operation by resetting the active and update flags.
321 	 */
322 	(void) pthread_mutex_lock(&session_p->session_mutex);
323 	session_p->sign.flags = 0;
324 	ses_lock_held = B_TRUE;
325 	REFRELE(session_p, ses_lock_held);
326 
327 	return (rv);
328 }
329 
330 
331 CK_RV
332 C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature,
333     CK_ULONG_PTR pulSignatureLen)
334 {
335 
336 	CK_RV rv;
337 	kernel_session_t *session_p;
338 	boolean_t ses_lock_held = B_FALSE;
339 	crypto_sign_final_t sign_final;
340 	int r;
341 
342 	if (!kernel_initialized)
343 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
344 
345 	/* Obtain the session pointer */
346 	rv = handle2session(hSession, &session_p);
347 	if (rv != CKR_OK)
348 		return (rv);
349 
350 	if (pulSignatureLen == NULL) {
351 		rv = CKR_ARGUMENTS_BAD;
352 		goto clean_exit;
353 	}
354 
355 	(void) pthread_mutex_lock(&session_p->session_mutex);
356 	ses_lock_held = B_TRUE;
357 
358 	/*
359 	 * Application must call C_SignInit before calling
360 	 * C_SignFinal.
361 	 */
362 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
363 		REFRELE(session_p, ses_lock_held);
364 		return (CKR_OPERATION_NOT_INITIALIZED);
365 	}
366 
367 	sign_final.sf_session = session_p->k_session;
368 	(void) pthread_mutex_unlock(&session_p->session_mutex);
369 	ses_lock_held = B_FALSE;
370 
371 	sign_final.sf_signlen = *pulSignatureLen;
372 	sign_final.sf_signbuf = (char *)pSignature;
373 
374 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_FINAL, &sign_final)) < 0) {
375 		if (errno != EINTR)
376 			break;
377 	}
378 	if (r < 0) {
379 		rv = CKR_FUNCTION_FAILED;
380 	} else {
381 		rv = crypto2pkcs11_error_number(sign_final.sf_return_value);
382 	}
383 
384 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
385 		*pulSignatureLen = sign_final.sf_signlen;
386 
387 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
388 	    (rv == CKR_OK && pSignature == NULL)) {
389 		/*
390 		 * We will not terminate the active sign operation flag,
391 		 * when the application-supplied buffer is too small, or
392 		 * the application asks for the length of buffer to hold
393 		 * the signature.
394 		 */
395 		REFRELE(session_p, ses_lock_held);
396 		return (rv);
397 	}
398 
399 clean_exit:
400 	/* Terminates the active sign operation */
401 	(void) pthread_mutex_lock(&session_p->session_mutex);
402 	session_p->sign.flags = 0;
403 	ses_lock_held = B_TRUE;
404 	REFRELE(session_p, ses_lock_held);
405 
406 	return (rv);
407 }
408 
409 
410 CK_RV
411 C_SignRecoverInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
412     CK_OBJECT_HANDLE hKey)
413 {
414 
415 	CK_RV rv;
416 	kernel_session_t *session_p;
417 	kernel_object_t *key_p;
418 	boolean_t ses_lock_held = B_FALSE;
419 	crypto_sign_recover_init_t sr_init;
420 	crypto_mech_type_t k_mech_type;
421 	int r;
422 
423 	if (!kernel_initialized)
424 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
425 
426 	if (pMechanism == NULL) {
427 		return (CKR_ARGUMENTS_BAD);
428 	}
429 
430 	/* Get the kernel's internal mechanism number. */
431 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
432 	if (rv != CKR_OK)
433 		return (rv);
434 
435 	/* Obtain the session pointer. */
436 	rv = handle2session(hSession, &session_p);
437 	if (rv != CKR_OK)
438 		return (rv);
439 
440 	/* Obtain the object pointer. */
441 	HANDLE2OBJECT(hKey, key_p, rv);
442 	if (rv != CKR_OK) {
443 		REFRELE(session_p, ses_lock_held);
444 		return (rv);
445 	}
446 
447 	/*
448 	 * Check to see if key object is a RSA key and if it supports
449 	 * sign_recover.
450 	 */
451 	if (key_p->is_lib_obj && !((key_p->key_type == CKK_RSA) &&
452 	    (key_p->bool_attr_mask & SIGN_RECOVER_BOOL_ON))) {
453 		rv = CKR_KEY_TYPE_INCONSISTENT;
454 		goto clean_exit;
455 	}
456 
457 	(void) pthread_mutex_lock(&session_p->session_mutex);
458 	ses_lock_held = B_TRUE;
459 
460 	/*
461 	 * This active flag will remain ON until application calls
462 	 * C_SignRecover to actually obtain the signature.
463 	 */
464 	session_p->sign.flags = CRYPTO_OPERATION_ACTIVE;
465 
466 	/* Set up the key data */
467 	if (!key_p->is_lib_obj) {
468 		sr_init.ri_key.ck_format = CRYPTO_KEY_REFERENCE;
469 		sr_init.ri_key.ck_obj_id = key_p->k_handle;
470 	} else {
471 		if (key_p->key_type == CKK_RSA) {
472 			if (get_rsa_private_key(key_p, &sr_init.ri_key) !=
473 			    CKR_OK) {
474 				rv = CKR_HOST_MEMORY;
475 				goto clean_exit;
476 			}
477 		} else {
478 			rv = CKR_KEY_TYPE_INCONSISTENT;
479 			goto clean_exit;
480 		}
481 	}
482 
483 	sr_init.ri_session = session_p->k_session;
484 	(void) pthread_mutex_unlock(&session_p->session_mutex);
485 	ses_lock_held = B_FALSE;
486 	sr_init.ri_mech.cm_type = k_mech_type;
487 	sr_init.ri_mech.cm_param = pMechanism->pParameter;
488 	sr_init.ri_mech.cm_param_len = pMechanism->ulParameterLen;
489 
490 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_RECOVER_INIT, &sr_init)) < 0) {
491 		if (errno != EINTR)
492 			break;
493 	}
494 	if (r < 0) {
495 		rv = CKR_FUNCTION_FAILED;
496 	} else {
497 		rv = crypto2pkcs11_error_number(sr_init.ri_return_value);
498 	}
499 
500 	if (key_p->is_lib_obj) {
501 		free_key_attributes(&sr_init.ri_key);
502 	}
503 
504 	if (rv != CKR_OK) {
505 		(void) pthread_mutex_lock(&session_p->session_mutex);
506 		session_p->sign.flags &= ~CRYPTO_OPERATION_ACTIVE;
507 		ses_lock_held = B_TRUE;
508 	}
509 
510 clean_exit:
511 	OBJ_REFRELE(key_p);
512 	REFRELE(session_p, ses_lock_held);
513 	return (rv);
514 }
515 
516 
517 CK_RV
518 C_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData,
519     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
520 {
521 
522 	CK_RV rv;
523 	kernel_session_t *session_p;
524 	boolean_t ses_lock_held = B_FALSE;
525 	crypto_sign_recover_t sign_recover;
526 	int r;
527 
528 	if (!kernel_initialized)
529 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
530 
531 	/* Obatin the session pointer */
532 	rv = handle2session(hSession, &session_p);
533 	if (rv != CKR_OK)
534 		return (rv);
535 
536 	if (pulSignatureLen == NULL) {
537 		rv = CKR_ARGUMENTS_BAD;
538 		goto clean_exit;
539 	}
540 
541 	(void) pthread_mutex_lock(&session_p->session_mutex);
542 	ses_lock_held = B_TRUE;
543 
544 	/* Application must call C_SignInit before calling C_Sign. */
545 	if (!(session_p->sign.flags & CRYPTO_OPERATION_ACTIVE)) {
546 		REFRELE(session_p, ses_lock_held);
547 		return (CKR_OPERATION_NOT_INITIALIZED);
548 	}
549 
550 	sign_recover.sr_session = session_p->k_session;
551 	(void) pthread_mutex_unlock(&session_p->session_mutex);
552 	ses_lock_held = B_FALSE;
553 
554 	sign_recover.sr_datalen = ulDataLen;
555 	sign_recover.sr_databuf = (char *)pData;
556 	sign_recover.sr_signlen = *pulSignatureLen;
557 	sign_recover.sr_signbuf = (char *)pSignature;
558 
559 	while ((r = ioctl(kernel_fd, CRYPTO_SIGN_RECOVER, &sign_recover)) < 0) {
560 		if (errno != EINTR)
561 			break;
562 	}
563 	if (r < 0) {
564 		rv = CKR_FUNCTION_FAILED;
565 	} else {
566 		rv = crypto2pkcs11_error_number(sign_recover.sr_return_value);
567 	}
568 
569 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
570 		*pulSignatureLen = sign_recover.sr_signlen;
571 
572 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
573 	    (rv == CKR_OK && pSignature == NULL)) {
574 		/*
575 		 * We will not terminate the active sign operation flag,
576 		 * when the application-supplied buffer is too small, or
577 		 * the application asks for the length of buffer to hold
578 		 * the signature.
579 		 */
580 		REFRELE(session_p, ses_lock_held);
581 		return (rv);
582 	}
583 
584 clean_exit:
585 	/*
586 	 * Terminates the active sign operation.
587 	 * Application needs to call C_SignInit again for next
588 	 * sign operation.
589 	 */
590 	(void) pthread_mutex_lock(&session_p->session_mutex);
591 	session_p->sign.flags = 0;
592 	ses_lock_held = B_TRUE;
593 	REFRELE(session_p, ses_lock_held);
594 
595 	return (rv);
596 }
597