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 * Copyright 2018, Joyent, Inc.
25 */
26
27 #include <pthread.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <sys/crypto/ioctl.h>
31 #include <security/cryptoki.h>
32 #include "kernelGlobal.h"
33 #include "kernelSession.h"
34 #include "kernelObject.h"
35
36
37 /*
38 * Real decryptInit work. The caller doesn't hold the session lock.
39 */
40 CK_RV
kernel_decrypt_init(kernel_session_t * session_p,kernel_object_t * key_p,CK_MECHANISM_PTR pMechanism)41 kernel_decrypt_init(kernel_session_t *session_p, kernel_object_t *key_p,
42 CK_MECHANISM_PTR pMechanism)
43 {
44 CK_RV rv;
45 crypto_decrypt_init_t decrypt_init;
46 crypto_mech_type_t k_mech_type;
47 boolean_t ses_lock_held = B_FALSE;
48 int r;
49 CK_AES_CCM_PARAMS ccm_params = { 0 };
50
51 /* Check to see if key object allows for decryption. */
52 if (key_p->is_lib_obj && !(key_p->bool_attr_mask & DECRYPT_BOOL_ON)) {
53 return (CKR_KEY_TYPE_INCONSISTENT);
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 (void) pthread_mutex_lock(&session_p->session_mutex);
62 ses_lock_held = B_TRUE;
63
64 /*
65 * This active flag will remain ON until application calls either
66 * C_Decrypt or C_DecryptFinal to actually obtain the final piece
67 * of plaintext.
68 */
69 session_p->decrypt.flags = CRYPTO_OPERATION_ACTIVE;
70
71 /* set up key data */
72 if (!key_p->is_lib_obj) {
73 decrypt_init.di_key.ck_format = CRYPTO_KEY_REFERENCE;
74 decrypt_init.di_key.ck_obj_id = key_p->k_handle;
75 } else {
76 if (key_p->class == CKO_SECRET_KEY) {
77 decrypt_init.di_key.ck_format = CRYPTO_KEY_RAW;
78 decrypt_init.di_key.ck_data =
79 get_symmetric_key_value(key_p);
80 if (decrypt_init.di_key.ck_data == NULL) {
81 rv = CKR_HOST_MEMORY;
82 goto clean_exit;
83 }
84 /* KEF key lengths are expressed in bits */
85 decrypt_init.di_key.ck_length =
86 OBJ_SEC(key_p)->sk_value_len << 3;
87
88 } else if (key_p->key_type == CKK_RSA) {
89 if (get_rsa_private_key(key_p, &decrypt_init.di_key) !=
90 CKR_OK) {
91 rv = CKR_HOST_MEMORY;
92 goto clean_exit;
93 }
94 } else {
95 rv = CKR_KEY_TYPE_INCONSISTENT;
96 goto clean_exit;
97 }
98 }
99
100 decrypt_init.di_session = session_p->k_session;
101 session_p->decrypt.mech = *pMechanism;
102
103 /* Cache this capability value for efficiency */
104 if (INPLACE_MECHANISM(session_p->decrypt.mech.mechanism)) {
105 session_p->decrypt.flags |= CRYPTO_OPERATION_INPLACE_OK;
106 }
107 (void) pthread_mutex_unlock(&session_p->session_mutex);
108
109 ses_lock_held = B_FALSE;
110 decrypt_init.di_mech.cm_type = k_mech_type;
111 decrypt_init.di_mech.cm_param = pMechanism->pParameter;
112 decrypt_init.di_mech.cm_param_len = pMechanism->ulParameterLen;
113
114 /*
115 * PKCS#11 uses CK_CCM_PARAMS as its mechanism parameter, while the
116 * kernel uses CK_AES_CCM_PARAMS. Unlike
117 * CK_GCM_PARAMS / CK_AES_GCM_PARAMS, the two definitions are not
118 * equivalent -- the fields are defined in different orders, so
119 * we must translate.
120 */
121 if (session_p->decrypt.mech.mechanism == CKM_AES_CCM) {
122 if (pMechanism->ulParameterLen != sizeof (CK_CCM_PARAMS)) {
123 rv = CKR_MECHANISM_PARAM_INVALID;
124 goto clean_exit;
125 }
126 p11_to_kernel_ccm_params(pMechanism->pParameter, &ccm_params);
127 decrypt_init.di_mech.cm_param = (caddr_t)&ccm_params;
128 decrypt_init.di_mech.cm_param_len = sizeof (ccm_params);
129 }
130
131 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_INIT, &decrypt_init)) < 0) {
132 if (errno != EINTR)
133 break;
134 }
135 if (r < 0) {
136 rv = CKR_FUNCTION_FAILED;
137 } else {
138 rv = crypto2pkcs11_error_number(decrypt_init.di_return_value);
139 }
140
141 /* Free memory allocated for decrypt_init.di_key */
142 if (key_p->is_lib_obj) {
143 if (key_p->class == CKO_SECRET_KEY) {
144 free(decrypt_init.di_key.ck_data);
145 } else if (key_p->key_type == CKK_RSA) {
146 free_key_attributes(&decrypt_init.di_key);
147 }
148 }
149
150 clean_exit:
151 /*
152 * ccm_params does not contain any key material -- just lengths and
153 * pointers, therefore it does not need to be zeroed on exit.
154 */
155 if (!ses_lock_held) {
156 (void) pthread_mutex_lock(&session_p->session_mutex);
157 ses_lock_held = B_TRUE;
158 }
159
160 if (rv != CKR_OK)
161 session_p->decrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
162
163 if (ses_lock_held) {
164 (void) pthread_mutex_unlock(&session_p->session_mutex);
165 ses_lock_held = B_FALSE;
166 }
167
168 return (rv);
169 }
170
171 CK_RV
C_DecryptInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)172 C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
173 CK_OBJECT_HANDLE hKey)
174 {
175
176 CK_RV rv;
177 kernel_session_t *session_p;
178 kernel_object_t *key_p;
179 boolean_t ses_lock_held = B_FALSE;
180
181 if (!kernel_initialized)
182 return (CKR_CRYPTOKI_NOT_INITIALIZED);
183
184 if (pMechanism == NULL) {
185 return (CKR_ARGUMENTS_BAD);
186 }
187
188 /* Obtain the session pointer. */
189 rv = handle2session(hSession, &session_p);
190 if (rv != CKR_OK)
191 return (rv);
192
193 /* Obtain the object pointer. */
194 HANDLE2OBJECT(hKey, key_p, rv);
195 if (rv == CKR_OK) {
196 rv = kernel_decrypt_init(session_p, key_p, pMechanism);
197 OBJ_REFRELE(key_p);
198 }
199
200 REFRELE(session_p, ses_lock_held);
201 return (rv);
202 }
203
204
205
206 /*
207 * Real decrypt work. The caller doesn't hold the session lock.
208 */
209 CK_RV
kernel_decrypt(kernel_session_t * session_p,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedData,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)210 kernel_decrypt(kernel_session_t *session_p, CK_BYTE_PTR pEncryptedData,
211 CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
212 {
213 crypto_decrypt_t decrypt;
214 boolean_t ses_lock_held = B_FALSE;
215 boolean_t inplace;
216 CK_RV rv;
217 int r;
218
219 (void) pthread_mutex_lock(&session_p->session_mutex);
220 ses_lock_held = B_TRUE;
221
222 /* Application must call C_DecryptInit before calling C_Decrypt. */
223 if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
224 rv = CKR_OPERATION_NOT_INITIALIZED;
225 goto clean_exit;
226 }
227
228 /*
229 * C_Decrypt must be called without intervening C_DecryptUpdate
230 * calls.
231 */
232 if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
233 /*
234 * C_Decrypt cannot be used to terminate a multiple-part
235 * operation, so we'll leave the active decrypt operation
236 * flag on and let the application continue with the
237 * decrypt update operation.
238 */
239 rv = CKR_FUNCTION_FAILED;
240 goto clean_exit;
241 }
242
243 decrypt.cd_session = session_p->k_session;
244
245 /*
246 * Certain mechanisms, where the length of the plaintext is
247 * same as the transformed ciphertext, can be optimized
248 * by the kernel into an in-place operation. Unfortunately,
249 * some applications use a plaintext buffer that is larger
250 * than it needs to be. We fix that here.
251 */
252 inplace = (session_p->decrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
253
254 if (ulEncryptedData < *pulDataLen && inplace) {
255 decrypt.cd_datalen = ulEncryptedData;
256 } else {
257 decrypt.cd_datalen = *pulDataLen;
258 }
259 (void) pthread_mutex_unlock(&session_p->session_mutex);
260 ses_lock_held = B_FALSE;
261
262 decrypt.cd_databuf = (char *)pData;
263 decrypt.cd_encrlen = ulEncryptedData;
264 decrypt.cd_encrbuf = (char *)pEncryptedData;
265 decrypt.cd_flags =
266 ((inplace && (pData != NULL)) || (pData == pEncryptedData)) &&
267 (decrypt.cd_datalen == decrypt.cd_encrlen) ?
268 CRYPTO_INPLACE_OPERATION : 0;
269
270 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT, &decrypt)) < 0) {
271 if (errno != EINTR)
272 break;
273 }
274 if (r < 0) {
275 rv = CKR_FUNCTION_FAILED;
276 } else {
277 rv = crypto2pkcs11_error_number(decrypt.cd_return_value);
278 }
279
280 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
281 *pulDataLen = decrypt.cd_datalen;
282
283 clean_exit:
284
285 if (ses_lock_held)
286 (void) pthread_mutex_unlock(&session_p->session_mutex);
287
288 return (rv);
289 }
290
291 CK_RV
C_Decrypt(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedData,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)292 C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData,
293 CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
294 {
295 CK_RV rv;
296 kernel_session_t *session_p;
297 boolean_t ses_lock_held = B_FALSE;
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 /*
308 * No need to check pData because application might
309 * just want to know the length of decrypted data.
310 */
311 if (pulDataLen == NULL) {
312 rv = CKR_ARGUMENTS_BAD;
313 goto clean_exit;
314 }
315
316 rv = kernel_decrypt(session_p, pEncryptedData, ulEncryptedData, pData,
317 pulDataLen);
318
319 if ((rv == CKR_BUFFER_TOO_SMALL) ||
320 (rv == CKR_OK && pData == NULL)) {
321 /*
322 * We will not terminate the active decrypt operation flag,
323 * when the application-supplied buffer is too small, or
324 * the application asks for the length of buffer to hold
325 * the plaintext.
326 */
327 REFRELE(session_p, ses_lock_held);
328 return (rv);
329 }
330
331 clean_exit:
332 /*
333 * Terminates the active decrypt operation.
334 * Application needs to call C_DecryptInit again for next
335 * decrypt operation.
336 */
337 (void) pthread_mutex_lock(&session_p->session_mutex);
338 session_p->decrypt.flags = 0;
339 ses_lock_held = B_TRUE;
340 REFRELE(session_p, ses_lock_held);
341
342 return (rv);
343 }
344
345
346 CK_RV
C_DecryptUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pEncryptedPart,CK_ULONG ulEncryptedPartLen,CK_BYTE_PTR pPart,CK_ULONG_PTR pulPartLen)347 C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart,
348 CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart,
349 CK_ULONG_PTR pulPartLen)
350 {
351
352 CK_RV rv;
353 kernel_session_t *session_p;
354 boolean_t ses_lock_held = B_FALSE;
355 boolean_t inplace;
356 crypto_decrypt_update_t decrypt_update;
357 int r;
358
359 if (!kernel_initialized)
360 return (CKR_CRYPTOKI_NOT_INITIALIZED);
361
362 /* Obtain the session pointer. */
363 rv = handle2session(hSession, &session_p);
364 if (rv != CKR_OK)
365 return (rv);
366
367 if (pEncryptedPart == NULL) {
368 rv = CKR_ARGUMENTS_BAD;
369 goto clean_exit;
370 }
371
372 /*
373 * Only check if pulPartLen is NULL.
374 * No need to check if pPart is NULL because application
375 * might just ask for the length of buffer to hold the
376 * recovered data.
377 */
378 if (pulPartLen == NULL) {
379 rv = CKR_ARGUMENTS_BAD;
380 goto clean_exit;
381 }
382
383 (void) pthread_mutex_lock(&session_p->session_mutex);
384 ses_lock_held = B_TRUE;
385
386 /*
387 * Application must call C_DecryptInit before calling
388 * C_DecryptUpdate.
389 */
390 if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
391 REFRELE(session_p, ses_lock_held);
392 return (CKR_OPERATION_NOT_INITIALIZED);
393 }
394
395 session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
396
397 decrypt_update.du_session = session_p->k_session;
398 (void) pthread_mutex_unlock(&session_p->session_mutex);
399 ses_lock_held = B_FALSE;
400
401 decrypt_update.du_datalen = *pulPartLen;
402 decrypt_update.du_databuf = (char *)pPart;
403 decrypt_update.du_encrlen = ulEncryptedPartLen;
404 decrypt_update.du_encrbuf = (char *)pEncryptedPart;
405
406 inplace = (session_p->decrypt.flags & CRYPTO_OPERATION_INPLACE_OK) != 0;
407 decrypt_update.du_flags =
408 ((inplace && (pPart != NULL)) || (pPart == pEncryptedPart)) &&
409 (decrypt_update.du_datalen == decrypt_update.du_encrlen) ?
410 CRYPTO_INPLACE_OPERATION : 0;
411
412 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_UPDATE,
413 &decrypt_update)) < 0) {
414 if (errno != EINTR)
415 break;
416 }
417 if (r < 0) {
418 rv = CKR_FUNCTION_FAILED;
419 } else {
420 rv = crypto2pkcs11_error_number(
421 decrypt_update.du_return_value);
422 }
423
424 /*
425 * If CKR_OK or CKR_BUFFER_TOO_SMALL, set the output length.
426 * We don't terminate the current decryption operation.
427 */
428 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL) {
429 *pulPartLen = decrypt_update.du_datalen;
430 REFRELE(session_p, ses_lock_held);
431 return (rv);
432 }
433
434 clean_exit:
435 /*
436 * After an error occurred, terminate the current decrypt
437 * operation by resetting the active and update flags.
438 */
439 (void) pthread_mutex_lock(&session_p->session_mutex);
440 session_p->decrypt.flags = 0;
441 ses_lock_held = B_TRUE;
442 REFRELE(session_p, ses_lock_held);
443
444 return (rv);
445 }
446
447
448 CK_RV
C_DecryptFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pLastPart,CK_ULONG_PTR pulLastPartLen)449 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
450 CK_ULONG_PTR pulLastPartLen)
451 {
452
453 CK_RV rv;
454 kernel_session_t *session_p;
455 boolean_t ses_lock_held = B_FALSE;
456 crypto_decrypt_final_t decrypt_final;
457 int r;
458
459 if (!kernel_initialized)
460 return (CKR_CRYPTOKI_NOT_INITIALIZED);
461
462 /* Obtain the session pointer. */
463 rv = handle2session(hSession, &session_p);
464 if (rv != CKR_OK)
465 return (rv);
466
467 if (pulLastPartLen == NULL) {
468 rv = CKR_ARGUMENTS_BAD;
469 goto clean_exit;
470 }
471
472 (void) pthread_mutex_lock(&session_p->session_mutex);
473 ses_lock_held = B_TRUE;
474
475 /*
476 * Application must call C_DecryptInit before calling
477 * C_DecryptFinal.
478 */
479 if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
480 REFRELE(session_p, ses_lock_held);
481 return (CKR_OPERATION_NOT_INITIALIZED);
482 }
483
484 decrypt_final.df_session = session_p->k_session;
485 (void) pthread_mutex_unlock(&session_p->session_mutex);
486 ses_lock_held = B_FALSE;
487
488 decrypt_final.df_datalen = *pulLastPartLen;
489 decrypt_final.df_databuf = (char *)pLastPart;
490
491 while ((r = ioctl(kernel_fd, CRYPTO_DECRYPT_FINAL,
492 &decrypt_final)) < 0) {
493 if (errno != EINTR)
494 break;
495 }
496 if (r < 0) {
497 rv = CKR_FUNCTION_FAILED;
498 } else {
499 rv = crypto2pkcs11_error_number(decrypt_final.df_return_value);
500 }
501
502 if (rv == CKR_OK || rv == CKR_BUFFER_TOO_SMALL)
503 *pulLastPartLen = decrypt_final.df_datalen;
504
505 if (rv == CKR_BUFFER_TOO_SMALL ||
506 (rv == CKR_OK && pLastPart == NULL)) {
507 /*
508 * We will not terminate the active decrypt operation flag,
509 * when the application-supplied buffer is too small, or
510 * the application asks for the length of buffer to hold
511 * the plaintext.
512 */
513 REFRELE(session_p, ses_lock_held);
514 return (rv);
515 }
516
517 clean_exit:
518 /* Terminates the active decrypt operation */
519 (void) pthread_mutex_lock(&session_p->session_mutex);
520 session_p->decrypt.flags = 0;
521 ses_lock_held = B_TRUE;
522 REFRELE(session_p, ses_lock_held);
523
524 return (rv);
525 }
526