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
C_EncryptInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)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
C_Encrypt(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncryptedData,CK_ULONG_PTR pulEncryptedDataLen)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
C_EncryptUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen,CK_BYTE_PTR pEncryptedPart,CK_ULONG_PTR pulEncryptedPartLen)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
C_EncryptFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pLastEncryptedPart,CK_ULONG_PTR pulLastEncryptedPartLen)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