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 CK_RV 37 C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, 38 CK_OBJECT_HANDLE hKey) 39 { 40 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; 48 49 if (!kernel_initialized) 50 return (CKR_CRYPTOKI_NOT_INITIALIZED); 51 52 if (pMechanism == NULL) { 53 return (CKR_ARGUMENTS_BAD); 54 } 55 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); 60 61 /* Obtain the session pointer. */ 62 rv = handle2session(hSession, &session_p); 63 if (rv != CKR_OK) 64 return (rv); 65 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); 71 } 72 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; 77 } 78 79 (void) pthread_mutex_lock(&session_p->session_mutex); 80 ses_lock_held = B_TRUE; 81 82 /* 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. 86 */ 87 session_p->encrypt.flags = CRYPTO_OPERATION_ACTIVE; 88 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; 101 } 102 encrypt_init.ei_key.ck_length = 103 OBJ_SEC(key_p)->sk_value_len << 3; 104 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; 110 } 111 } else { 112 rv = CKR_KEY_TYPE_INCONSISTENT; 113 goto clean_exit; 114 } 115 } 116 117 encrypt_init.ei_session = session_p->k_session; 118 session_p->encrypt.mech = *pMechanism; 119 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; 123 } 124 (void) pthread_mutex_unlock(&session_p->session_mutex); 125 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; 130 131 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_INIT, &encrypt_init)) < 0) { 132 if (errno != EINTR) 133 break; 134 } 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); 141 } 142 } 143 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); 150 } 151 } 152 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; 157 } 158 159 clean_exit: 160 OBJ_REFRELE(key_p); 161 REFRELE(session_p, ses_lock_held); 162 return (rv); 163 } 164 165 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) 169 { 170 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; 177 178 if (!kernel_initialized) 179 return (CKR_CRYPTOKI_NOT_INITIALIZED); 180 181 /* Obtain the session pointer. */ 182 rv = handle2session(hSession, &session_p); 183 if (rv != CKR_OK) 184 return (rv); 185 186 if (pData == NULL) { 187 rv = CKR_ARGUMENTS_BAD; 188 goto clean_exit; 189 } 190 191 /* 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. 196 */ 197 if (pulEncryptedDataLen == NULL) { 198 rv = CKR_ARGUMENTS_BAD; 199 goto clean_exit; 200 } 201 202 (void) pthread_mutex_lock(&session_p->session_mutex); 203 ses_lock_held = B_TRUE; 204 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); 209 } 210 211 /* 212 * C_Encrypt must be called without intervening C_EncryptUpdate 213 * calls. 214 */ 215 if (session_p->encrypt.flags & CRYPTO_OPERATION_UPDATE) { 216 /* 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. 221 */ 222 REFRELE(session_p, ses_lock_held); 223 return (CKR_FUNCTION_FAILED); 224 } 225 226 encrypt.ce_session = session_p->k_session; 227 228 /* 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. 234 */ 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; 240 } 241 (void) pthread_mutex_unlock(&session_p->session_mutex); 242 ses_lock_held = B_FALSE; 243 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; 252 253 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT, &encrypt)) < 0) { 254 if (errno != EINTR) 255 break; 256 } 257 if (r < 0) { 258 rv = CKR_FUNCTION_FAILED; 259 } else { 260 rv = crypto2pkcs11_error_number(encrypt.ce_return_value); 261 } 262 263 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 264 *pulEncryptedDataLen = encrypt.ce_encrlen; 265 266 if ((rv == CKR_BUFFER_TOO_SMALL) || 267 (rv == CKR_OK && pEncryptedData == NULL)) { 268 /* 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. 273 */ 274 REFRELE(session_p, ses_lock_held); 275 return (rv); 276 } 277 278 clean_exit: 279 /* 280 * Terminates the active encrypt operation. 281 * Application needs to call C_EncryptInit again for next 282 * encrypt operation. 283 */ 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); 288 289 return (rv); 290 } 291 292 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) 297 { 298 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; 305 306 if (!kernel_initialized) 307 return (CKR_CRYPTOKI_NOT_INITIALIZED); 308 309 /* Obtain the session pointer. */ 310 rv = handle2session(hSession, &session_p); 311 if (rv != CKR_OK) 312 return (rv); 313 314 if (pPart == NULL) { 315 rv = CKR_ARGUMENTS_BAD; 316 goto clean_exit; 317 } 318 319 /* 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. 324 */ 325 if (pulEncryptedPartLen == NULL) { 326 rv = CKR_ARGUMENTS_BAD; 327 goto clean_exit; 328 } 329 330 (void) pthread_mutex_lock(&session_p->session_mutex); 331 ses_lock_held = B_TRUE; 332 333 /* 334 * Application must call C_EncryptInit before calling 335 * C_EncryptUpdate. 336 */ 337 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) { 338 REFRELE(session_p, ses_lock_held); 339 return (CKR_OPERATION_NOT_INITIALIZED); 340 } 341 342 session_p->encrypt.flags |= CRYPTO_OPERATION_UPDATE; 343 344 encrypt_update.eu_session = session_p->k_session; 345 (void) pthread_mutex_unlock(&session_p->session_mutex); 346 ses_lock_held = B_FALSE; 347 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; 352 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; 359 360 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_UPDATE, 361 &encrypt_update)) < 0) { 362 if (errno != EINTR) 363 break; 364 } 365 if (r < 0) { 366 rv = CKR_FUNCTION_FAILED; 367 } else { 368 rv = crypto2pkcs11_error_number( 369 encrypt_update.eu_return_value); 370 } 371 372 /* 373 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length. 374 * We don't terminate the current encryption operation. 375 */ 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); 380 } 381 382 clean_exit: 383 /* 384 * After an error occurred, terminate the current encrypt 385 * operation by resetting the active and update flags. 386 */ 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); 391 392 return (rv); 393 } 394 395 396 CK_RV 397 C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, 398 CK_ULONG_PTR pulLastEncryptedPartLen) 399 { 400 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; 406 407 if (!kernel_initialized) 408 return (CKR_CRYPTOKI_NOT_INITIALIZED); 409 410 /* Obtain the session pointer. */ 411 rv = handle2session(hSession, &session_p); 412 if (rv != CKR_OK) 413 return (rv); 414 415 if (pulLastEncryptedPartLen == NULL) { 416 rv = CKR_ARGUMENTS_BAD; 417 goto clean_exit; 418 } 419 420 (void) pthread_mutex_lock(&session_p->session_mutex); 421 ses_lock_held = B_TRUE; 422 423 /* 424 * Application must call C_EncryptInit before calling 425 * C_EncryptFinal. 426 */ 427 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) { 428 REFRELE(session_p, ses_lock_held); 429 return (CKR_OPERATION_NOT_INITIALIZED); 430 } 431 432 encrypt_final.ef_session = session_p->k_session; 433 (void) pthread_mutex_unlock(&session_p->session_mutex); 434 ses_lock_held = B_FALSE; 435 436 encrypt_final.ef_encrlen = *pulLastEncryptedPartLen; 437 encrypt_final.ef_encrbuf = (char *)pLastEncryptedPart; 438 439 while ((r = ioctl(kernel_fd, CRYPTO_ENCRYPT_FINAL, 440 &encrypt_final)) < 0) { 441 if (errno != EINTR) 442 break; 443 } 444 if (r < 0) { 445 rv = CKR_FUNCTION_FAILED; 446 } else { 447 rv = crypto2pkcs11_error_number(encrypt_final.ef_return_value); 448 } 449 450 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) 451 *pulLastEncryptedPartLen = encrypt_final.ef_encrlen; 452 453 if ((rv == CKR_BUFFER_TOO_SMALL) || 454 (rv == CKR_OK && pLastEncryptedPart == NULL)) { 455 /* 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. 460 */ 461 REFRELE(session_p, ses_lock_held); 462 return (rv); 463 } 464 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); 471 472 return (rv); 473 } 474