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 CK_RV
40 C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
41     CK_OBJECT_HANDLE hKey)
42 {
43 
44 	CK_RV rv;
45 	kernel_session_t *session_p;
46 	kernel_object_t	*key_p;
47 	boolean_t ses_lock_held = B_FALSE;
48 	crypto_encrypt_init_t encrypt_init;
49 	crypto_mech_type_t k_mech_type;
50 	int r;
51 
52 	if (!kernel_initialized)
53 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
54 
55 	if (pMechanism == NULL) {
56 		return (CKR_ARGUMENTS_BAD);
57 	}
58 
59 	/* Get the kernel's internal mechanism number. */
60 	rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
61 	if (rv != CKR_OK)
62 		return (rv);
63 
64 	/* Obtain the session pointer. */
65 	rv = handle2session(hSession, &session_p);
66 	if (rv != CKR_OK)
67 		return (rv);
68 
69 	/* Obtain the object pointer. */
70 	HANDLE2OBJECT(hKey, key_p, rv);
71 	if (rv != CKR_OK) {
72 		REFRELE(session_p, ses_lock_held);
73 		return (rv);
74 	}
75 
76 	/* Check to see if key object allows for encryption. */
77 	if (key_p->is_lib_obj && !(key_p->bool_attr_mask & ENCRYPT_BOOL_ON)) {
78 		rv = CKR_KEY_TYPE_INCONSISTENT;
79 		goto clean_exit;
80 	}
81 
82 	(void) pthread_mutex_lock(&session_p->session_mutex);
83 	ses_lock_held = B_TRUE;
84 
85 	/*
86 	 * This active flag will remain ON until application calls either
87 	 * C_Encrypt or C_EncryptFinal to actually obtain the final piece
88 	 * of ciphertext.
89 	 */
90 	session_p->encrypt.flags = CRYPTO_OPERATION_ACTIVE;
91 
92 	/* set up key data */
93 	if (!key_p->is_lib_obj) {
94 		encrypt_init.ei_key.ck_format = CRYPTO_KEY_REFERENCE;
95 		encrypt_init.ei_key.ck_obj_id = key_p->k_handle;
96 	} else {
97 		if (key_p->class == CKO_SECRET_KEY) {
98 			encrypt_init.ei_key.ck_format = CRYPTO_KEY_RAW;
99 			encrypt_init.ei_key.ck_data =
100 			    get_symmetric_key_value(key_p);
101 			if (encrypt_init.ei_key.ck_data == NULL) {
102 				rv = CKR_HOST_MEMORY;
103 				goto clean_exit;
104 			}
105 			encrypt_init.ei_key.ck_length =
106 				OBJ_SEC(key_p)->sk_value_len << 3;
107 
108 		} else if (key_p->key_type == CKK_RSA) {
109 			if (get_rsa_public_key(key_p, &encrypt_init.ei_key) !=
110 			    CKR_OK) {
111 				rv = CKR_HOST_MEMORY;
112 				goto clean_exit;
113 			}
114 		} else {
115 			rv = CKR_KEY_TYPE_INCONSISTENT;
116 			goto clean_exit;
117 		}
118 	}
119 
120 	encrypt_init.ei_session = session_p->k_session;
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 	crypto_encrypt_t encrypt;
171 	int r;
172 
173 	if (!kernel_initialized)
174 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
175 
176 	/* Obtain the session pointer. */
177 	rv = handle2session(hSession, &session_p);
178 	if (rv != CKR_OK)
179 		return (rv);
180 
181 	if (pData == NULL) {
182 		rv = CKR_ARGUMENTS_BAD;
183 		goto clean_exit;
184 	}
185 
186 	/*
187 	 * Only check if pulEncryptedDataLen is NULL.
188 	 * No need to check if pEncryptedData is NULL because
189 	 * application might just ask for the length of buffer to hold
190 	 * the ciphertext.
191 	 */
192 	if (pulEncryptedDataLen == NULL) {
193 		rv = CKR_ARGUMENTS_BAD;
194 		goto clean_exit;
195 	}
196 
197 	(void) pthread_mutex_lock(&session_p->session_mutex);
198 	ses_lock_held = B_TRUE;
199 
200 	/* Application must call C_EncryptInit before calling C_Encrypt. */
201 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
202 		REFRELE(session_p, ses_lock_held);
203 		return (CKR_OPERATION_NOT_INITIALIZED);
204 	}
205 
206 	/*
207 	 * C_Encrypt must be called without intervening C_EncryptUpdate
208 	 * calls.
209 	 */
210 	if (session_p->encrypt.flags & CRYPTO_OPERATION_UPDATE) {
211 		/*
212 		 * C_Encrypt can not be used to terminate a multi-part
213 		 * operation, so we'll leave the active encrypt operation
214 		 * flag on and let the application continue with the
215 		 * encrypt update operation.
216 		 */
217 		REFRELE(session_p, ses_lock_held);
218 		return (CKR_FUNCTION_FAILED);
219 	}
220 
221 	encrypt.ce_session = session_p->k_session;
222 	(void) pthread_mutex_unlock(&session_p->session_mutex);
223 	ses_lock_held = B_FALSE;
224 
225 	encrypt.ce_datalen = ulDataLen;
226 	encrypt.ce_databuf = (char *)pData;
227 	encrypt.ce_encrlen = *pulEncryptedDataLen;
228 	encrypt.ce_encrbuf = (char *)pEncryptedData;
229 
230 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT, &encrypt)) < 0) {
231 		if (errno != EINTR)
232 			break;
233 	}
234 	if (r < 0) {
235 		rv = CKR_FUNCTION_FAILED;
236 	} else {
237 		rv = crypto2pkcs11_error_number(encrypt.ce_return_value);
238 	}
239 
240 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
241 		*pulEncryptedDataLen = encrypt.ce_encrlen;
242 
243 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
244 	    (rv == CKR_OK && pEncryptedData == NULL)) {
245 		/*
246 		 * We will not terminate the active encrypt operation flag,
247 		 * when the application-supplied buffer is too small, or
248 		 * the application asks for the length of buffer to hold
249 		 * the ciphertext.
250 		 */
251 		REFRELE(session_p, ses_lock_held);
252 		return (rv);
253 	}
254 
255 clean_exit:
256 	/*
257 	 * Terminates the active encrypt operation.
258 	 * Application needs to call C_EncryptInit again for next
259 	 * encrypt operation.
260 	 */
261 	(void) pthread_mutex_lock(&session_p->session_mutex);
262 	session_p->encrypt.flags = 0;
263 	ses_lock_held = B_TRUE;
264 	REFRELE(session_p, ses_lock_held);
265 
266 	return (rv);
267 }
268 
269 
270 CK_RV
271 C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
272     CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,
273     CK_ULONG_PTR pulEncryptedPartLen)
274 {
275 
276 	CK_RV rv;
277 	kernel_session_t *session_p;
278 	boolean_t ses_lock_held = B_FALSE;
279 	crypto_encrypt_update_t encrypt_update;
280 	int r;
281 
282 	if (!kernel_initialized)
283 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
284 
285 	/* Obtain the session pointer. */
286 	rv = handle2session(hSession, &session_p);
287 	if (rv != CKR_OK)
288 		return (rv);
289 
290 	if (pPart == NULL) {
291 		rv = CKR_ARGUMENTS_BAD;
292 		goto clean_exit;
293 	}
294 
295 	/*
296 	 * Only check if pulEncryptedPartLen is NULL.
297 	 * No need to check if pEncryptedPart is NULL because
298 	 * application might just ask for the length of buffer to hold
299 	 * the ciphertext.
300 	 */
301 	if (pulEncryptedPartLen == NULL) {
302 		rv = CKR_ARGUMENTS_BAD;
303 		goto clean_exit;
304 	}
305 
306 	(void) pthread_mutex_lock(&session_p->session_mutex);
307 	ses_lock_held = B_TRUE;
308 
309 	/*
310 	 * Application must call C_EncryptInit before calling
311 	 * C_EncryptUpdate.
312 	 */
313 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
314 		REFRELE(session_p, ses_lock_held);
315 		return (CKR_OPERATION_NOT_INITIALIZED);
316 	}
317 
318 	session_p->encrypt.flags |= CRYPTO_OPERATION_UPDATE;
319 
320 	encrypt_update.eu_session = session_p->k_session;
321 	(void) pthread_mutex_unlock(&session_p->session_mutex);
322 	ses_lock_held = B_FALSE;
323 
324 	encrypt_update.eu_datalen = ulPartLen;
325 	encrypt_update.eu_databuf = (char *)pPart;
326 	encrypt_update.eu_encrlen = *pulEncryptedPartLen;
327 	encrypt_update.eu_encrbuf = (char *)pEncryptedPart;
328 
329 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_UPDATE,
330 	    &encrypt_update)) < 0) {
331 		if (errno != EINTR)
332 			break;
333 	}
334 	if (r < 0) {
335 		rv = CKR_FUNCTION_FAILED;
336 	} else {
337 		rv = crypto2pkcs11_error_number(
338 		    encrypt_update.eu_return_value);
339 	}
340 
341 	/*
342 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
343 	 * We don't terminate the current encryption operation.
344 	 */
345 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
346 		*pulEncryptedPartLen = encrypt_update.eu_encrlen;
347 		REFRELE(session_p, ses_lock_held);
348 		return (rv);
349 	}
350 
351 clean_exit:
352 	/*
353 	 * After an error occurred, terminate the current encrypt
354 	 * operation by resetting the active and update flags.
355 	 */
356 	(void) pthread_mutex_lock(&session_p->session_mutex);
357 	session_p->encrypt.flags = 0;
358 	ses_lock_held = B_TRUE;
359 	REFRELE(session_p, ses_lock_held);
360 
361 	return (rv);
362 }
363 
364 
365 CK_RV
366 C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart,
367     CK_ULONG_PTR pulLastEncryptedPartLen)
368 {
369 
370 	CK_RV rv;
371 	kernel_session_t *session_p;
372 	boolean_t ses_lock_held = B_FALSE;
373 	crypto_encrypt_final_t encrypt_final;
374 	int r;
375 
376 	if (!kernel_initialized)
377 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
378 
379 	/* Obtain the session pointer. */
380 	rv = handle2session(hSession, &session_p);
381 	if (rv != CKR_OK)
382 		return (rv);
383 
384 	if (pulLastEncryptedPartLen == NULL) {
385 		rv = CKR_ARGUMENTS_BAD;
386 		goto clean_exit;
387 	}
388 
389 	(void) pthread_mutex_lock(&session_p->session_mutex);
390 	ses_lock_held = B_TRUE;
391 
392 	/*
393 	 * Application must call C_EncryptInit before calling
394 	 * C_EncryptFinal.
395 	 */
396 	if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
397 		REFRELE(session_p, ses_lock_held);
398 		return (CKR_OPERATION_NOT_INITIALIZED);
399 	}
400 
401 	encrypt_final.ef_session = session_p->k_session;
402 	(void) pthread_mutex_unlock(&session_p->session_mutex);
403 	ses_lock_held = B_FALSE;
404 
405 	encrypt_final.ef_encrlen = *pulLastEncryptedPartLen;
406 	encrypt_final.ef_encrbuf = (char *)pLastEncryptedPart;
407 
408 	while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_FINAL,
409 	    &encrypt_final)) < 0) {
410 		if (errno != EINTR)
411 			break;
412 	}
413 	if (r < 0) {
414 		rv = CKR_FUNCTION_FAILED;
415 	} else {
416 		rv = crypto2pkcs11_error_number(encrypt_final.ef_return_value);
417 	}
418 
419 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
420 		*pulLastEncryptedPartLen = encrypt_final.ef_encrlen;
421 
422 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
423 	    (rv == CKR_OK && pLastEncryptedPart == NULL)) {
424 		/*
425 		 * We will not terminate the active encrypt operation flag,
426 		 * when the application-supplied buffer is too small, or
427 		 * the application asks for the length of buffer to hold
428 		 * the ciphertext.
429 		 */
430 		REFRELE(session_p, ses_lock_held);
431 		return (rv);
432 	}
433 
434 clean_exit:
435 	/* Terminates the active encrypt operation. */
436 	(void) pthread_mutex_lock(&session_p->session_mutex);
437 	session_p->encrypt.flags = 0;
438 	ses_lock_held = B_TRUE;
439 	REFRELE(session_p, ses_lock_held);
440 
441 	return (rv);
442 }
443