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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include <sys/crypto/ioctl.h>
30 #include <security/cryptoki.h>
31 #include "kernelGlobal.h"
32 #include "kernelSession.h"
33 #include "kernelObject.h"
37 C_EncryptInit(CK_SESSION_HANDLE hSession
, CK_MECHANISM_PTR pMechanism
,
38 CK_OBJECT_HANDLE hKey
)
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
;
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
);
61 /* Obtain the session pointer. */
62 rv
= handle2session(hSession
, &session_p
);
66 /* Obtain the object pointer. */
67 HANDLE2OBJECT(hKey
, key_p
, rv
);
69 REFRELE(session_p
, ses_lock_held
);
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
;
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
87 session_p
->encrypt
.flags
= CRYPTO_OPERATION_ACTIVE
;
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
;
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
) {
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
) !=
108 rv
= CKR_HOST_MEMORY
;
112 rv
= CKR_KEY_TYPE_INCONSISTENT
;
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) {
136 rv
= CKR_FUNCTION_FAILED
;
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
);
154 (void) pthread_mutex_lock(&session_p
->session_mutex
);
155 session_p
->encrypt
.flags
&= ~CRYPTO_OPERATION_ACTIVE
;
156 ses_lock_held
= B_TRUE
;
161 REFRELE(session_p
, ses_lock_held
);
167 C_Encrypt(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pData
, CK_ULONG ulDataLen
,
168 CK_BYTE_PTR pEncryptedData
, CK_ULONG_PTR pulEncryptedDataLen
)
172 kernel_session_t
*session_p
;
173 boolean_t ses_lock_held
= B_FALSE
;
175 crypto_encrypt_t encrypt
;
178 if (!kernel_initialized
)
179 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
181 /* Obtain the session pointer. */
182 rv
= handle2session(hSession
, &session_p
);
187 rv
= CKR_ARGUMENTS_BAD
;
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
197 if (pulEncryptedDataLen
== NULL
) {
198 rv
= CKR_ARGUMENTS_BAD
;
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
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
;
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
;
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) {
258 rv
= CKR_FUNCTION_FAILED
;
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
274 REFRELE(session_p
, ses_lock_held
);
280 * Terminates the active encrypt operation.
281 * Application needs to call C_EncryptInit again for next
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
);
294 C_EncryptUpdate(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pPart
,
295 CK_ULONG ulPartLen
, CK_BYTE_PTR pEncryptedPart
,
296 CK_ULONG_PTR pulEncryptedPartLen
)
300 kernel_session_t
*session_p
;
301 boolean_t ses_lock_held
= B_FALSE
;
303 crypto_encrypt_update_t encrypt_update
;
306 if (!kernel_initialized
)
307 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
309 /* Obtain the session pointer. */
310 rv
= handle2session(hSession
, &session_p
);
315 rv
= CKR_ARGUMENTS_BAD
;
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
325 if (pulEncryptedPartLen
== NULL
) {
326 rv
= CKR_ARGUMENTS_BAD
;
330 (void) pthread_mutex_lock(&session_p
->session_mutex
);
331 ses_lock_held
= B_TRUE
;
334 * Application must call C_EncryptInit before calling
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) {
366 rv
= CKR_FUNCTION_FAILED
;
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
);
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
);
397 C_EncryptFinal(CK_SESSION_HANDLE hSession
, CK_BYTE_PTR pLastEncryptedPart
,
398 CK_ULONG_PTR pulLastEncryptedPartLen
)
402 kernel_session_t
*session_p
;
403 boolean_t ses_lock_held
= B_FALSE
;
404 crypto_encrypt_final_t encrypt_final
;
407 if (!kernel_initialized
)
408 return (CKR_CRYPTOKI_NOT_INITIALIZED
);
410 /* Obtain the session pointer. */
411 rv
= handle2session(hSession
, &session_p
);
415 if (pulLastEncryptedPartLen
== NULL
) {
416 rv
= CKR_ARGUMENTS_BAD
;
420 (void) pthread_mutex_lock(&session_p
->session_mutex
);
421 ses_lock_held
= B_TRUE
;
424 * Application must call C_EncryptInit before calling
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) {
445 rv
= CKR_FUNCTION_FAILED
;
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
461 REFRELE(session_p
, ses_lock_held
);
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
);