dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / pkcs11 / pkcs11_kernel / common / kernelEncrypt.c
blobd27945f87748bdb0f2d8cc1a7f06d340fd3ae739
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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"
36 CK_RV
37 C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
38 CK_OBJECT_HANDLE hKey)
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;
49 if (!kernel_initialized)
50 return (CKR_CRYPTOKI_NOT_INITIALIZED);
52 if (pMechanism == NULL) {
53 return (CKR_ARGUMENTS_BAD);
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);
61 /* Obtain the session pointer. */
62 rv = handle2session(hSession, &session_p);
63 if (rv != CKR_OK)
64 return (rv);
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);
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;
79 (void) pthread_mutex_lock(&session_p->session_mutex);
80 ses_lock_held = B_TRUE;
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.
87 session_p->encrypt.flags = CRYPTO_OPERATION_ACTIVE;
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;
102 encrypt_init.ei_key.ck_length =
103 OBJ_SEC(key_p)->sk_value_len << 3;
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;
111 } else {
112 rv = CKR_KEY_TYPE_INCONSISTENT;
113 goto clean_exit;
117 encrypt_init.ei_session = session_p->k_session;
118 session_p->encrypt.mech = *pMechanism;
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;
124 (void) pthread_mutex_unlock(&session_p->session_mutex);
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;
131 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_INIT, &encrypt_init)) < 0) {
132 if (errno != EINTR)
133 break;
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);
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);
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;
159 clean_exit:
160 OBJ_REFRELE(key_p);
161 REFRELE(session_p, ses_lock_held);
162 return (rv);
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)
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;
178 if (!kernel_initialized)
179 return (CKR_CRYPTOKI_NOT_INITIALIZED);
181 /* Obtain the session pointer. */
182 rv = handle2session(hSession, &session_p);
183 if (rv != CKR_OK)
184 return (rv);
186 if (pData == NULL) {
187 rv = CKR_ARGUMENTS_BAD;
188 goto clean_exit;
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.
197 if (pulEncryptedDataLen == NULL) {
198 rv = CKR_ARGUMENTS_BAD;
199 goto clean_exit;
202 (void) pthread_mutex_lock(&session_p->session_mutex);
203 ses_lock_held = B_TRUE;
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);
212 * C_Encrypt must be called without intervening C_EncryptUpdate
213 * calls.
215 if (session_p->encrypt.flags & CRYPTO_OPERATION_UPDATE) {
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.
222 REFRELE(session_p, ses_lock_held);
223 return (CKR_FUNCTION_FAILED);
226 encrypt.ce_session = session_p->k_session;
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.
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;
241 (void) pthread_mutex_unlock(&session_p->session_mutex);
242 ses_lock_held = B_FALSE;
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;
253 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT, &encrypt)) < 0) {
254 if (errno != EINTR)
255 break;
257 if (r < 0) {
258 rv = CKR_FUNCTION_FAILED;
259 } else {
260 rv = crypto2pkcs11_error_number(encrypt.ce_return_value);
263 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
264 *pulEncryptedDataLen = encrypt.ce_encrlen;
266 if ((rv == CKR_BUFFER_TOO_SMALL) ||
267 (rv == CKR_OK && pEncryptedData == NULL)) {
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.
274 REFRELE(session_p, ses_lock_held);
275 return (rv);
278 clean_exit:
280 * Terminates the active encrypt operation.
281 * Application needs to call C_EncryptInit again for next
282 * encrypt operation.
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);
289 return (rv);
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)
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;
306 if (!kernel_initialized)
307 return (CKR_CRYPTOKI_NOT_INITIALIZED);
309 /* Obtain the session pointer. */
310 rv = handle2session(hSession, &session_p);
311 if (rv != CKR_OK)
312 return (rv);
314 if (pPart == NULL) {
315 rv = CKR_ARGUMENTS_BAD;
316 goto clean_exit;
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.
325 if (pulEncryptedPartLen == NULL) {
326 rv = CKR_ARGUMENTS_BAD;
327 goto clean_exit;
330 (void) pthread_mutex_lock(&session_p->session_mutex);
331 ses_lock_held = B_TRUE;
334 * Application must call C_EncryptInit before calling
335 * C_EncryptUpdate.
337 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
338 REFRELE(session_p, ses_lock_held);
339 return (CKR_OPERATION_NOT_INITIALIZED);
342 session_p->encrypt.flags |= CRYPTO_OPERATION_UPDATE;
344 encrypt_update.eu_session = session_p->k_session;
345 (void) pthread_mutex_unlock(&session_p->session_mutex);
346 ses_lock_held = B_FALSE;
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;
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;
360 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_UPDATE,
361 &encrypt_update)) < 0) {
362 if (errno != EINTR)
363 break;
365 if (r < 0) {
366 rv = CKR_FUNCTION_FAILED;
367 } else {
368 rv = crypto2pkcs11_error_number(
369 encrypt_update.eu_return_value);
373 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
374 * We don't terminate the current encryption operation.
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);
382 clean_exit:
384 * After an error occurred, terminate the current encrypt
385 * operation by resetting the active and update flags.
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);
392 return (rv);
396 CK_RV
397 C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart,
398 CK_ULONG_PTR pulLastEncryptedPartLen)
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;
407 if (!kernel_initialized)
408 return (CKR_CRYPTOKI_NOT_INITIALIZED);
410 /* Obtain the session pointer. */
411 rv = handle2session(hSession, &session_p);
412 if (rv != CKR_OK)
413 return (rv);
415 if (pulLastEncryptedPartLen == NULL) {
416 rv = CKR_ARGUMENTS_BAD;
417 goto clean_exit;
420 (void) pthread_mutex_lock(&session_p->session_mutex);
421 ses_lock_held = B_TRUE;
424 * Application must call C_EncryptInit before calling
425 * C_EncryptFinal.
427 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
428 REFRELE(session_p, ses_lock_held);
429 return (CKR_OPERATION_NOT_INITIALIZED);
432 encrypt_final.ef_session = session_p->k_session;
433 (void) pthread_mutex_unlock(&session_p->session_mutex);
434 ses_lock_held = B_FALSE;
436 encrypt_final.ef_encrlen = *pulLastEncryptedPartLen;
437 encrypt_final.ef_encrbuf = (char *)pLastEncryptedPart;
439 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_FINAL,
440 &encrypt_final)) < 0) {
441 if (errno != EINTR)
442 break;
444 if (r < 0) {
445 rv = CKR_FUNCTION_FAILED;
446 } else {
447 rv = crypto2pkcs11_error_number(encrypt_final.ef_return_value);
450 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
451 *pulLastEncryptedPartLen = encrypt_final.ef_encrlen;
453 if ((rv == CKR_BUFFER_TOO_SMALL) ||
454 (rv == CKR_OK && pLastEncryptedPart == NULL)) {
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.
461 REFRELE(session_p, ses_lock_held);
462 return (rv);
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);
472 return (rv);