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 2007 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 <pthread.h>
30 #include <errno.h>
31 #include <sys/crypto/ioctl.h>
32 #include <security/cryptoki.h>
33 #include "kernelGlobal.h"
34 #include "kernelSession.h"
35 #include "kernelEmulate.h"
36 
37 CK_RV
38 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
39 {
40 	CK_RV rv;
41 	kernel_session_t *session_p;
42 	boolean_t ses_lock_held = B_TRUE;
43 	crypto_digest_init_t digest_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 	 */
56 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
57 	if (rv != CKR_OK)
58 		return (rv);
59 
60 	/*
61 	 * Obtain the session pointer. Also, increment the session
62 	 * reference count.
63 	 */
64 	rv = handle2session(hSession, &session_p);
65 	if (rv != CKR_OK)
66 		return (rv);
67 
68 	/* Acquire the session lock */
69 	(void) pthread_mutex_lock(&session_p->session_mutex);
70 
71 	/*
72 	 * This active flag will remain ON until application calls either
73 	 * C_Digest or C_DigestFinal to actually obtain the value of
74 	 * the message digest.
75 	 */
76 	session_p->digest.flags = CRYPTO_OPERATION_ACTIVE;
77 	digest_init.di_session = session_p->k_session;
78 	(void) pthread_mutex_unlock(&session_p->session_mutex);
79 	digest_init.di_mech.cm_type = k_mech_type;
80 	digest_init.di_mech.cm_param = pMechanism->pParameter;
81 
82 	/*
83 	 * If pParameter is NULL, set cm_param_len to be 0, so that ioctl call
84 	 * will have a clean input data.
85 	 */
86 	if (pMechanism->pParameter != NULL)
87 		digest_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
88 	else
89 		digest_init.di_mech.cm_param_len = 0;
90 
91 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_INIT, &digest_init)) < 0) {
92 		if (errno != EINTR)
93 			break;
94 	}
95 	if (r < 0) {
96 		rv = CKR_FUNCTION_FAILED;
97 	} else {
98 		rv = crypto2pkcs11_error_number(digest_init.di_return_value);
99 	}
100 
101 	if (rv == CKR_OK && SLOT_HAS_LIMITED_HASH(session_p)) {
102 		(void) pthread_mutex_lock(&session_p->session_mutex);
103 		session_p->digest.flags |= CRYPTO_EMULATE;
104 		(void) pthread_mutex_unlock(&session_p->session_mutex);
105 		rv = emulate_init(session_p, pMechanism, NULL, OP_DIGEST);
106 	}
107 
108 	if (rv != CKR_OK) {
109 		(void) pthread_mutex_lock(&session_p->session_mutex);
110 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
111 		/*
112 		 * Decrement the session reference count.
113 		 * We hold the session lock, and REFRELE()
114 		 * will release the session lock for us.
115 		 */
116 		REFRELE(session_p, ses_lock_held);
117 		return (rv);
118 	}
119 
120 	/*
121 	 * Decrement the session reference count.
122 	 * We do not hold the session lock.
123 	 */
124 	ses_lock_held = B_FALSE;
125 	REFRELE(session_p, ses_lock_held);
126 	return (rv);
127 }
128 
129 CK_RV
130 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
131     CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
132 {
133 	CK_RV rv;
134 	kernel_session_t *session_p;
135 	boolean_t ses_lock_held = B_TRUE;
136 	crypto_digest_t digest;
137 	int r;
138 
139 	if (!kernel_initialized)
140 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
141 
142 	/*
143 	 * Obtain the session pointer. Also, increment the session
144 	 * reference count.
145 	 */
146 	rv = handle2session(hSession, &session_p);
147 	if (rv != CKR_OK)
148 		return (rv);
149 
150 	if (pData == NULL || pulDigestLen == NULL) {
151 		rv = CKR_ARGUMENTS_BAD;
152 		goto clean_exit;
153 	}
154 
155 	/* Acquire the session lock */
156 	(void) pthread_mutex_lock(&session_p->session_mutex);
157 
158 	/* Application must call C_DigestInit before calling C_Digest */
159 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
160 		/*
161 		 * Decrement the session reference count.
162 		 * We hold the session lock, and REFRELE()
163 		 * will release the session lock for us.
164 		 */
165 		REFRELE(session_p, ses_lock_held);
166 		return (CKR_OPERATION_NOT_INITIALIZED);
167 	}
168 
169 	/*
170 	 * C_Digest must be called without intervening C_DigestUpdate
171 	 * calls.
172 	 */
173 	if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) {
174 		/*
175 		 * C_Digest can not be used to terminate a multi-part
176 		 * operation, so we'll leave the active digest operation
177 		 * flag on and let the application continue with the
178 		 * digest update operation.
179 		 *
180 		 * Decrement the session reference count.
181 		 * We hold the session lock, and REFRELE()
182 		 * will release the session lock for us.
183 		 */
184 		REFRELE(session_p, ses_lock_held);
185 		return (CKR_FUNCTION_FAILED);
186 	}
187 
188 	if (session_p->digest.flags & CRYPTO_EMULATE) {
189 		if ((ulDataLen < SLOT_THRESHOLD(session_p)) ||
190 		    (ulDataLen > SLOT_MAX_INDATA_LEN(session_p))) {
191 			session_p->digest.flags |= CRYPTO_EMULATE_USING_SW;
192 			(void) pthread_mutex_unlock(&session_p->session_mutex);
193 
194 			rv = do_soft_digest(get_spp(&session_p->digest), NULL,
195 			    pData, ulDataLen, pDigest, pulDigestLen, OP_SINGLE);
196 			goto done;
197 		} else {
198 			free_soft_ctx(get_sp(&session_p->digest), OP_DIGEST);
199 		}
200 	}
201 
202 	digest.cd_session = session_p->k_session;
203 	(void) pthread_mutex_unlock(&session_p->session_mutex);
204 	digest.cd_datalen =  ulDataLen;
205 	digest.cd_databuf = (char *)pData;
206 	digest.cd_digestbuf = (char *)pDigest;
207 	digest.cd_digestlen = *pulDigestLen;
208 
209 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST, &digest)) < 0) {
210 		if (errno != EINTR)
211 			break;
212 	}
213 	if (r < 0) {
214 		rv = CKR_FUNCTION_FAILED;
215 	} else {
216 		rv = crypto2pkcs11_error_number(digest.cd_return_value);
217 	}
218 
219 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
220 		*pulDigestLen = digest.cd_digestlen;
221 
222 done:
223 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
224 	    (rv == CKR_OK && pDigest == NULL)) {
225 		/*
226 		 * We will not terminate the active digest operation flag,
227 		 * when the application-supplied buffer is too small, or
228 		 * the application asks for the length of buffer to hold
229 		 * the message digest.
230 		 *
231 		 * Decrement the session reference count.
232 		 * We do not hold the session lock.
233 		 */
234 		ses_lock_held = B_FALSE;
235 		REFRELE(session_p, ses_lock_held);
236 		return (rv);
237 	}
238 
239 clean_exit:
240 	/*
241 	 * Terminates the active digest operation.
242 	 * Application needs to call C_DigestInit again for next
243 	 * digest operation.
244 	 */
245 	(void) pthread_mutex_lock(&session_p->session_mutex);
246 
247 	REINIT_OPBUF(&session_p->digest);
248 	session_p->digest.flags = 0;
249 
250 	/*
251 	 * Decrement the session reference count.
252 	 * We hold the session lock, and REFRELE()
253 	 * will release the session lock for us.
254 	 */
255 	REFRELE(session_p, ses_lock_held);
256 
257 	return (rv);
258 }
259 
260 CK_RV
261 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
262     CK_ULONG ulPartLen)
263 {
264 
265 	CK_RV rv;
266 	kernel_session_t *session_p;
267 	boolean_t ses_lock_held = B_TRUE;
268 	crypto_digest_update_t digest_update;
269 	int r;
270 
271 	if (!kernel_initialized)
272 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
273 
274 	/*
275 	 * Obtain the session pointer. Also, increment the session
276 	 * reference count.
277 	 */
278 	rv = handle2session(hSession, &session_p);
279 	if (rv != CKR_OK)
280 		return (rv);
281 
282 	if (pPart == NULL) {
283 		rv = CKR_ARGUMENTS_BAD;
284 		goto clean_exit;
285 	}
286 
287 	/* Acquire the session lock */
288 	(void) pthread_mutex_lock(&session_p->session_mutex);
289 
290 	/*
291 	 * Application must call C_DigestInit before calling
292 	 * C_DigestUpdate.
293 	 */
294 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
295 		/*
296 		 * Decrement the session reference count.
297 		 * We hold the session lock, and REFRELE()
298 		 * will release the session lock for us.
299 		 */
300 		REFRELE(session_p, ses_lock_held);
301 		return (CKR_OPERATION_NOT_INITIALIZED);
302 	}
303 
304 	/* Set update flag to protect C_Digest */
305 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
306 
307 	if (session_p->digest.flags & CRYPTO_EMULATE) {
308 		(void) pthread_mutex_unlock(&session_p->session_mutex);
309 		rv = emulate_update(session_p, pPart, ulPartLen, OP_DIGEST);
310 		goto done;
311 	}
312 
313 	digest_update.du_session = session_p->k_session;
314 	(void) pthread_mutex_unlock(&session_p->session_mutex);
315 	digest_update.du_datalen =  ulPartLen;
316 	digest_update.du_databuf = (char *)pPart;
317 
318 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
319 	    &digest_update)) < 0) {
320 		if (errno != EINTR)
321 			break;
322 	}
323 	if (r < 0) {
324 		rv = CKR_FUNCTION_FAILED;
325 	} else {
326 		rv = crypto2pkcs11_error_number(digest_update.du_return_value);
327 	}
328 
329 done:
330 	if (rv == CKR_OK) {
331 		/*
332 		 * Decrement the session reference count.
333 		 * We do not hold the session lock.
334 		 */
335 		ses_lock_held = B_FALSE;
336 		REFRELE(session_p, ses_lock_held);
337 		return (CKR_OK);
338 	}
339 
340 clean_exit:
341 	/*
342 	 * After an error occurred, terminate the current digest
343 	 * operation by resetting the active and update flags.
344 	 */
345 	(void) pthread_mutex_lock(&session_p->session_mutex);
346 	REINIT_OPBUF(&session_p->digest);
347 	session_p->digest.flags = 0;
348 
349 	/*
350 	 * Decrement the session reference count.
351 	 * We hold the session lock, and REFRELE()
352 	 * will release the session lock for us.
353 	 */
354 	REFRELE(session_p, ses_lock_held);
355 
356 	return (rv);
357 }
358 
359 
360 CK_RV
361 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
362 {
363 
364 	CK_RV		rv;
365 	kernel_session_t	*session_p;
366 	kernel_object_t	*key_p;
367 	boolean_t ses_lock_held = B_TRUE;
368 	CK_BYTE_PTR	pPart;
369 	CK_ULONG	ulPartLen;
370 	crypto_digest_key_t digest_key;
371 	crypto_digest_update_t digest_update;
372 	int r;
373 
374 	if (!kernel_initialized)
375 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
376 
377 	/*
378 	 * Obtain the session pointer. Also, increment the session
379 	 * reference count.
380 	 */
381 	rv = handle2session(hSession, &session_p);
382 	if (rv != CKR_OK)
383 		return (rv);
384 
385 	/* Obtain the object pointer. */
386 	HANDLE2OBJECT(hKey, key_p, rv);
387 	if (rv != CKR_OK) {
388 		(void) pthread_mutex_lock(&session_p->session_mutex);
389 		REINIT_OPBUF(&session_p->digest);
390 		session_p->digest.flags = 0;
391 		REFRELE(session_p, ses_lock_held);
392 		return (rv);
393 	}
394 
395 	/* Check the key type */
396 	if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
397 		rv = CKR_KEY_INDIGESTIBLE;
398 		goto clean_exit;
399 	}
400 
401 	/*
402 	 * Application must call C_DigestInit before calling
403 	 * C_DigestKey.
404 	 */
405 	(void) pthread_mutex_lock(&session_p->session_mutex);
406 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
407 		/*
408 		 * Decrement the session reference count.
409 		 * We hold the session lock, and REFRELE()
410 		 * will release the session lock for us.
411 		 */
412 		OBJ_REFRELE(key_p);
413 		REFRELE(session_p, ses_lock_held);
414 		return (CKR_OPERATION_NOT_INITIALIZED);
415 	}
416 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
417 
418 	/*
419 	 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
420 	 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
421 	 * by value.
422 	 */
423 	if (key_p->is_lib_obj) {
424 		digest_update.du_session = session_p->k_session;
425 	} else {
426 		digest_key.dk_session = session_p->k_session;
427 	}
428 	(void) pthread_mutex_unlock(&session_p->session_mutex);
429 
430 	if (!key_p->is_lib_obj) {
431 		if (session_p->digest.flags & CRYPTO_EMULATE) {
432 			rv = CKR_FUNCTION_NOT_SUPPORTED;
433 			goto clean_exit;
434 		}
435 		digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE;
436 		digest_key.dk_key.ck_obj_id = key_p->k_handle;
437 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY,
438 		    &digest_key)) < 0) {
439 			if (errno != EINTR)
440 				break;
441 		}
442 		if (r < 0) {
443 			rv = CKR_FUNCTION_FAILED;
444 		} else {
445 			rv = crypto2pkcs11_error_number(
446 			    digest_key.dk_return_value);
447 		}
448 	} else {
449 		ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
450 		if (ulPartLen == 0) {
451 			rv = CKR_KEY_SIZE_RANGE;
452 			goto clean_exit;
453 		}
454 
455 		pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
456 		if (pPart == NULL) {
457 			rv = CKR_KEY_HANDLE_INVALID;
458 			goto clean_exit;
459 		}
460 
461 		(void) pthread_mutex_lock(&session_p->session_mutex);
462 		if (session_p->digest.flags & CRYPTO_EMULATE) {
463 			(void) pthread_mutex_unlock(&session_p->session_mutex);
464 			rv = emulate_update(session_p, pPart,
465 			    ulPartLen, OP_DIGEST);
466 			goto done;
467 		}
468 		(void) pthread_mutex_unlock(&session_p->session_mutex);
469 
470 		digest_update.du_datalen = ulPartLen;
471 		digest_update.du_databuf = (char *)pPart;
472 
473 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
474 		    &digest_update)) < 0) {
475 			if (errno != EINTR)
476 				break;
477 		}
478 		if (r < 0) {
479 			rv = CKR_FUNCTION_FAILED;
480 		} else {
481 			rv = crypto2pkcs11_error_number(
482 			    digest_update.du_return_value);
483 		}
484 	}
485 
486 done:
487 	if (rv == CKR_OK) {
488 		/*
489 		 * Decrement the session reference count.
490 		 * We do not hold the session lock.
491 		 */
492 		OBJ_REFRELE(key_p);
493 		ses_lock_held = B_FALSE;
494 		REFRELE(session_p, ses_lock_held);
495 		return (CKR_OK);
496 	}
497 
498 clean_exit:
499 	OBJ_REFRELE(key_p);
500 	/*
501 	 * After an error occurred, terminate the current digest
502 	 * operation by resetting the active and update flags.
503 	 */
504 	(void) pthread_mutex_lock(&session_p->session_mutex);
505 	REINIT_OPBUF(&session_p->digest);
506 	session_p->digest.flags = 0;
507 
508 	/*
509 	 * Decrement the session reference count.
510 	 * We hold the session lock, and REFRELE()
511 	 * will release the session lock for us.
512 	 */
513 	REFRELE(session_p, ses_lock_held);
514 	return (rv);
515 }
516 
517 
518 CK_RV
519 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
520     CK_ULONG_PTR pulDigestLen)
521 {
522 
523 	CK_RV rv;
524 	kernel_session_t *session_p;
525 	boolean_t ses_lock_held = B_TRUE;
526 	crypto_digest_final_t digest_final;
527 	int r;
528 
529 	if (!kernel_initialized)
530 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
531 
532 	/*
533 	 * Obtain the session pointer. Also, increment the session
534 	 * reference count.
535 	 */
536 	rv = handle2session(hSession, &session_p);
537 	if (rv != CKR_OK)
538 		return (rv);
539 
540 	if (pulDigestLen == NULL) {
541 		rv = CKR_ARGUMENTS_BAD;
542 		goto clean_exit;
543 	}
544 
545 	/* Acquire the session lock */
546 	(void) pthread_mutex_lock(&session_p->session_mutex);
547 
548 	/*
549 	 * Application must call C_DigestInit before calling
550 	 * C_DigestFinal.
551 	 */
552 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
553 		/*
554 		 * Decrement the session reference count.
555 		 * We hold the session lock, and REFRELE()
556 		 * will release the session lock for us.
557 		 */
558 		REFRELE(session_p, ses_lock_held);
559 		return (CKR_OPERATION_NOT_INITIALIZED);
560 	}
561 
562 	/* The order of checks is important here */
563 	if (session_p->digest.flags & CRYPTO_EMULATE_USING_SW) {
564 		if (session_p->digest.flags & CRYPTO_EMULATE_UPDATE_DONE) {
565 			(void) pthread_mutex_unlock(&session_p->session_mutex);
566 			rv = do_soft_digest(get_spp(&session_p->digest),
567 			    NULL, NULL, NULL, pDigest, pulDigestLen, OP_FINAL);
568 		} else {
569 			/*
570 			 * We end up here if an earlier C_DigestFinal() call
571 			 * took the C_Digest() path and it had returned
572 			 * CKR_BUFFER_TOO_SMALL.
573 			 */
574 			digest_buf_t *bufp = session_p->digest.context;
575 			(void) pthread_mutex_unlock(&session_p->session_mutex);
576 			if (bufp == NULL || bufp->buf == NULL) {
577 				rv = CKR_ARGUMENTS_BAD;
578 				goto clean_exit;
579 			}
580 			rv = do_soft_digest(get_spp(&session_p->digest),
581 			    NULL, bufp->buf, bufp->indata_len,
582 			    pDigest, pulDigestLen, OP_SINGLE);
583 		}
584 		goto done;
585 	} else if (session_p->digest.flags & CRYPTO_EMULATE) {
586 		digest_buf_t *bufp = session_p->digest.context;
587 
588 		/*
589 		 * We are emulating a single-part operation now.
590 		 * So, clear the flag.
591 		 */
592 		session_p->digest.flags &= ~CRYPTO_OPERATION_UPDATE;
593 		if (bufp == NULL || bufp->buf == NULL) {
594 			rv = CKR_ARGUMENTS_BAD;
595 			goto clean_exit;
596 		}
597 		REFRELE(session_p, ses_lock_held);
598 		rv = C_Digest(hSession, bufp->buf, bufp->indata_len,
599 		    pDigest, pulDigestLen);
600 		return (rv);
601 	}
602 
603 	digest_final.df_session = session_p->k_session;
604 	(void) pthread_mutex_unlock(&session_p->session_mutex);
605 	digest_final.df_digestlen = *pulDigestLen;
606 	digest_final.df_digestbuf = (char *)pDigest;
607 
608 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) {
609 		if (errno != EINTR)
610 			break;
611 	}
612 	if (r < 0) {
613 		rv = CKR_FUNCTION_FAILED;
614 	} else {
615 		rv = crypto2pkcs11_error_number(digest_final.df_return_value);
616 	}
617 
618 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
619 		*pulDigestLen = digest_final.df_digestlen;
620 
621 done:
622 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
623 	    (rv == CKR_OK && pDigest == NULL)) {
624 		/*
625 		 * We will not terminate the active digest operation flag,
626 		 * when the application-supplied buffer is too small, or
627 		 * the application asks for the length of buffer to hold
628 		 * the message digest.
629 		 *
630 		 * Decrement the session reference count.
631 		 * We do not hold the session lock.
632 		 */
633 		ses_lock_held = B_FALSE;
634 		REFRELE(session_p, ses_lock_held);
635 		return (rv);
636 	}
637 
638 clean_exit:
639 	/* Terminates the active digest operation */
640 	(void) pthread_mutex_lock(&session_p->session_mutex);
641 	REINIT_OPBUF(&session_p->digest);
642 	session_p->digest.flags = 0;
643 
644 	/*
645 	 * Decrement the session reference count.
646 	 * We hold the session lock, and REFRELE()
647 	 * will release the session lock for us.
648 	 */
649 	REFRELE(session_p, ses_lock_held);
650 
651 	return (rv);
652 }
653