xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright 2018, Joyent, Inc.
25  */
26 
27 #include <pthread.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <sys/crypto/ioctl.h>
31 #include <security/cryptoki.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelObject.h"
35 
36 
37 CK_RV
38 C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
39     CK_OBJECT_HANDLE hKey)
40 {
41 
42 	CK_RV rv;
43 	kernel_session_t *session_p;
44 	kernel_object_t	*key_p;
45 	boolean_t ses_lock_held = B_FALSE;
46 	crypto_encrypt_init_t encrypt_init;
47 	crypto_mech_type_t k_mech_type;
48 	int r;
49 	CK_AES_CCM_PARAMS ccm_params = { 0 };
50 
51 	if (!kernel_initialized)
52 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
53 
54 	if (pMechanism == NULL) {
55 		return (CKR_ARGUMENTS_BAD);
56 	}
57 
58 	/* Get the kernel's internal mechanism number. */
59 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
60 	if (rv != CKR_OK)
61 		return (rv);
62 
63 	/* Obtain the session pointer. */
64 	rv = handle2session(hSession, &session_p);
65 	if (rv != CKR_OK)
66 		return (rv);
67 
68 	/* Obtain the object pointer. */
69 	HANDLE2OBJECT(hKey, key_p, rv);
70 	if (rv != CKR_OK) {
71 		REFRELE(session_p, ses_lock_held);
72 		return (rv);
73 	}
74 
75 	/* Check to see if key object allows for encryption. */
76 	if (key_p->is_lib_obj && !(key_p->bool_attr_mask & ENCRYPT_BOOL_ON)) {
77 		rv = CKR_KEY_TYPE_INCONSISTENT;
78 		goto clean_exit;
79 	}
80 
81 	(void) pthread_mutex_lock(&session_p->session_mutex);
82 	ses_lock_held = B_TRUE;
83 
84 	/*
85 	 * This active flag will remain ON until application calls either
86 	 * C_Encrypt or C_EncryptFinal to actually obtain the final piece
87 	 * of ciphertext.
88 	 */
89 	session_p->encrypt.flags = CRYPTO_OPERATION_ACTIVE;
90 
91 	/* set up key data */
92 	if (!key_p->is_lib_obj) {
93 		encrypt_init.ei_key.ck_format = CRYPTO_KEY_REFERENCE;
94 		encrypt_init.ei_key.ck_obj_id = key_p->k_handle;
95 	} else {
96 		if (key_p->class == CKO_SECRET_KEY) {
97 			encrypt_init.ei_key.ck_format = CRYPTO_KEY_RAW;
98 			encrypt_init.ei_key.ck_data =
99 			    get_symmetric_key_value(key_p);
100 			if (encrypt_init.ei_key.ck_data == NULL) {
101 				rv = CKR_HOST_MEMORY;
102 				goto clean_exit;
103 			}
104 			encrypt_init.ei_key.ck_length =
105 			    OBJ_SEC(key_p)->sk_value_len << 3;
106 
107 		} else if (key_p->key_type == CKK_RSA) {
108 			if (get_rsa_public_key(key_p, &encrypt_init.ei_key) !=
109 			    CKR_OK) {
110 				rv = CKR_HOST_MEMORY;
111 				goto clean_exit;
112 			}
113 		} else {
114 			rv = CKR_KEY_TYPE_INCONSISTENT;
115 			goto clean_exit;
116 		}
117 	}
118 
119 	encrypt_init.ei_session = session_p->k_session;
120 	session_p->encrypt.mech = *pMechanism;
121 
122 	/* Cache this capability value for efficiency */
123 	if (INPLACE_MECHANISM(session_p->encrypt.mech.mechanism)) {
124 		session_p->encrypt.flags |= CRYPTO_OPERATION_INPLACE_OK;
125 	}
126 	(void) pthread_mutex_unlock(&session_p->session_mutex);
127 
128 	ses_lock_held = B_FALSE;
129 	encrypt_init.ei_mech.cm_type = k_mech_type;
130 	encrypt_init.ei_mech.cm_param = pMechanism->pParameter;
131 	encrypt_init.ei_mech.cm_param_len = pMechanism->ulParameterLen;
132 
133 	/*
134 	 * PKCS#11 uses CK_CCM_PARAMS as its mechanism parameter, while the
135 	 * kernel uses CK_AES_CCM_PARAMS.  Unlike
136 	 * CK_GCM_PARAMS / CK_AES_GCM_PARAMS, the two definitions are not
137 	 * equivalent -- the fields are defined in different orders, so
138 	 * we much translate.
139 	 */
140 	if (session_p->encrypt.mech.mechanism == CKM_AES_CCM) {
141 		if (pMechanism->ulParameterLen != sizeof (CK_CCM_PARAMS)) {
142 			rv = CKR_MECHANISM_PARAM_INVALID;
143 			goto clean_exit;
144 		}
145 		p11_to_kernel_ccm_params(pMechanism->pParameter, &ccm_params);
146 		encrypt_init.ei_mech.cm_param = (caddr_t)&ccm_params;
147 		encrypt_init.ei_mech.cm_param_len = sizeof (ccm_params);
148 	}
149 
150 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_INIT, &encrypt_init)) < 0) {
151 		if (errno != EINTR)
152 			break;
153 	}
154 	if (r < 0) {
155 		rv = CKR_FUNCTION_FAILED;
156 	} else {
157 		if (encrypt_init.ei_return_value != CRYPTO_SUCCESS) {
158 			rv = crypto2pkcs11_error_number(
159 			    encrypt_init.ei_return_value);
160 		}
161 	}
162 
163 	/* Free memory allocated for decrypt_init.di_key */
164 	if (key_p->is_lib_obj) {
165 		if (key_p->class == CKO_SECRET_KEY) {
166 			free(encrypt_init.ei_key.ck_data);
167 		} else if (key_p->key_type == CKK_RSA) {
168 			free_key_attributes(&encrypt_init.ei_key);
169 		}
170 	}
171 
172 	if (rv != CKR_OK) {
173 		(void) pthread_mutex_lock(&session_p->session_mutex);
174 		session_p->encrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
175 		ses_lock_held = B_TRUE;
176 	}
177 
178 clean_exit:
179 	/*
180 	 * ccm_params does not contain any key material -- just lengths and
181 	 * pointers, therefore it does not need to be zeroed on exit.
182 	 */
183 	OBJ_REFRELE(key_p);
184 	REFRELE(session_p, ses_lock_held);
185 	return (rv);
186 }
187 
188 
189 CK_RV
190 C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
191     CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
192 {
193 
194 	CK_RV rv;
195 	kernel_session_t *session_p;
196 	boolean_t ses_lock_held = B_FALSE;
197 	boolean_t inplace;
198 	crypto_encrypt_t encrypt;
199 	int r;
200 
201 	if (!kernel_initialized)
202 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
203 
204 	/* Obtain the session pointer. */
205 	rv = handle2session(hSession, &session_p);
206 	if (rv != CKR_OK)
207 		return (rv);
208 
209 	/*
210 	 * Only check if pulEncryptedDataLen is NULL.
211 	 * No need to check if pEncryptedData is NULL because
212 	 * application might just ask for the length of buffer to hold
213 	 * the ciphertext.
214 	 */
215 	if (pulEncryptedDataLen == NULL) {
216 		rv = CKR_ARGUMENTS_BAD;
217 		goto clean_exit;
218 	}
219 
220 	/*
221 	 * Some encryption algs (often combined mode ciphers such as AES-GCM)
222 	 * allow 0-byte inputs to encrypt.
223 	 */
224 	if (pData == NULL && ulDataLen != 0) {
225 		rv = CKR_ARGUMENTS_BAD;
226 		goto clean_exit;
227 	}
228 
229 	(void) pthread_mutex_lock(&session_p->session_mutex);
230 	ses_lock_held = B_TRUE;
231 
232 	/* Application must call C_EncryptInit before calling C_Encrypt. */
233 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
234 		REFRELE(session_p, ses_lock_held);
235 		return (CKR_OPERATION_NOT_INITIALIZED);
236 	}
237 
238 	/*
239 	 * C_Encrypt must be called without intervening C_EncryptUpdate
240 	 * calls.
241 	 */
242 	if (session_p->encrypt.flags & CRYPTO_OPERATION_UPDATE) {
243 		/*
244 		 * C_Encrypt can not be used to terminate a multi-part
245 		 * operation, so we'll leave the active encrypt operation
246 		 * flag on and let the application continue with the
247 		 * encrypt update operation.
248 		 */
249 		REFRELE(session_p, ses_lock_held);
250 		return (CKR_FUNCTION_FAILED);
251 	}
252 
253 	encrypt.ce_session = session_p->k_session;
254 
255 	/*
256 	 * Certain mechanisms, where the length of the ciphertext is
257 	 * same as the transformed plaintext, can be optimized
258 	 * by the kernel into an in-place operation. Unfortunately,
259 	 * some applications use a ciphertext buffer that is larger
260 	 * than it needs to be. We fix that here.
261 	 */
262 	inplace = (session_p->encrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
263 	if (ulDataLen < *pulEncryptedDataLen && inplace) {
264 		encrypt.ce_encrlen = ulDataLen;
265 	} else {
266 		encrypt.ce_encrlen = *pulEncryptedDataLen;
267 	}
268 	(void) pthread_mutex_unlock(&session_p->session_mutex);
269 	ses_lock_held = B_FALSE;
270 
271 	encrypt.ce_datalen = ulDataLen;
272 	encrypt.ce_databuf = (char *)pData;
273 	encrypt.ce_encrbuf = (char *)pEncryptedData;
274 	encrypt.ce_flags =
275 	    ((inplace && (pEncryptedData != NULL)) ||
276 	    (pData == pEncryptedData)) &&
277 	    (encrypt.ce_encrlen == encrypt.ce_datalen) ?
278 	    CRYPTO_INPLACE_OPERATION : 0;
279 
280 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT, &encrypt)) < 0) {
281 		if (errno != EINTR)
282 			break;
283 	}
284 	if (r < 0) {
285 		rv = CKR_FUNCTION_FAILED;
286 	} else {
287 		rv = crypto2pkcs11_error_number(encrypt.ce_return_value);
288 	}
289 
290 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
291 		*pulEncryptedDataLen = encrypt.ce_encrlen;
292 
293 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
294 	    (rv == CKR_OK && pEncryptedData == NULL)) {
295 		/*
296 		 * We will not terminate the active encrypt operation flag,
297 		 * when the application-supplied buffer is too small, or
298 		 * the application asks for the length of buffer to hold
299 		 * the ciphertext.
300 		 */
301 		REFRELE(session_p, ses_lock_held);
302 		return (rv);
303 	}
304 
305 clean_exit:
306 	/*
307 	 * Terminates the active encrypt operation.
308 	 * Application needs to call C_EncryptInit again for next
309 	 * encrypt operation.
310 	 */
311 	(void) pthread_mutex_lock(&session_p->session_mutex);
312 	session_p->encrypt.flags = 0;
313 	ses_lock_held = B_TRUE;
314 	REFRELE(session_p, ses_lock_held);
315 
316 	return (rv);
317 }
318 
319 
320 CK_RV
321 C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
322     CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,
323     CK_ULONG_PTR pulEncryptedPartLen)
324 {
325 
326 	CK_RV rv;
327 	kernel_session_t *session_p;
328 	boolean_t ses_lock_held = B_FALSE;
329 	boolean_t inplace;
330 	crypto_encrypt_update_t encrypt_update;
331 	int r;
332 
333 	if (!kernel_initialized)
334 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
335 
336 	/* Obtain the session pointer. */
337 	rv = handle2session(hSession, &session_p);
338 	if (rv != CKR_OK)
339 		return (rv);
340 
341 	if (pPart == NULL) {
342 		rv = CKR_ARGUMENTS_BAD;
343 		goto clean_exit;
344 	}
345 
346 	/*
347 	 * Only check if pulEncryptedPartLen is NULL.
348 	 * No need to check if pEncryptedPart is NULL because
349 	 * application might just ask for the length of buffer to hold
350 	 * the ciphertext.
351 	 */
352 	if (pulEncryptedPartLen == NULL) {
353 		rv = CKR_ARGUMENTS_BAD;
354 		goto clean_exit;
355 	}
356 
357 	(void) pthread_mutex_lock(&session_p->session_mutex);
358 	ses_lock_held = B_TRUE;
359 
360 	/*
361 	 * Application must call C_EncryptInit before calling
362 	 * C_EncryptUpdate.
363 	 */
364 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
365 		REFRELE(session_p, ses_lock_held);
366 		return (CKR_OPERATION_NOT_INITIALIZED);
367 	}
368 
369 	session_p->encrypt.flags |= CRYPTO_OPERATION_UPDATE;
370 
371 	encrypt_update.eu_session = session_p->k_session;
372 	(void) pthread_mutex_unlock(&session_p->session_mutex);
373 	ses_lock_held = B_FALSE;
374 
375 	encrypt_update.eu_datalen = ulPartLen;
376 	encrypt_update.eu_databuf = (char *)pPart;
377 	encrypt_update.eu_encrlen = *pulEncryptedPartLen;
378 	encrypt_update.eu_encrbuf = (char *)pEncryptedPart;
379 
380 	inplace = (session_p->encrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
381 	encrypt_update.eu_flags =
382 	    ((inplace && (pEncryptedPart != NULL)) ||
383 	    (pPart == pEncryptedPart)) &&
384 	    (encrypt_update.eu_encrlen == encrypt_update.eu_datalen) ?
385 	    CRYPTO_INPLACE_OPERATION : 0;
386 
387 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_UPDATE,
388 	    &encrypt_update)) < 0) {
389 		if (errno != EINTR)
390 			break;
391 	}
392 	if (r < 0) {
393 		rv = CKR_FUNCTION_FAILED;
394 	} else {
395 		rv = crypto2pkcs11_error_number(
396 		    encrypt_update.eu_return_value);
397 	}
398 
399 	/*
400 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
401 	 * We don't terminate the current encryption operation.
402 	 */
403 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
404 		*pulEncryptedPartLen = encrypt_update.eu_encrlen;
405 		REFRELE(session_p, ses_lock_held);
406 		return (rv);
407 	}
408 
409 clean_exit:
410 	/*
411 	 * After an error occurred, terminate the current encrypt
412 	 * operation by resetting the active and update flags.
413 	 */
414 	(void) pthread_mutex_lock(&session_p->session_mutex);
415 	session_p->encrypt.flags = 0;
416 	ses_lock_held = B_TRUE;
417 	REFRELE(session_p, ses_lock_held);
418 
419 	return (rv);
420 }
421 
422 
423 CK_RV
424 C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart,
425     CK_ULONG_PTR pulLastEncryptedPartLen)
426 {
427 
428 	CK_RV rv;
429 	kernel_session_t *session_p;
430 	boolean_t ses_lock_held = B_FALSE;
431 	crypto_encrypt_final_t encrypt_final;
432 	int r;
433 
434 	if (!kernel_initialized)
435 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
436 
437 	/* Obtain the session pointer. */
438 	rv = handle2session(hSession, &session_p);
439 	if (rv != CKR_OK)
440 		return (rv);
441 
442 	if (pulLastEncryptedPartLen == NULL) {
443 		rv = CKR_ARGUMENTS_BAD;
444 		goto clean_exit;
445 	}
446 
447 	(void) pthread_mutex_lock(&session_p->session_mutex);
448 	ses_lock_held = B_TRUE;
449 
450 	/*
451 	 * Application must call C_EncryptInit before calling
452 	 * C_EncryptFinal.
453 	 */
454 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
455 		REFRELE(session_p, ses_lock_held);
456 		return (CKR_OPERATION_NOT_INITIALIZED);
457 	}
458 
459 	encrypt_final.ef_session = session_p->k_session;
460 	(void) pthread_mutex_unlock(&session_p->session_mutex);
461 	ses_lock_held = B_FALSE;
462 
463 	encrypt_final.ef_encrlen = *pulLastEncryptedPartLen;
464 	encrypt_final.ef_encrbuf = (char *)pLastEncryptedPart;
465 
466 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_FINAL,
467 	    &encrypt_final)) < 0) {
468 		if (errno != EINTR)
469 			break;
470 	}
471 	if (r < 0) {
472 		rv = CKR_FUNCTION_FAILED;
473 	} else {
474 		rv = crypto2pkcs11_error_number(encrypt_final.ef_return_value);
475 	}
476 
477 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
478 		*pulLastEncryptedPartLen = encrypt_final.ef_encrlen;
479 
480 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
481 	    (rv == CKR_OK && pLastEncryptedPart == NULL)) {
482 		/*
483 		 * We will not terminate the active encrypt operation flag,
484 		 * when the application-supplied buffer is too small, or
485 		 * the application asks for the length of buffer to hold
486 		 * the ciphertext.
487 		 */
488 		REFRELE(session_p, ses_lock_held);
489 		return (rv);
490 	}
491 
492 clean_exit:
493 	/* Terminates the active encrypt operation. */
494 	(void) pthread_mutex_lock(&session_p->session_mutex);
495 	session_p->encrypt.flags = 0;
496 	ses_lock_held = B_TRUE;
497 	REFRELE(session_p, ses_lock_held);
498 
499 	return (rv);
500 }
501