xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelDecrypt.c (revision 355b4669e025ff377602b6fc7caaf30dbc218371)
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 		OBJ_REFRELE(key_p);
172 	}
173 
174 	REFRELE(session_p, ses_lock_held);
175 	return (rv);
176 }
177 
178 
179 
180 /*
181  * Real decrypt work. The caller doesn't hold the session lock.
182  */
183 CK_RV
184 kernel_decrypt(kernel_session_t *session_p, CK_BYTE_PTR pEncryptedData,
185     CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
186 {
187 	crypto_decrypt_t decrypt;
188 	boolean_t ses_lock_held = B_FALSE;
189 	CK_RV rv;
190 	int r;
191 
192 	(void) pthread_mutex_lock(&session_p->session_mutex);
193 	ses_lock_held = B_TRUE;
194 
195 	/* Application must call C_DecryptInit before calling C_Decrypt. */
196 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
197 		rv = CKR_OPERATION_NOT_INITIALIZED;
198 		goto clean_exit;
199 	}
200 
201 	/*
202 	 * C_Decrypt must be called without intervening C_DecryptUpdate
203 	 * calls.
204 	 */
205 	if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
206 		/*
207 		 * C_Decrypt cannot be used to terminate a multiple-part
208 		 * operation, so we'll leave the active decrypt operation
209 		 * flag on and let the application continue with the
210 		 * decrypt update operation.
211 		 */
212 		rv = CKR_FUNCTION_FAILED;
213 		goto clean_exit;
214 	}
215 
216 	decrypt.cd_session = session_p->k_session;
217 	(void) pthread_mutex_unlock(&session_p->session_mutex);
218 	ses_lock_held = B_FALSE;
219 
220 	decrypt.cd_datalen = *pulDataLen;
221 	decrypt.cd_databuf = (char *)pData;
222 	decrypt.cd_encrlen = ulEncryptedData;
223 	decrypt.cd_encrbuf = (char *)pEncryptedData;
224 
225 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT, &decrypt)) < 0) {
226 		if (errno != EINTR)
227 			break;
228 	}
229 	if (r < 0) {
230 		rv = CKR_FUNCTION_FAILED;
231 	} else {
232 		rv = crypto2pkcs11_error_number(decrypt.cd_return_value);
233 	}
234 
235 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
236 		*pulDataLen = decrypt.cd_datalen;
237 
238 clean_exit:
239 
240 	if (ses_lock_held)
241 		(void) pthread_mutex_unlock(&session_p->session_mutex);
242 
243 	return (rv);
244 }
245 
246 CK_RV
247 C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData,
248     CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
249 {
250 	CK_RV rv;
251 	kernel_session_t *session_p;
252 	boolean_t ses_lock_held = B_FALSE;
253 
254 	if (!kernel_initialized)
255 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
256 
257 	/* Obtain the session pointer. */
258 	rv = handle2session(hSession, &session_p);
259 	if (rv != CKR_OK)
260 		return (rv);
261 
262 	/*
263 	 * No need to check pData because application might
264 	 * just want to know the length of decrypted data.
265 	 */
266 	if (pulDataLen == NULL) {
267 		rv = CKR_ARGUMENTS_BAD;
268 		goto clean_exit;
269 	}
270 
271 	rv = kernel_decrypt(session_p, pEncryptedData, ulEncryptedData, pData,
272 	    pulDataLen);
273 
274 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
275 	    (rv == CKR_OK && pData == NULL)) {
276 		/*
277 		 * We will not terminate the active decrypt operation flag,
278 		 * when the application-supplied buffer is too small, or
279 		 * the application asks for the length of buffer to hold
280 		 * the plaintext.
281 		 */
282 		REFRELE(session_p, ses_lock_held);
283 		return (rv);
284 	}
285 
286 clean_exit:
287 	/*
288 	 * Terminates the active decrypt operation.
289 	 * Application needs to call C_DecryptInit again for next
290 	 * decrypt operation.
291 	 */
292 	(void) pthread_mutex_lock(&session_p->session_mutex);
293 	session_p->decrypt.flags = 0;
294 	ses_lock_held = B_TRUE;
295 	REFRELE(session_p, ses_lock_held);
296 
297 	return (rv);
298 }
299 
300 
301 CK_RV
302 C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart,
303     CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart,
304     CK_ULONG_PTR pulPartLen)
305 {
306 
307 	CK_RV rv;
308 	kernel_session_t *session_p;
309 	boolean_t ses_lock_held = B_FALSE;
310 	crypto_decrypt_update_t decrypt_update;
311 	int r;
312 
313 	if (!kernel_initialized)
314 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
315 
316 	/* Obtain the session pointer. */
317 	rv = handle2session(hSession, &session_p);
318 	if (rv != CKR_OK)
319 		return (rv);
320 
321 	if (pEncryptedPart == NULL) {
322 		rv = CKR_ARGUMENTS_BAD;
323 		goto clean_exit;
324 	}
325 
326 	/*
327 	 * Only check if pulPartLen is NULL.
328 	 * No need to check if pPart is NULL because application
329 	 * might just ask for the length of buffer to hold the
330 	 * recovered data.
331 	 */
332 	if (pulPartLen == NULL) {
333 		rv = CKR_ARGUMENTS_BAD;
334 		goto clean_exit;
335 	}
336 
337 	(void) pthread_mutex_lock(&session_p->session_mutex);
338 	ses_lock_held = B_TRUE;
339 
340 	/*
341 	 * Application must call C_DecryptInit before calling
342 	 * C_DecryptUpdate.
343 	 */
344 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
345 		REFRELE(session_p, ses_lock_held);
346 		return (CKR_OPERATION_NOT_INITIALIZED);
347 	}
348 
349 	session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
350 
351 	decrypt_update.du_session = session_p->k_session;
352 	(void) pthread_mutex_unlock(&session_p->session_mutex);
353 	ses_lock_held = B_FALSE;
354 
355 	decrypt_update.du_datalen = *pulPartLen;
356 	decrypt_update.du_databuf = (char *)pPart;
357 	decrypt_update.du_encrlen = ulEncryptedPartLen;
358 	decrypt_update.du_encrbuf = (char *)pEncryptedPart;
359 
360 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_UPDATE,
361 	    &decrypt_update)) < 0) {
362 		if (errno != EINTR)
363 			break;
364 	}
365 	if (r < 0) {
366 		rv = CKR_FUNCTION_FAILED;
367 	} else {
368 		rv = crypto2pkcs11_error_number(
369 		    decrypt_update.du_return_value);
370 	}
371 
372 	/*
373 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
374 	 * We don't terminate the current decryption operation.
375 	 */
376 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
377 		*pulPartLen = decrypt_update.du_datalen;
378 		REFRELE(session_p, ses_lock_held);
379 		return (rv);
380 	}
381 
382 clean_exit:
383 	/*
384 	 * After an error occurred, terminate the current decrypt
385 	 * operation by resetting the active and update flags.
386 	 */
387 	(void) pthread_mutex_lock(&session_p->session_mutex);
388 	session_p->decrypt.flags = 0;
389 	ses_lock_held = B_TRUE;
390 	REFRELE(session_p, ses_lock_held);
391 
392 	return (rv);
393 }
394 
395 
396 CK_RV
397 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
398     CK_ULONG_PTR pulLastPartLen)
399 {
400 
401 	CK_RV rv;
402 	kernel_session_t *session_p;
403 	boolean_t ses_lock_held = B_FALSE;
404 	crypto_decrypt_final_t decrypt_final;
405 	int r;
406 
407 	if (!kernel_initialized)
408 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
409 
410 	/* Obtain the session pointer. */
411 	rv = handle2session(hSession, &session_p);
412 	if (rv != CKR_OK)
413 		return (rv);
414 
415 	if (pulLastPartLen == NULL) {
416 		rv = CKR_ARGUMENTS_BAD;
417 		goto clean_exit;
418 	}
419 
420 	(void) pthread_mutex_lock(&session_p->session_mutex);
421 	ses_lock_held = B_TRUE;
422 
423 	/*
424 	 * Application must call C_DecryptInit before calling
425 	 * C_DecryptFinal.
426 	 */
427 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
428 		REFRELE(session_p, ses_lock_held);
429 		return (CKR_OPERATION_NOT_INITIALIZED);
430 	}
431 
432 	decrypt_final.df_session = session_p->k_session;
433 	(void) pthread_mutex_unlock(&session_p->session_mutex);
434 	ses_lock_held = B_FALSE;
435 
436 	decrypt_final.df_datalen = *pulLastPartLen;
437 	decrypt_final.df_databuf = (char *)pLastPart;
438 
439 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_FINAL,
440 	    &decrypt_final)) < 0) {
441 		if (errno != EINTR)
442 			break;
443 	}
444 	if (r < 0) {
445 		rv = CKR_FUNCTION_FAILED;
446 	} else {
447 		rv = crypto2pkcs11_error_number(decrypt_final.df_return_value);
448 	}
449 
450 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
451 		*pulLastPartLen = decrypt_final.df_datalen;
452 
453 	if (rv == CKR_BUFFER_TOO_SMALL ||
454 	    (rv == CKR_OK && pLastPart == NULL)) {
455 		/*
456 		 * We will not terminate the active decrypt operation flag,
457 		 * when the application-supplied buffer is too small, or
458 		 * the application asks for the length of buffer to hold
459 		 * the plaintext.
460 		 */
461 		REFRELE(session_p, ses_lock_held);
462 		return (rv);
463 	}
464 
465 clean_exit:
466 	/* Terminates the active decrypt operation */
467 	(void) pthread_mutex_lock(&session_p->session_mutex);
468 	session_p->decrypt.flags = 0;
469 	ses_lock_held = B_TRUE;
470 	REFRELE(session_p, ses_lock_held);
471 
472 	return (rv);
473 }
474