xref: /titanic_50/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDigest.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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 		goto clean_exit;
361 
362 	/* Check the key type */
363 	if (key_p->is_lib_obj && (key_p->class != CKO_SECRET_KEY)) {
364 		rv = CKR_KEY_INDIGESTIBLE;
365 		goto clean_exit;
366 	}
367 
368 	/*
369 	 * Application must call C_DigestInit before calling
370 	 * C_DigestKey.
371 	 */
372 	(void) pthread_mutex_lock(&session_p->session_mutex);
373 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
374 		/*
375 		 * Decrement the session reference count.
376 		 * We hold the session lock, and REFRELE()
377 		 * will release the session lock for us.
378 		 */
379 		REFRELE(session_p, ses_lock_held);
380 		return (CKR_OPERATION_NOT_INITIALIZED);
381 	}
382 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
383 
384 	/*
385 	 * If the key object is from the HW provider, call CRYPTO_DIGEST_KEY
386 	 * ioctl. Otherwise, call CRYPTO_DIGEST_UPDATE ioctl and pass the key
387 	 * by value.
388 	 */
389 	if (key_p->is_lib_obj) {
390 		digest_update.du_session = session_p->k_session;
391 	} else {
392 		digest_key.dk_session = session_p->k_session;
393 	}
394 	(void) pthread_mutex_unlock(&session_p->session_mutex);
395 
396 
397 	if (!key_p->is_lib_obj) {
398 		digest_key.dk_key.ck_format = CRYPTO_KEY_REFERENCE;
399 		digest_key.dk_key.ck_obj_id = key_p->k_handle;
400 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_KEY,
401 		    &digest_key)) < 0) {
402 			if (errno != EINTR)
403 				break;
404 		}
405 		if (r < 0) {
406 			rv = CKR_FUNCTION_FAILED;
407 		} else {
408 			rv = crypto2pkcs11_error_number(
409 			    digest_key.dk_return_value);
410 		}
411 	} else {
412 		ulPartLen = OBJ_SEC_VALUE_LEN(key_p);
413 		if (ulPartLen == 0) {
414 			rv = CKR_KEY_SIZE_RANGE;
415 			goto clean_exit;
416 		}
417 
418 		pPart = (CK_BYTE_PTR) OBJ_SEC_VALUE(key_p);
419 		if (pPart == NULL) {
420 			rv = CKR_KEY_HANDLE_INVALID;
421 			goto clean_exit;
422 		}
423 
424 		digest_update.du_datalen = ulPartLen;
425 		digest_update.du_databuf = (char *)pPart;
426 
427 		while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_UPDATE,
428 		    &digest_update)) < 0) {
429 			if (errno != EINTR)
430 				break;
431 		}
432 		if (r < 0) {
433 			rv = CKR_FUNCTION_FAILED;
434 		} else {
435 			rv = crypto2pkcs11_error_number(
436 			    digest_update.du_return_value);
437 		}
438 	}
439 
440 	if (rv == CKR_OK) {
441 		/*
442 		 * Decrement the session reference count.
443 		 * We do not hold the session lock.
444 		 */
445 		REFRELE(session_p, ses_lock_held);
446 		ses_lock_held = B_FALSE;
447 		return (CKR_OK);
448 	}
449 
450 clean_exit:
451 	/*
452 	 * After an error occurred, terminate the current digest
453 	 * operation by resetting the active and update flags.
454 	 */
455 	(void) pthread_mutex_lock(&session_p->session_mutex);
456 	session_p->digest.flags = 0;
457 
458 	/*
459 	 * Decrement the session reference count.
460 	 * We hold the session lock, and REFRELE()
461 	 * will release the session lock for us.
462 	 */
463 	REFRELE(session_p, ses_lock_held);
464 	return (rv);
465 }
466 
467 
468 CK_RV
469 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
470     CK_ULONG_PTR pulDigestLen)
471 {
472 
473 	CK_RV rv;
474 	kernel_session_t *session_p;
475 	boolean_t ses_lock_held = B_TRUE;
476 	crypto_digest_final_t digest_final;
477 	int r;
478 
479 	if (!kernel_initialized)
480 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
481 
482 	/*
483 	 * Obtain the session pointer. Also, increment the session
484 	 * reference count.
485 	 */
486 	rv = handle2session(hSession, &session_p);
487 	if (rv != CKR_OK)
488 		return (rv);
489 
490 	if (pulDigestLen == NULL) {
491 		rv = CKR_ARGUMENTS_BAD;
492 		goto clean_exit;
493 	}
494 
495 	/* Acquire the session lock */
496 	(void) pthread_mutex_lock(&session_p->session_mutex);
497 
498 	/*
499 	 * Application must call C_DigestInit before calling
500 	 * C_DigestFinal.
501 	 */
502 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
503 		/*
504 		 * Decrement the session reference count.
505 		 * We hold the session lock, and REFRELE()
506 		 * will release the session lock for us.
507 		 */
508 		REFRELE(session_p, ses_lock_held);
509 		return (CKR_OPERATION_NOT_INITIALIZED);
510 	}
511 
512 	digest_final.df_session = session_p->k_session;
513 	(void) pthread_mutex_unlock(&session_p->session_mutex);
514 	digest_final.df_digestlen = *pulDigestLen;
515 	digest_final.df_digestbuf = (char *)pDigest;
516 
517 	while ((r = ioctl(kernel_fd, CRYPTO_DIGEST_FINAL, &digest_final)) < 0) {
518 		if (errno != EINTR)
519 			break;
520 	}
521 	if (r < 0) {
522 		rv = CKR_FUNCTION_FAILED;
523 	} else {
524 		rv = crypto2pkcs11_error_number(digest_final.df_return_value);
525 	}
526 
527 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL))
528 		*pulDigestLen = digest_final.df_digestlen;
529 
530 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
531 	    (rv == CKR_OK && pDigest == NULL)) {
532 		/*
533 		 * We will not terminate the active digest operation flag,
534 		 * when the application-supplied buffer is too small, or
535 		 * the application asks for the length of buffer to hold
536 		 * the message digest.
537 		 *
538 		 * Decrement the session reference count.
539 		 * We do not hold the session lock.
540 		 */
541 		ses_lock_held = B_FALSE;
542 		REFRELE(session_p, ses_lock_held);
543 		return (rv);
544 	}
545 
546 clean_exit:
547 	/* Terminates the active digest operation */
548 	(void) pthread_mutex_lock(&session_p->session_mutex);
549 	session_p->digest.flags = 0;
550 
551 	/*
552 	 * Decrement the session reference count.
553 	 * We hold the session lock, and REFRELE()
554 	 * will release the session lock for us.
555 	 */
556 	REFRELE(session_p, ses_lock_held);
557 
558 	return (rv);
559 }
560