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