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