dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / pkcs11 / pkcs11_kernel / common / kernelDecrypt.c
blob57b5cbae3a2c22f5e55b16a5ffebaabeca6beca6
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"
37 * Real decryptInit work. The caller doesn't hold the session lock.
39 CK_RV
40 kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
41 CK_MECHANISM_PTR pMechanism)
43 CK_RV rv;
44 crypto_decrypt_init_t decrypt_init;
45 crypto_mech_type_t k_mech_type;
46 boolean_t ses_lock_held = B_FALSE;
47 int r;
49 /* Check to see if key object allows for decryption. */
50 if (key_p->is_lib_obj && !(key_p->bool_attr_mask & DECRYPT_BOOL_ON)) {
51 return (CKR_KEY_TYPE_INCONSISTENT);
54 /* Get the kernel's internal mechanism number. */
55 rv = kernel_mech(pMechanism->mechanism, &k_mech_type);
56 if (rv != CKR_OK)
57 return (rv);
59 (void) pthread_mutex_lock(&session_p->session_mutex);
60 ses_lock_held = B_TRUE;
63 * This active flag will remain ON until application calls either
64 * C_Decrypt or C_DecryptFinal to actually obtain the final piece
65 * of plaintext.
67 session_p->decrypt.flags = CRYPTO_OPERATION_ACTIVE;
69 /* set up key data */
70 if (!key_p->is_lib_obj) {
71 decrypt_init.di_key.ck_format = CRYPTO_KEY_REFERENCE;
72 decrypt_init.di_key.ck_obj_id = key_p->k_handle;
73 } else {
74 if (key_p->class == CKO_SECRET_KEY) {
75 decrypt_init.di_key.ck_format = CRYPTO_KEY_RAW;
76 decrypt_init.di_key.ck_data =
77 get_symmetric_key_value(key_p);
78 if (decrypt_init.di_key.ck_data == NULL) {
79 rv = CKR_HOST_MEMORY;
80 goto clean_exit;
82 /* KEF key lengths are expressed in bits */
83 decrypt_init.di_key.ck_length =
84 OBJ_SEC(key_p)->sk_value_len << 3;
86 } else if (key_p->key_type == CKK_RSA) {
87 if (get_rsa_private_key(key_p, &decrypt_init.di_key) !=
88 CKR_OK) {
89 rv = CKR_HOST_MEMORY;
90 goto clean_exit;
92 } else {
93 rv = CKR_KEY_TYPE_INCONSISTENT;
94 goto clean_exit;
98 decrypt_init.di_session = session_p->k_session;
99 session_p->decrypt.mech = *pMechanism;
101 /* Cache this capability value for efficiency */
102 if (INPLACE_MECHANISM(session_p->decrypt.mech.mechanism)) {
103 session_p->decrypt.flags |= CRYPTO_OPERATION_INPLACE_OK;
105 (void) pthread_mutex_unlock(&session_p->session_mutex);
107 ses_lock_held = B_FALSE;
108 decrypt_init.di_mech.cm_type = k_mech_type;
109 decrypt_init.di_mech.cm_param = pMechanism->pParameter;
110 decrypt_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
112 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_INIT, &decrypt_init)) < 0) {
113 if (errno != EINTR)
114 break;
116 if (r < 0) {
117 rv = CKR_FUNCTION_FAILED;
118 } else {
119 rv = crypto2pkcs11_error_number(decrypt_init.di_return_value);
122 /* Free memory allocated for decrypt_init.di_key */
123 if (key_p->is_lib_obj) {
124 if (key_p->class == CKO_SECRET_KEY) {
125 free(decrypt_init.di_key.ck_data);
126 } else if (key_p->key_type == CKK_RSA) {
127 free_key_attributes(&decrypt_init.di_key);
131 clean_exit:
133 if (!ses_lock_held) {
134 (void) pthread_mutex_lock(&session_p->session_mutex);
135 ses_lock_held = B_TRUE;
138 if (rv != CKR_OK)
139 session_p->decrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
141 if (ses_lock_held) {
142 (void) pthread_mutex_unlock(&session_p->session_mutex);
143 ses_lock_held = B_FALSE;
146 return (rv);
149 CK_RV
150 C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
151 CK_OBJECT_HANDLE hKey)
154 CK_RV rv;
155 kernel_session_t *session_p;
156 kernel_object_t *key_p;
157 boolean_t ses_lock_held = B_FALSE;
159 if (!kernel_initialized)
160 return (CKR_CRYPTOKI_NOT_INITIALIZED);
162 if (pMechanism == NULL) {
163 return (CKR_ARGUMENTS_BAD);
166 /* Obtain the session pointer. */
167 rv = handle2session(hSession, &session_p);
168 if (rv != CKR_OK)
169 return (rv);
171 /* Obtain the object pointer. */
172 HANDLE2OBJECT(hKey, key_p, rv);
173 if (rv == CKR_OK) {
174 rv = kernel_decrypt_init(session_p, key_p, pMechanism);
175 OBJ_REFRELE(key_p);
178 REFRELE(session_p, ses_lock_held);
179 return (rv);
185 * Real decrypt work. The caller doesn't hold the session lock.
187 CK_RV
188 kernel_decrypt(kernel_session_t *session_p, CK_BYTE_PTR pEncryptedData,
189 CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
191 crypto_decrypt_t decrypt;
192 boolean_t ses_lock_held = B_FALSE;
193 boolean_t inplace;
194 CK_RV rv;
195 int r;
197 (void) pthread_mutex_lock(&session_p->session_mutex);
198 ses_lock_held = B_TRUE;
200 /* Application must call C_DecryptInit before calling C_Decrypt. */
201 if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
202 rv = CKR_OPERATION_NOT_INITIALIZED;
203 goto clean_exit;
207 * C_Decrypt must be called without intervening C_DecryptUpdate
208 * calls.
210 if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
212 * C_Decrypt cannot be used to terminate a multiple-part
213 * operation, so we'll leave the active decrypt operation
214 * flag on and let the application continue with the
215 * decrypt update operation.
217 rv = CKR_FUNCTION_FAILED;
218 goto clean_exit;
221 decrypt.cd_session = session_p->k_session;
224 * Certain mechanisms, where the length of the plaintext is
225 * same as the transformed ciphertext, can be optimized
226 * by the kernel into an in-place operation. Unfortunately,
227 * some applications use a plaintext buffer that is larger
228 * than it needs to be. We fix that here.
230 inplace = (session_p->decrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
232 if (ulEncryptedData < *pulDataLen && inplace) {
233 decrypt.cd_datalen = ulEncryptedData;
234 } else {
235 decrypt.cd_datalen = *pulDataLen;
237 (void) pthread_mutex_unlock(&session_p->session_mutex);
238 ses_lock_held = B_FALSE;
240 decrypt.cd_databuf = (char *)pData;
241 decrypt.cd_encrlen = ulEncryptedData;
242 decrypt.cd_encrbuf = (char *)pEncryptedData;
243 decrypt.cd_flags =
244 ((inplace && (pData != NULL)) || (pData == pEncryptedData)) &&
245 (decrypt.cd_datalen == decrypt.cd_encrlen) ?
246 CRYPTO_INPLACE_OPERATION : 0;
248 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT, &decrypt)) < 0) {
249 if (errno != EINTR)
250 break;
252 if (r < 0) {
253 rv = CKR_FUNCTION_FAILED;
254 } else {
255 rv = crypto2pkcs11_error_number(decrypt.cd_return_value);
258 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
259 *pulDataLen = decrypt.cd_datalen;
261 clean_exit:
263 if (ses_lock_held)
264 (void) pthread_mutex_unlock(&session_p->session_mutex);
266 return (rv);
269 CK_RV
270 C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData,
271 CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
273 CK_RV rv;
274 kernel_session_t *session_p;
275 boolean_t ses_lock_held = B_FALSE;
277 if (!kernel_initialized)
278 return (CKR_CRYPTOKI_NOT_INITIALIZED);
280 /* Obtain the session pointer. */
281 rv = handle2session(hSession, &session_p);
282 if (rv != CKR_OK)
283 return (rv);
286 * No need to check pData because application might
287 * just want to know the length of decrypted data.
289 if (pulDataLen == NULL) {
290 rv = CKR_ARGUMENTS_BAD;
291 goto clean_exit;
294 rv = kernel_decrypt(session_p, pEncryptedData, ulEncryptedData, pData,
295 pulDataLen);
297 if ((rv == CKR_BUFFER_TOO_SMALL) ||
298 (rv == CKR_OK && pData == NULL)) {
300 * We will not terminate the active decrypt operation flag,
301 * when the application-supplied buffer is too small, or
302 * the application asks for the length of buffer to hold
303 * the plaintext.
305 REFRELE(session_p, ses_lock_held);
306 return (rv);
309 clean_exit:
311 * Terminates the active decrypt operation.
312 * Application needs to call C_DecryptInit again for next
313 * decrypt operation.
315 (void) pthread_mutex_lock(&session_p->session_mutex);
316 session_p->decrypt.flags = 0;
317 ses_lock_held = B_TRUE;
318 REFRELE(session_p, ses_lock_held);
320 return (rv);
324 CK_RV
325 C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart,
326 CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart,
327 CK_ULONG_PTR pulPartLen)
330 CK_RV rv;
331 kernel_session_t *session_p;
332 boolean_t ses_lock_held = B_FALSE;
333 boolean_t inplace;
334 crypto_decrypt_update_t decrypt_update;
335 int r;
337 if (!kernel_initialized)
338 return (CKR_CRYPTOKI_NOT_INITIALIZED);
340 /* Obtain the session pointer. */
341 rv = handle2session(hSession, &session_p);
342 if (rv != CKR_OK)
343 return (rv);
345 if (pEncryptedPart == NULL) {
346 rv = CKR_ARGUMENTS_BAD;
347 goto clean_exit;
351 * Only check if pulPartLen is NULL.
352 * No need to check if pPart is NULL because application
353 * might just ask for the length of buffer to hold the
354 * recovered data.
356 if (pulPartLen == NULL) {
357 rv = CKR_ARGUMENTS_BAD;
358 goto clean_exit;
361 (void) pthread_mutex_lock(&session_p->session_mutex);
362 ses_lock_held = B_TRUE;
365 * Application must call C_DecryptInit before calling
366 * C_DecryptUpdate.
368 if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
369 REFRELE(session_p, ses_lock_held);
370 return (CKR_OPERATION_NOT_INITIALIZED);
373 session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
375 decrypt_update.du_session = session_p->k_session;
376 (void) pthread_mutex_unlock(&session_p->session_mutex);
377 ses_lock_held = B_FALSE;
379 decrypt_update.du_datalen = *pulPartLen;
380 decrypt_update.du_databuf = (char *)pPart;
381 decrypt_update.du_encrlen = ulEncryptedPartLen;
382 decrypt_update.du_encrbuf = (char *)pEncryptedPart;
384 inplace = (session_p->decrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
385 decrypt_update.du_flags =
386 ((inplace && (pPart != NULL)) || (pPart == pEncryptedPart)) &&
387 (decrypt_update.du_datalen == decrypt_update.du_encrlen) ?
388 CRYPTO_INPLACE_OPERATION : 0;
390 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_UPDATE,
391 &decrypt_update)) < 0) {
392 if (errno != EINTR)
393 break;
395 if (r < 0) {
396 rv = CKR_FUNCTION_FAILED;
397 } else {
398 rv = crypto2pkcs11_error_number(
399 decrypt_update.du_return_value);
403 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
404 * We don't terminate the current decryption operation.
406 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
407 *pulPartLen = decrypt_update.du_datalen;
408 REFRELE(session_p, ses_lock_held);
409 return (rv);
412 clean_exit:
414 * After an error occurred, terminate the current decrypt
415 * operation by resetting the active and update flags.
417 (void) pthread_mutex_lock(&session_p->session_mutex);
418 session_p->decrypt.flags = 0;
419 ses_lock_held = B_TRUE;
420 REFRELE(session_p, ses_lock_held);
422 return (rv);
426 CK_RV
427 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
428 CK_ULONG_PTR pulLastPartLen)
431 CK_RV rv;
432 kernel_session_t *session_p;
433 boolean_t ses_lock_held = B_FALSE;
434 crypto_decrypt_final_t decrypt_final;
435 int r;
437 if (!kernel_initialized)
438 return (CKR_CRYPTOKI_NOT_INITIALIZED);
440 /* Obtain the session pointer. */
441 rv = handle2session(hSession, &session_p);
442 if (rv != CKR_OK)
443 return (rv);
445 if (pulLastPartLen == NULL) {
446 rv = CKR_ARGUMENTS_BAD;
447 goto clean_exit;
450 (void) pthread_mutex_lock(&session_p->session_mutex);
451 ses_lock_held = B_TRUE;
454 * Application must call C_DecryptInit before calling
455 * C_DecryptFinal.
457 if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
458 REFRELE(session_p, ses_lock_held);
459 return (CKR_OPERATION_NOT_INITIALIZED);
462 decrypt_final.df_session = session_p->k_session;
463 (void) pthread_mutex_unlock(&session_p->session_mutex);
464 ses_lock_held = B_FALSE;
466 decrypt_final.df_datalen = *pulLastPartLen;
467 decrypt_final.df_databuf = (char *)pLastPart;
469 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_FINAL,
470 &decrypt_final)) < 0) {
471 if (errno != EINTR)
472 break;
474 if (r < 0) {
475 rv = CKR_FUNCTION_FAILED;
476 } else {
477 rv = crypto2pkcs11_error_number(decrypt_final.df_return_value);
480 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
481 *pulLastPartLen = decrypt_final.df_datalen;
483 if (rv == CKR_BUFFER_TOO_SMALL ||
484 (rv == CKR_OK && pLastPart == NULL)) {
486 * We will not terminate the active decrypt operation flag,
487 * when the application-supplied buffer is too small, or
488 * the application asks for the length of buffer to hold
489 * the plaintext.
491 REFRELE(session_p, ses_lock_held);
492 return (rv);
495 clean_exit:
496 /* Terminates the active decrypt operation */
497 (void) pthread_mutex_lock(&session_p->session_mutex);
498 session_p->decrypt.flags = 0;
499 ses_lock_held = B_TRUE;
500 REFRELE(session_p, ses_lock_held);
502 return (rv);