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