xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelEncrypt.c (revision fbd1c0dae6f4a2ccc2ce0527c7f19d3dd5ea90b8)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <pthread.h>
29 #include <stdlib.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 #include "kernelObject.h"
36 
37 
38 CK_RV
39 C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
40     CK_OBJECT_HANDLE hKey)
41 {
42 
43 	CK_RV rv;
44 	kernel_session_t *session_p;
45 	kernel_object_t	*key_p;
46 	boolean_t ses_lock_held = B_FALSE;
47 	crypto_encrypt_init_t encrypt_init;
48 	crypto_mech_type_t k_mech_type;
49 	int r;
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 	(void) pthread_mutex_unlock(&session_p->session_mutex);
122 	ses_lock_held = B_FALSE;
123 	encrypt_init.ei_mech.cm_type = k_mech_type;
124 	encrypt_init.ei_mech.cm_param = pMechanism->pParameter;
125 	encrypt_init.ei_mech.cm_param_len = pMechanism->ulParameterLen;
126 
127 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_INIT, &encrypt_init)) < 0) {
128 		if (errno != EINTR)
129 			break;
130 	}
131 	if (r < 0) {
132 		rv = CKR_FUNCTION_FAILED;
133 	} else {
134 		if (encrypt_init.ei_return_value != CRYPTO_SUCCESS) {
135 			rv = crypto2pkcs11_error_number(
136 			    encrypt_init.ei_return_value);
137 		}
138 	}
139 
140 	/* Free memory allocated for decrypt_init.di_key */
141 	if (key_p->is_lib_obj) {
142 		if (key_p->class == CKO_SECRET_KEY) {
143 			free(encrypt_init.ei_key.ck_data);
144 		} else if (key_p->key_type == CKK_RSA) {
145 			free_key_attributes(&encrypt_init.ei_key);
146 		}
147 	}
148 
149 	if (rv != CKR_OK) {
150 		(void) pthread_mutex_lock(&session_p->session_mutex);
151 		session_p->encrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
152 		ses_lock_held = B_TRUE;
153 	}
154 
155 clean_exit:
156 	OBJ_REFRELE(key_p);
157 	REFRELE(session_p, ses_lock_held);
158 	return (rv);
159 }
160 
161 
162 CK_RV
163 C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
164     CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
165 {
166 
167 	CK_RV rv;
168 	kernel_session_t *session_p;
169 	boolean_t ses_lock_held = B_FALSE;
170 	boolean_t inplace;
171 	crypto_encrypt_t encrypt;
172 	int r;
173 
174 	if (!kernel_initialized)
175 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
176 
177 	/* Obtain the session pointer. */
178 	rv = handle2session(hSession, &session_p);
179 	if (rv != CKR_OK)
180 		return (rv);
181 
182 	if (pData == NULL) {
183 		rv = CKR_ARGUMENTS_BAD;
184 		goto clean_exit;
185 	}
186 
187 	/*
188 	 * Only check if pulEncryptedDataLen is NULL.
189 	 * No need to check if pEncryptedData is NULL because
190 	 * application might just ask for the length of buffer to hold
191 	 * the ciphertext.
192 	 */
193 	if (pulEncryptedDataLen == NULL) {
194 		rv = CKR_ARGUMENTS_BAD;
195 		goto clean_exit;
196 	}
197 
198 	(void) pthread_mutex_lock(&session_p->session_mutex);
199 	ses_lock_held = B_TRUE;
200 
201 	/* Application must call C_EncryptInit before calling C_Encrypt. */
202 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
203 		REFRELE(session_p, ses_lock_held);
204 		return (CKR_OPERATION_NOT_INITIALIZED);
205 	}
206 
207 	/*
208 	 * C_Encrypt must be called without intervening C_EncryptUpdate
209 	 * calls.
210 	 */
211 	if (session_p->encrypt.flags & CRYPTO_OPERATION_UPDATE) {
212 		/*
213 		 * C_Encrypt can not be used to terminate a multi-part
214 		 * operation, so we'll leave the active encrypt operation
215 		 * flag on and let the application continue with the
216 		 * encrypt update operation.
217 		 */
218 		REFRELE(session_p, ses_lock_held);
219 		return (CKR_FUNCTION_FAILED);
220 	}
221 
222 	encrypt.ce_session = session_p->k_session;
223 
224 	/*
225 	 * Certain mechanisms, where the length of the ciphertext is
226 	 * same as the transformed plaintext, can be optimized
227 	 * by the kernel into an in-place operation. Unfortunately,
228 	 * some applications use a ciphertext buffer that is larger
229 	 * than it needs to be. We fix that here.
230 	 */
231 	inplace = INPLACE_MECHANISM(session_p->encrypt.mech.mechanism);
232 	if (ulDataLen < *pulEncryptedDataLen && inplace) {
233 		encrypt.ce_encrlen = ulDataLen;
234 	} else {
235 		encrypt.ce_encrlen = *pulEncryptedDataLen;
236 	}
237 	(void) pthread_mutex_unlock(&session_p->session_mutex);
238 	ses_lock_held = B_FALSE;
239 
240 	encrypt.ce_datalen = ulDataLen;
241 	encrypt.ce_databuf = (char *)pData;
242 	encrypt.ce_encrbuf = (char *)pEncryptedData;
243 	encrypt.ce_flags = inplace && pEncryptedData != NULL &&
244 	    encrypt.ce_encrlen == encrypt.ce_datalen ?
245 	    CRYPTO_INPLACE_OPERATION : 0;
246 
247 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT, &encrypt)) < 0) {
248 		if (errno != EINTR)
249 			break;
250 	}
251 	if (r < 0) {
252 		rv = CKR_FUNCTION_FAILED;
253 	} else {
254 		rv = crypto2pkcs11_error_number(encrypt.ce_return_value);
255 	}
256 
257 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
258 		*pulEncryptedDataLen = encrypt.ce_encrlen;
259 
260 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
261 	    (rv == CKR_OK && pEncryptedData == NULL)) {
262 		/*
263 		 * We will not terminate the active encrypt operation flag,
264 		 * when the application-supplied buffer is too small, or
265 		 * the application asks for the length of buffer to hold
266 		 * the ciphertext.
267 		 */
268 		REFRELE(session_p, ses_lock_held);
269 		return (rv);
270 	}
271 
272 clean_exit:
273 	/*
274 	 * Terminates the active encrypt operation.
275 	 * Application needs to call C_EncryptInit again for next
276 	 * encrypt operation.
277 	 */
278 	(void) pthread_mutex_lock(&session_p->session_mutex);
279 	session_p->encrypt.flags = 0;
280 	ses_lock_held = B_TRUE;
281 	REFRELE(session_p, ses_lock_held);
282 
283 	return (rv);
284 }
285 
286 
287 CK_RV
288 C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
289     CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,
290     CK_ULONG_PTR pulEncryptedPartLen)
291 {
292 
293 	CK_RV rv;
294 	kernel_session_t *session_p;
295 	boolean_t ses_lock_held = B_FALSE;
296 	crypto_encrypt_update_t encrypt_update;
297 	int r;
298 
299 	if (!kernel_initialized)
300 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
301 
302 	/* Obtain the session pointer. */
303 	rv = handle2session(hSession, &session_p);
304 	if (rv != CKR_OK)
305 		return (rv);
306 
307 	if (pPart == NULL) {
308 		rv = CKR_ARGUMENTS_BAD;
309 		goto clean_exit;
310 	}
311 
312 	/*
313 	 * Only check if pulEncryptedPartLen is NULL.
314 	 * No need to check if pEncryptedPart is NULL because
315 	 * application might just ask for the length of buffer to hold
316 	 * the ciphertext.
317 	 */
318 	if (pulEncryptedPartLen == NULL) {
319 		rv = CKR_ARGUMENTS_BAD;
320 		goto clean_exit;
321 	}
322 
323 	(void) pthread_mutex_lock(&session_p->session_mutex);
324 	ses_lock_held = B_TRUE;
325 
326 	/*
327 	 * Application must call C_EncryptInit before calling
328 	 * C_EncryptUpdate.
329 	 */
330 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
331 		REFRELE(session_p, ses_lock_held);
332 		return (CKR_OPERATION_NOT_INITIALIZED);
333 	}
334 
335 	session_p->encrypt.flags |= CRYPTO_OPERATION_UPDATE;
336 
337 	encrypt_update.eu_session = session_p->k_session;
338 	(void) pthread_mutex_unlock(&session_p->session_mutex);
339 	ses_lock_held = B_FALSE;
340 
341 	encrypt_update.eu_datalen = ulPartLen;
342 	encrypt_update.eu_databuf = (char *)pPart;
343 	encrypt_update.eu_encrlen = *pulEncryptedPartLen;
344 	encrypt_update.eu_encrbuf = (char *)pEncryptedPart;
345 
346 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_UPDATE,
347 	    &encrypt_update)) < 0) {
348 		if (errno != EINTR)
349 			break;
350 	}
351 	if (r < 0) {
352 		rv = CKR_FUNCTION_FAILED;
353 	} else {
354 		rv = crypto2pkcs11_error_number(
355 		    encrypt_update.eu_return_value);
356 	}
357 
358 	/*
359 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
360 	 * We don't terminate the current encryption operation.
361 	 */
362 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
363 		*pulEncryptedPartLen = encrypt_update.eu_encrlen;
364 		REFRELE(session_p, ses_lock_held);
365 		return (rv);
366 	}
367 
368 clean_exit:
369 	/*
370 	 * After an error occurred, terminate the current encrypt
371 	 * operation by resetting the active and update flags.
372 	 */
373 	(void) pthread_mutex_lock(&session_p->session_mutex);
374 	session_p->encrypt.flags = 0;
375 	ses_lock_held = B_TRUE;
376 	REFRELE(session_p, ses_lock_held);
377 
378 	return (rv);
379 }
380 
381 
382 CK_RV
383 C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart,
384     CK_ULONG_PTR pulLastEncryptedPartLen)
385 {
386 
387 	CK_RV rv;
388 	kernel_session_t *session_p;
389 	boolean_t ses_lock_held = B_FALSE;
390 	crypto_encrypt_final_t encrypt_final;
391 	int r;
392 
393 	if (!kernel_initialized)
394 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
395 
396 	/* Obtain the session pointer. */
397 	rv = handle2session(hSession, &session_p);
398 	if (rv != CKR_OK)
399 		return (rv);
400 
401 	if (pulLastEncryptedPartLen == NULL) {
402 		rv = CKR_ARGUMENTS_BAD;
403 		goto clean_exit;
404 	}
405 
406 	(void) pthread_mutex_lock(&session_p->session_mutex);
407 	ses_lock_held = B_TRUE;
408 
409 	/*
410 	 * Application must call C_EncryptInit before calling
411 	 * C_EncryptFinal.
412 	 */
413 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
414 		REFRELE(session_p, ses_lock_held);
415 		return (CKR_OPERATION_NOT_INITIALIZED);
416 	}
417 
418 	encrypt_final.ef_session = session_p->k_session;
419 	(void) pthread_mutex_unlock(&session_p->session_mutex);
420 	ses_lock_held = B_FALSE;
421 
422 	encrypt_final.ef_encrlen = *pulLastEncryptedPartLen;
423 	encrypt_final.ef_encrbuf = (char *)pLastEncryptedPart;
424 
425 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_FINAL,
426 	    &encrypt_final)) < 0) {
427 		if (errno != EINTR)
428 			break;
429 	}
430 	if (r < 0) {
431 		rv = CKR_FUNCTION_FAILED;
432 	} else {
433 		rv = crypto2pkcs11_error_number(encrypt_final.ef_return_value);
434 	}
435 
436 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
437 		*pulLastEncryptedPartLen = encrypt_final.ef_encrlen;
438 
439 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
440 	    (rv == CKR_OK && pLastEncryptedPart == NULL)) {
441 		/*
442 		 * We will not terminate the active encrypt operation flag,
443 		 * when the application-supplied buffer is too small, or
444 		 * the application asks for the length of buffer to hold
445 		 * the ciphertext.
446 		 */
447 		REFRELE(session_p, ses_lock_held);
448 		return (rv);
449 	}
450 
451 clean_exit:
452 	/* Terminates the active encrypt operation. */
453 	(void) pthread_mutex_lock(&session_p->session_mutex);
454 	session_p->encrypt.flags = 0;
455 	ses_lock_held = B_TRUE;
456 	REFRELE(session_p, ses_lock_held);
457 
458 	return (rv);
459 }
460