Home | History | Annotate | Download | only in common
      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 /*
     37  * Real decryptInit work. The caller doesn't hold the session lock.
     38  */
     39 CK_RV
     40 kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
     41     CK_MECHANISM_PTR pMechanism)
     42 {
     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;
     48 
     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);
     52 	}
     53 
     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);
     58 
     59 	(void) pthread_mutex_lock(&session_p->session_mutex);
     60 	ses_lock_held = B_TRUE;
     61 
     62 	/*
     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.
     66 	 */
     67 	session_p->decrypt.flags = CRYPTO_OPERATION_ACTIVE;
     68 
     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;
     81 			}
     82 			/* KEF key lengths are expressed in bits */
     83 			decrypt_init.di_key.ck_length =
     84 			    OBJ_SEC(key_p)->sk_value_len << 3;
     85 
     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;
     91 			}
     92 		} else {
     93 			rv = CKR_KEY_TYPE_INCONSISTENT;
     94 			goto clean_exit;
     95 		}
     96 	}
     97 
     98 	decrypt_init.di_session = session_p->k_session;
     99 	session_p->decrypt.mech = *pMechanism;
    100 
    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;
    104 	}
    105 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    106 
    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;
    111 
    112 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_INIT, &decrypt_init)) < 0) {
    113 		if (errno != EINTR)
    114 			break;
    115 	}
    116 	if (r < 0) {
    117 		rv = CKR_FUNCTION_FAILED;
    118 	} else {
    119 		rv = crypto2pkcs11_error_number(decrypt_init.di_return_value);
    120 	}
    121 
    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);
    128 		}
    129 	}
    130 
    131 clean_exit:
    132 
    133 	if (!ses_lock_held) {
    134 		(void) pthread_mutex_lock(&session_p->session_mutex);
    135 		ses_lock_held = B_TRUE;
    136 	}
    137 
    138 	if (rv != CKR_OK)
    139 		session_p->decrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
    140 
    141 	if (ses_lock_held) {
    142 		(void) pthread_mutex_unlock(&session_p->session_mutex);
    143 		ses_lock_held = B_FALSE;
    144 	}
    145 
    146 	return (rv);
    147 }
    148 
    149 CK_RV
    150 C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
    151     CK_OBJECT_HANDLE hKey)
    152 {
    153 
    154 	CK_RV rv;
    155 	kernel_session_t *session_p;
    156 	kernel_object_t	*key_p;
    157 	boolean_t ses_lock_held = B_FALSE;
    158 
    159 	if (!kernel_initialized)
    160 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    161 
    162 	if (pMechanism == NULL) {
    163 		return (CKR_ARGUMENTS_BAD);
    164 	}
    165 
    166 	/* Obtain the session pointer. */
    167 	rv = handle2session(hSession, &session_p);
    168 	if (rv != CKR_OK)
    169 		return (rv);
    170 
    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);
    176 	}
    177 
    178 	REFRELE(session_p, ses_lock_held);
    179 	return (rv);
    180 }
    181 
    182 
    183 
    184 /*
    185  * Real decrypt work. The caller doesn't hold the session lock.
    186  */
    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)
    190 {
    191 	crypto_decrypt_t decrypt;
    192 	boolean_t ses_lock_held = B_FALSE;
    193 	boolean_t inplace;
    194 	CK_RV rv;
    195 	int r;
    196 
    197 	(void) pthread_mutex_lock(&session_p->session_mutex);
    198 	ses_lock_held = B_TRUE;
    199 
    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;
    204 	}
    205 
    206 	/*
    207 	 * C_Decrypt must be called without intervening C_DecryptUpdate
    208 	 * calls.
    209 	 */
    210 	if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
    211 		/*
    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.
    216 		 */
    217 		rv = CKR_FUNCTION_FAILED;
    218 		goto clean_exit;
    219 	}
    220 
    221 	decrypt.cd_session = session_p->k_session;
    222 
    223 	/*
    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.
    229 	 */
    230 	inplace = (session_p->decrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
    231 
    232 	if (ulEncryptedData < *pulDataLen && inplace) {
    233 		decrypt.cd_datalen = ulEncryptedData;
    234 	} else {
    235 		decrypt.cd_datalen = *pulDataLen;
    236 	}
    237 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    238 	ses_lock_held = B_FALSE;
    239 
    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;
    247 
    248 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT, &decrypt)) < 0) {
    249 		if (errno != EINTR)
    250 			break;
    251 	}
    252 	if (r < 0) {
    253 		rv = CKR_FUNCTION_FAILED;
    254 	} else {
    255 		rv = crypto2pkcs11_error_number(decrypt.cd_return_value);
    256 	}
    257 
    258 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
    259 		*pulDataLen = decrypt.cd_datalen;
    260 
    261 clean_exit:
    262 
    263 	if (ses_lock_held)
    264 		(void) pthread_mutex_unlock(&session_p->session_mutex);
    265 
    266 	return (rv);
    267 }
    268 
    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)
    272 {
    273 	CK_RV rv;
    274 	kernel_session_t *session_p;
    275 	boolean_t ses_lock_held = B_FALSE;
    276 
    277 	if (!kernel_initialized)
    278 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    279 
    280 	/* Obtain the session pointer. */
    281 	rv = handle2session(hSession, &session_p);
    282 	if (rv != CKR_OK)
    283 		return (rv);
    284 
    285 	/*
    286 	 * No need to check pData because application might
    287 	 * just want to know the length of decrypted data.
    288 	 */
    289 	if (pulDataLen == NULL) {
    290 		rv = CKR_ARGUMENTS_BAD;
    291 		goto clean_exit;
    292 	}
    293 
    294 	rv = kernel_decrypt(session_p, pEncryptedData, ulEncryptedData, pData,
    295 	    pulDataLen);
    296 
    297 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
    298 	    (rv == CKR_OK && pData == NULL)) {
    299 		/*
    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.
    304 		 */
    305 		REFRELE(session_p, ses_lock_held);
    306 		return (rv);
    307 	}
    308 
    309 clean_exit:
    310 	/*
    311 	 * Terminates the active decrypt operation.
    312 	 * Application needs to call C_DecryptInit again for next
    313 	 * decrypt operation.
    314 	 */
    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);
    319 
    320 	return (rv);
    321 }
    322 
    323 
    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)
    328 {
    329 
    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;
    336 
    337 	if (!kernel_initialized)
    338 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    339 
    340 	/* Obtain the session pointer. */
    341 	rv = handle2session(hSession, &session_p);
    342 	if (rv != CKR_OK)
    343 		return (rv);
    344 
    345 	if (pEncryptedPart == NULL) {
    346 		rv = CKR_ARGUMENTS_BAD;
    347 		goto clean_exit;
    348 	}
    349 
    350 	/*
    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.
    355 	 */
    356 	if (pulPartLen == NULL) {
    357 		rv = CKR_ARGUMENTS_BAD;
    358 		goto clean_exit;
    359 	}
    360 
    361 	(void) pthread_mutex_lock(&session_p->session_mutex);
    362 	ses_lock_held = B_TRUE;
    363 
    364 	/*
    365 	 * Application must call C_DecryptInit before calling
    366 	 * C_DecryptUpdate.
    367 	 */
    368 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
    369 		REFRELE(session_p, ses_lock_held);
    370 		return (CKR_OPERATION_NOT_INITIALIZED);
    371 	}
    372 
    373 	session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
    374 
    375 	decrypt_update.du_session = session_p->k_session;
    376 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    377 	ses_lock_held = B_FALSE;
    378 
    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;
    383 
    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;
    389 
    390 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_UPDATE,
    391 	    &decrypt_update)) < 0) {
    392 		if (errno != EINTR)
    393 			break;
    394 	}
    395 	if (r < 0) {
    396 		rv = CKR_FUNCTION_FAILED;
    397 	} else {
    398 		rv = crypto2pkcs11_error_number(
    399 		    decrypt_update.du_return_value);
    400 	}
    401 
    402 	/*
    403 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
    404 	 * We don't terminate the current decryption operation.
    405 	 */
    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);
    410 	}
    411 
    412 clean_exit:
    413 	/*
    414 	 * After an error occurred, terminate the current decrypt
    415 	 * operation by resetting the active and update flags.
    416 	 */
    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);
    421 
    422 	return (rv);
    423 }
    424 
    425 
    426 CK_RV
    427 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
    428     CK_ULONG_PTR pulLastPartLen)
    429 {
    430 
    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;
    436 
    437 	if (!kernel_initialized)
    438 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
    439 
    440 	/* Obtain the session pointer. */
    441 	rv = handle2session(hSession, &session_p);
    442 	if (rv != CKR_OK)
    443 		return (rv);
    444 
    445 	if (pulLastPartLen == NULL) {
    446 		rv = CKR_ARGUMENTS_BAD;
    447 		goto clean_exit;
    448 	}
    449 
    450 	(void) pthread_mutex_lock(&session_p->session_mutex);
    451 	ses_lock_held = B_TRUE;
    452 
    453 	/*
    454 	 * Application must call C_DecryptInit before calling
    455 	 * C_DecryptFinal.
    456 	 */
    457 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
    458 		REFRELE(session_p, ses_lock_held);
    459 		return (CKR_OPERATION_NOT_INITIALIZED);
    460 	}
    461 
    462 	decrypt_final.df_session = session_p->k_session;
    463 	(void) pthread_mutex_unlock(&session_p->session_mutex);
    464 	ses_lock_held = B_FALSE;
    465 
    466 	decrypt_final.df_datalen = *pulLastPartLen;
    467 	decrypt_final.df_databuf = (char *)pLastPart;
    468 
    469 	while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_FINAL,
    470 	    &decrypt_final)) < 0) {
    471 		if (errno != EINTR)
    472 			break;
    473 	}
    474 	if (r < 0) {
    475 		rv = CKR_FUNCTION_FAILED;
    476 	} else {
    477 		rv = crypto2pkcs11_error_number(decrypt_final.df_return_value);
    478 	}
    479 
    480 	if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
    481 		*pulLastPartLen = decrypt_final.df_datalen;
    482 
    483 	if (rv == CKR_BUFFER_TOO_SMALL ||
    484 	    (rv == CKR_OK && pLastPart == NULL)) {
    485 		/*
    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.
    490 		 */
    491 		REFRELE(session_p, ses_lock_held);
    492 		return (rv);
    493 	}
    494 
    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);
    501 
    502 	return (rv);
    503 }
    504