xref: /titanic_54/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 <stdlib.h>
31 #include <errno.h>
32 #include <sys/crypto/ioctl.h>
33 #include <security/cryptoki.h>
34 #include "kernelGlobal.h"
35 #include "kernelSession.h"
36 #include "kernelObject.h"
37 
38 
39 /*
40  * Real decryptInit work. The caller doesn't hold the session lock.
41  */
42 CK_RV
43 kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
44     CK_MECHANISM_PTR pMechanism)
45 {
46 	CK_RV rv;
47 	crypto_decrypt_init_t decrypt_init;
48 	crypto_mech_type_t k_mech_type;
49 	boolean_t ses_lock_held = B_FALSE;
50 	int r;
51 
52 	/* Check to see if key object allows for decryption. */
53 	if (key_p->is_lib_obj && !(key_p->bool_attr_mask & DECRYPT_BOOL_ON)) {
54 		return (CKR_KEY_TYPE_INCONSISTENT);
55 	}
56 
57 	/* Get the kernel's internal mechanism number. */
58 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
59 	if (rv != CKR_OK)
60 		return (rv);
61 
62 	(void) pthread_mutex_lock(&session_p->session_mutex);
63 	ses_lock_held = B_TRUE;
64 
65 	/*
66 	 * This active flag will remain ON until application calls either
67 	 * C_Decrypt or C_DecryptFinal to actually obtain the final piece
68 	 * of plaintext.
69 	 */
70 	session_p->decrypt.flags = CRYPTO_OPERATION_ACTIVE;
71 
72 	/* set up key data */
73 	if (!key_p->is_lib_obj) {
74 		decrypt_init.di_key.ck_format = CRYPTO_KEY_REFERENCE;
75 		decrypt_init.di_key.ck_obj_id = key_p->k_handle;
76 	} else {
77 		if (key_p->class == CKO_SECRET_KEY) {
78 			decrypt_init.di_key.ck_format = CRYPTO_KEY_RAW;
79 			decrypt_init.di_key.ck_data =
80 			    get_symmetric_key_value(key_p);
81 			if (decrypt_init.di_key.ck_data == NULL) {
82 				rv = CKR_HOST_MEMORY;
83 				goto clean_exit;
84 			}
85 			/* KEF key lengths are expressed in bits */
86 			decrypt_init.di_key.ck_length =
87 				OBJ_SEC(key_p)->sk_value_len << 3;
88 
89 		} else if (key_p->key_type == CKK_RSA) {
90 			if (get_rsa_private_key(key_p, &decrypt_init.di_key) !=
91 			    CKR_OK) {
92 				rv = CKR_HOST_MEMORY;
93 				goto clean_exit;
94 			}
95 		} else {
96 			rv = CKR_KEY_TYPE_INCONSISTENT;
97 			goto clean_exit;
98 		}
99 	}
100 
101 	decrypt_init.di_session = session_p->k_session;
102 	(void) pthread_mutex_unlock(&session_p->session_mutex);
103 	ses_lock_held = B_FALSE;
104 	decrypt_init.di_mech.cm_type = k_mech_type;
105 	decrypt_init.di_mech.cm_param = pMechanism->pParameter;
106 	decrypt_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
107 
108 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_INIT, &decrypt_init)) < 0) {
109 		if (errno != EINTR)
110 			break;
111 	}
112 	if (r < 0) {
113 		rv = CKR_FUNCTION_FAILED;
114 	} else {
115 		rv = crypto2pkcs11_error_number(decrypt_init.di_return_value);
116 	}
117 
118 	/* Free memory allocated for decrypt_init.di_key */
119 	if (key_p->is_lib_obj) {
120 		if (key_p->class == CKO_SECRET_KEY) {
121 			free(decrypt_init.di_key.ck_data);
122 		} else if (key_p->key_type == CKK_RSA) {
123 			free_key_attributes(&decrypt_init.di_key);
124 		}
125 	}
126 
127 clean_exit:
128 
129 	if (!ses_lock_held) {
130 		(void) pthread_mutex_lock(&session_p->session_mutex);
131 		ses_lock_held = B_TRUE;
132 	}
133 
134 	if (rv != CKR_OK)
135 		session_p->decrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
136 
137 	if (ses_lock_held) {
138 		(void) pthread_mutex_unlock(&session_p->session_mutex);
139 		ses_lock_held = B_FALSE;
140 	}
141 
142 	return (rv);
143 }
144 
145 CK_RV
146 C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
147     CK_OBJECT_HANDLE hKey)
148 {
149 
150 	CK_RV rv;
151 	kernel_session_t *session_p;
152 	kernel_object_t	*key_p;
153 	boolean_t ses_lock_held = B_FALSE;
154 
155 	if (!kernel_initialized)
156 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
157 
158 	if (pMechanism == NULL) {
159 		return (CKR_ARGUMENTS_BAD);
160 	}
161 
162 	/* Obtain the session pointer. */
163 	rv = handle2session(hSession, &session_p);
164 	if (rv != CKR_OK)
165 		return (rv);
166 
167 	/* Obtain the object pointer. */
168 	HANDLE2OBJECT(hKey, key_p, rv);
169 	if (rv == CKR_OK) {
170 		rv = kernel_decrypt_init(session_p, key_p, pMechanism);
171 	}
172 
173 	REFRELE(session_p, ses_lock_held);
174 	return (rv);
175 }
176 
177 
178 
179 /*
180  * Real decrypt work. The caller doesn't hold the session lock.
181  */
182 CK_RV
183 kernel_decrypt(kernel_session_t *session_p, CK_BYTE_PTR pEncryptedData,
184     CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
185 {
186 	crypto_decrypt_t decrypt;
187 	boolean_t ses_lock_held = B_FALSE;
188 	CK_RV rv;
189 	int r;
190 
191 	(void) pthread_mutex_lock(&session_p->session_mutex);
192 	ses_lock_held = B_TRUE;
193 
194 	/* Application must call C_DecryptInit before calling C_Decrypt. */
195 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
196 		rv = CKR_OPERATION_NOT_INITIALIZED;
197 		goto clean_exit;
198 	}
199 
200 	/*
201 	 * C_Decrypt must be called without intervening C_DecryptUpdate
202 	 * calls.
203 	 */
204 	if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
205 		/*
206 		 * C_Decrypt cannot be used to terminate a multiple-part
207 		 * operation, so we'll leave the active decrypt operation
208 		 * flag on and let the application continue with the
209 		 * decrypt update operation.
210 		 */
211 		rv = CKR_FUNCTION_FAILED;
212 		goto clean_exit;
213 	}
214 
215 	decrypt.cd_session = session_p->k_session;
216 	(void) pthread_mutex_unlock(&session_p->session_mutex);
217 	ses_lock_held = B_FALSE;
218 
219 	decrypt.cd_datalen = *pulDataLen;
220 	decrypt.cd_databuf = (char *)pData;
221 	decrypt.cd_encrlen = ulEncryptedData;
222 	decrypt.cd_encrbuf = (char *)pEncryptedData;
223 
224 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT, &decrypt)) < 0) {
225 		if (errno != EINTR)
226 			break;
227 	}
228 	if (r < 0) {
229 		rv = CKR_FUNCTION_FAILED;
230 	} else {
231 		rv = crypto2pkcs11_error_number(decrypt.cd_return_value);
232 	}
233 
234 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
235 		*pulDataLen = decrypt.cd_datalen;
236 
237 clean_exit:
238 
239 	if (ses_lock_held)
240 		(void) pthread_mutex_unlock(&session_p->session_mutex);
241 
242 	return (rv);
243 }
244 
245 CK_RV
246 C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData,
247     CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
248 {
249 	CK_RV rv;
250 	kernel_session_t *session_p;
251 	boolean_t ses_lock_held = B_FALSE;
252 
253 	if (!kernel_initialized)
254 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
255 
256 	/* Obtain the session pointer. */
257 	rv = handle2session(hSession, &session_p);
258 	if (rv != CKR_OK)
259 		return (rv);
260 
261 	/*
262 	 * No need to check pData because application might
263 	 * just want to know the length of decrypted data.
264 	 */
265 	if (pulDataLen == NULL) {
266 		rv = CKR_ARGUMENTS_BAD;
267 		goto clean_exit;
268 	}
269 
270 	rv = kernel_decrypt(session_p, pEncryptedData, ulEncryptedData, pData,
271 	    pulDataLen);
272 
273 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
274 	    (rv == CKR_OK && pData == NULL)) {
275 		/*
276 		 * We will not terminate the active decrypt operation flag,
277 		 * when the application-supplied buffer is too small, or
278 		 * the application asks for the length of buffer to hold
279 		 * the plaintext.
280 		 */
281 		REFRELE(session_p, ses_lock_held);
282 		return (rv);
283 	}
284 
285 clean_exit:
286 	/*
287 	 * Terminates the active decrypt operation.
288 	 * Application needs to call C_DecryptInit again for next
289 	 * decrypt operation.
290 	 */
291 	(void) pthread_mutex_lock(&session_p->session_mutex);
292 	session_p->decrypt.flags = 0;
293 	ses_lock_held = B_TRUE;
294 	REFRELE(session_p, ses_lock_held);
295 
296 	return (rv);
297 }
298 
299 
300 CK_RV
301 C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart,
302     CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart,
303     CK_ULONG_PTR pulPartLen)
304 {
305 
306 	CK_RV rv;
307 	kernel_session_t *session_p;
308 	boolean_t ses_lock_held = B_FALSE;
309 	crypto_decrypt_update_t decrypt_update;
310 	int r;
311 
312 	if (!kernel_initialized)
313 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
314 
315 	/* Obtain the session pointer. */
316 	rv = handle2session(hSession, &session_p);
317 	if (rv != CKR_OK)
318 		return (rv);
319 
320 	if (pEncryptedPart == NULL) {
321 		rv = CKR_ARGUMENTS_BAD;
322 		goto clean_exit;
323 	}
324 
325 	/*
326 	 * Only check if pulPartLen is NULL.
327 	 * No need to check if pPart is NULL because application
328 	 * might just ask for the length of buffer to hold the
329 	 * recovered data.
330 	 */
331 	if (pulPartLen == NULL) {
332 		rv = CKR_ARGUMENTS_BAD;
333 		goto clean_exit;
334 	}
335 
336 	(void) pthread_mutex_lock(&session_p->session_mutex);
337 	ses_lock_held = B_TRUE;
338 
339 	/*
340 	 * Application must call C_DecryptInit before calling
341 	 * C_DecryptUpdate.
342 	 */
343 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
344 		REFRELE(session_p, ses_lock_held);
345 		return (CKR_OPERATION_NOT_INITIALIZED);
346 	}
347 
348 	session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
349 
350 	decrypt_update.du_session = session_p->k_session;
351 	(void) pthread_mutex_unlock(&session_p->session_mutex);
352 	ses_lock_held = B_FALSE;
353 
354 	decrypt_update.du_datalen = *pulPartLen;
355 	decrypt_update.du_databuf = (char *)pPart;
356 	decrypt_update.du_encrlen = ulEncryptedPartLen;
357 	decrypt_update.du_encrbuf = (char *)pEncryptedPart;
358 
359 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_UPDATE,
360 	    &decrypt_update)) < 0) {
361 		if (errno != EINTR)
362 			break;
363 	}
364 	if (r < 0) {
365 		rv = CKR_FUNCTION_FAILED;
366 	} else {
367 		rv = crypto2pkcs11_error_number(
368 		    decrypt_update.du_return_value);
369 	}
370 
371 	/*
372 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
373 	 * We don't terminate the current decryption operation.
374 	 */
375 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
376 		*pulPartLen = decrypt_update.du_datalen;
377 		REFRELE(session_p, ses_lock_held);
378 		return (rv);
379 	}
380 
381 clean_exit:
382 	/*
383 	 * After an error occurred, terminate the current decrypt
384 	 * operation by resetting the active and update flags.
385 	 */
386 	(void) pthread_mutex_lock(&session_p->session_mutex);
387 	session_p->decrypt.flags = 0;
388 	ses_lock_held = B_TRUE;
389 	REFRELE(session_p, ses_lock_held);
390 
391 	return (rv);
392 }
393 
394 
395 CK_RV
396 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
397     CK_ULONG_PTR pulLastPartLen)
398 {
399 
400 	CK_RV rv;
401 	kernel_session_t *session_p;
402 	boolean_t ses_lock_held = B_FALSE;
403 	crypto_decrypt_final_t decrypt_final;
404 	int r;
405 
406 	if (!kernel_initialized)
407 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
408 
409 	/* Obtain the session pointer. */
410 	rv = handle2session(hSession, &session_p);
411 	if (rv != CKR_OK)
412 		return (rv);
413 
414 	if (pulLastPartLen == NULL) {
415 		rv = CKR_ARGUMENTS_BAD;
416 		goto clean_exit;
417 	}
418 
419 	(void) pthread_mutex_lock(&session_p->session_mutex);
420 	ses_lock_held = B_TRUE;
421 
422 	/*
423 	 * Application must call C_DecryptInit before calling
424 	 * C_DecryptFinal.
425 	 */
426 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
427 		REFRELE(session_p, ses_lock_held);
428 		return (CKR_OPERATION_NOT_INITIALIZED);
429 	}
430 
431 	decrypt_final.df_session = session_p->k_session;
432 	(void) pthread_mutex_unlock(&session_p->session_mutex);
433 	ses_lock_held = B_FALSE;
434 
435 	decrypt_final.df_datalen = *pulLastPartLen;
436 	decrypt_final.df_databuf = (char *)pLastPart;
437 
438 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_FINAL,
439 	    &decrypt_final)) < 0) {
440 		if (errno != EINTR)
441 			break;
442 	}
443 	if (r < 0) {
444 		rv = CKR_FUNCTION_FAILED;
445 	} else {
446 		rv = crypto2pkcs11_error_number(decrypt_final.df_return_value);
447 	}
448 
449 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
450 		*pulLastPartLen = decrypt_final.df_datalen;
451 
452 	if (rv == CKR_BUFFER_TOO_SMALL ||
453 	    (rv == CKR_OK && pLastPart == NULL)) {
454 		/*
455 		 * We will not terminate the active decrypt operation flag,
456 		 * when the application-supplied buffer is too small, or
457 		 * the application asks for the length of buffer to hold
458 		 * the plaintext.
459 		 */
460 		REFRELE(session_p, ses_lock_held);
461 		return (rv);
462 	}
463 
464 clean_exit:
465 	/* Terminates the active decrypt operation */
466 	(void) pthread_mutex_lock(&session_p->session_mutex);
467 	session_p->decrypt.flags = 0;
468 	ses_lock_held = B_TRUE;
469 	REFRELE(session_p, ses_lock_held);
470 
471 	return (rv);
472 }
473