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
kernel_decrypt_init(kernel_session_t * session_p,kernel_object_t * key_p,CK_MECHANISM_PTR pMechanism)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
C_DecryptInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)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
kernel_decrypt(kernel_session_t * session_p,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedData,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)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
C_Decrypt(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedData,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)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
C_DecryptUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pEncryptedPart,CK_ULONG ulEncryptedPartLen,CK_BYTE_PTR pPart,CK_ULONG_PTR pulPartLen)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
C_DecryptFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pLastPart,CK_ULONG_PTR pulLastPartLen)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