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