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 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
22 */
23
24 #include <string.h>
25 #include <strings.h>
26 #include <security/cryptoki.h>
27 #include "kmsGlobal.h"
28 #include "kmsCrypt.h"
29
30 static CK_RV
kms_encrypt_init(kms_session_t * session_p,CK_MECHANISM_PTR pMechanism,kms_object_t * key_p)31 kms_encrypt_init(kms_session_t *session_p, CK_MECHANISM_PTR pMechanism,
32 kms_object_t *key_p)
33 {
34 CK_RV rv = CKR_OK;
35 kms_aes_ctx_t *kms_aes_ctx;
36
37 if (pMechanism->mechanism != CKM_AES_CBC &&
38 pMechanism->mechanism != CKM_AES_CBC_PAD)
39 return (CKR_MECHANISM_INVALID);
40
41 if (key_p->key_type != CKK_AES) {
42 return (CKR_KEY_TYPE_INCONSISTENT);
43 }
44
45 if ((pMechanism->pParameter == NULL) ||
46 (pMechanism->ulParameterLen != AES_BLOCK_LEN)) {
47 return (CKR_MECHANISM_PARAM_INVALID);
48 }
49
50 rv = kms_aes_crypt_init_common(session_p, pMechanism,
51 key_p, B_TRUE);
52
53 if (rv != CKR_OK)
54 return (rv);
55
56 (void) pthread_mutex_lock(&session_p->session_mutex);
57
58 kms_aes_ctx = (kms_aes_ctx_t *)session_p->encrypt.context;
59 /* Copy Initialization Vector (IV) into the context. */
60
61 (void) memcpy(kms_aes_ctx->ivec, pMechanism->pParameter,
62 AES_BLOCK_LEN);
63
64 /* Allocate a context for AES cipher-block chaining. */
65 kms_aes_ctx->aes_cbc = (void *)aes_cbc_ctx_init(
66 kms_aes_ctx->key_sched, kms_aes_ctx->keysched_len,
67 kms_aes_ctx->ivec);
68
69 if (kms_aes_ctx->aes_cbc == NULL) {
70 bzero(kms_aes_ctx->key_sched,
71 kms_aes_ctx->keysched_len);
72 free(kms_aes_ctx->key_sched);
73 free(session_p->encrypt.context);
74 session_p->encrypt.context = NULL;
75 rv = CKR_HOST_MEMORY;
76 }
77
78 (void) pthread_mutex_unlock(&session_p->session_mutex);
79
80 return (rv);
81 }
82
83 void
kms_crypt_cleanup(kms_session_t * session_p,boolean_t encrypt,boolean_t lock_held)84 kms_crypt_cleanup(kms_session_t *session_p, boolean_t encrypt,
85 boolean_t lock_held)
86 {
87 kms_active_op_t *active_op;
88 boolean_t lock_true = B_TRUE;
89 kms_aes_ctx_t *kms_aes_ctx;
90 aes_ctx_t *aes_ctx;
91
92 if (!lock_held)
93 (void) pthread_mutex_lock(&session_p->session_mutex);
94
95 active_op = (encrypt) ? &(session_p->encrypt) : &(session_p->decrypt);
96 if (active_op->mech.mechanism != CKM_AES_CBC &&
97 active_op->mech.mechanism != CKM_AES_CBC_PAD)
98 return;
99
100 kms_aes_ctx = (kms_aes_ctx_t *)active_op->context;
101
102 if (kms_aes_ctx != NULL) {
103 aes_ctx = (aes_ctx_t *)kms_aes_ctx->aes_cbc;
104 if (aes_ctx != NULL) {
105 bzero(aes_ctx->ac_keysched, aes_ctx->ac_keysched_len);
106 free(kms_aes_ctx->aes_cbc);
107 bzero(kms_aes_ctx->key_sched,
108 kms_aes_ctx->keysched_len);
109 free(kms_aes_ctx->key_sched);
110 }
111 }
112 if (active_op->context != NULL) {
113 free(active_op->context);
114 active_op->context = NULL;
115 }
116 active_op->flags = 0;
117 if (!lock_held)
118 REFRELE(session_p, lock_true);
119 }
120
121 CK_RV
C_EncryptInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)122 C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
123 CK_OBJECT_HANDLE hKey)
124 {
125 CK_RV rv;
126 kms_session_t *session_p;
127 kms_object_t *key_p;
128 boolean_t lock_held = B_FALSE;
129
130 if (!kms_initialized)
131 return (CKR_CRYPTOKI_NOT_INITIALIZED);
132
133 /* Obtain the session pointer. */
134 rv = handle2session(hSession, &session_p);
135 if (rv != CKR_OK)
136 return (rv);
137
138 if (pMechanism == NULL) {
139 rv = CKR_ARGUMENTS_BAD;
140 goto clean_exit;
141 }
142
143 if (pMechanism->mechanism != CKM_AES_CBC &&
144 pMechanism->mechanism != CKM_AES_CBC_PAD)
145 return (CKR_MECHANISM_INVALID);
146
147 /* Obtain the object pointer. */
148 HANDLE2OBJECT(hKey, key_p, rv);
149 if (rv != CKR_OK)
150 goto clean_exit;
151
152 /* Check to see if key object allows for encryption. */
153 if (!(key_p->bool_attr_mask & ENCRYPT_BOOL_ON)) {
154 rv = CKR_KEY_FUNCTION_NOT_PERMITTED;
155 goto clean_exit1;
156 }
157
158 (void) pthread_mutex_lock(&session_p->session_mutex);
159 lock_held = B_TRUE;
160
161 /* Check to see if encrypt operation is already active. */
162 if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
163 /* free the memory to avoid memory leak */
164 kms_crypt_cleanup(session_p, B_TRUE, lock_held);
165 }
166
167 /*
168 * This active flag will remain ON until application calls either
169 * C_Encrypt or C_EncryptFinal to actually obtain the final piece
170 * of ciphertext.
171 */
172 session_p->encrypt.flags = CRYPTO_OPERATION_ACTIVE;
173
174 (void) pthread_mutex_unlock(&session_p->session_mutex);
175 lock_held = B_FALSE;
176
177 rv = kms_encrypt_init(session_p, pMechanism, key_p);
178
179 if (rv != CKR_OK) {
180 (void) pthread_mutex_lock(&session_p->session_mutex);
181 session_p->encrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
182 lock_held = B_TRUE;
183 }
184
185 clean_exit1:
186 OBJ_REFRELE(key_p);
187 clean_exit:
188 REFRELE(session_p, lock_held);
189 return (rv);
190 }
191
192
193 CK_RV
C_Encrypt(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pEncryptedData,CK_ULONG_PTR pulEncryptedDataLen)194 C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
195 CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
196 {
197 CK_RV rv;
198 kms_session_t *session_p;
199 boolean_t lock_held = B_FALSE;
200
201 if (!kms_initialized)
202 return (CKR_CRYPTOKI_NOT_INITIALIZED);
203
204 /* Obtain the session pointer. */
205 rv = handle2session(hSession, &session_p);
206 if (rv != CKR_OK)
207 return (rv);
208
209 /*
210 * Only check if input buffer is null. How to handle zero input
211 * length depends on the mechanism in use. For secret key mechanisms,
212 * unpadded ones yield zero length output, but padded ones always
213 * result in greater than zero length output.
214 */
215 if (pData == NULL) {
216 rv = CKR_ARGUMENTS_BAD;
217 goto clean_exit;
218 }
219
220 /*
221 * Only check if pulEncryptedDataLen is NULL.
222 * No need to check if pEncryptedData is NULL because
223 * application might just ask for the length of buffer to hold
224 * the ciphertext.
225 */
226 if (pulEncryptedDataLen == NULL) {
227 rv = CKR_ARGUMENTS_BAD;
228 goto clean_exit;
229 }
230
231 (void) pthread_mutex_lock(&session_p->session_mutex);
232 lock_held = B_TRUE;
233
234 /* Application must call C_EncryptInit before calling C_Encrypt. */
235 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
236 REFRELE(session_p, lock_held);
237 return (CKR_OPERATION_NOT_INITIALIZED);
238 }
239
240 /*
241 * C_Encrypt must be called without intervening C_EncryptUpdate
242 * calls.
243 */
244 if (session_p->encrypt.flags & CRYPTO_OPERATION_UPDATE) {
245 /*
246 * C_Encrypt can not be used to terminate a multi-part
247 * operation, so we'll leave the active encrypt operation
248 * flag on and let the application continue with the
249 * encrypt update operation.
250 */
251 REFRELE(session_p, lock_held);
252 return (CKR_FUNCTION_FAILED);
253 }
254
255 (void) pthread_mutex_unlock(&session_p->session_mutex);
256 lock_held = B_FALSE;
257
258 rv = kms_aes_encrypt_common(session_p, pData, ulDataLen, pEncryptedData,
259 pulEncryptedDataLen, 0);
260
261 if ((rv == CKR_BUFFER_TOO_SMALL) ||
262 (pEncryptedData == NULL && rv == CKR_OK)) {
263 /*
264 * We will not terminate the active encrypt operation flag,
265 * when the application-supplied buffer is too small, or
266 * the application asks for the length of buffer to hold
267 * the ciphertext.
268 */
269 REFRELE(session_p, lock_held);
270 return (rv);
271 }
272
273 clean_exit:
274 /* Clear context, free key, and release session counter */
275 kms_crypt_cleanup(session_p, B_TRUE, B_FALSE);
276 return (rv);
277 }
278
279 CK_RV
C_EncryptUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pPart,CK_ULONG ulPartLen,CK_BYTE_PTR pEncryptedPart,CK_ULONG_PTR pulEncryptedPartLen)280 C_EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
281 CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart,
282 CK_ULONG_PTR pulEncryptedPartLen)
283 {
284
285 CK_RV rv;
286 kms_session_t *session_p;
287 boolean_t lock_held = B_FALSE;
288
289 if (!kms_initialized)
290 return (CKR_CRYPTOKI_NOT_INITIALIZED);
291
292 /* Obtain the session pointer. */
293 rv = handle2session(hSession, &session_p);
294 if (rv != CKR_OK)
295 return (rv);
296
297 /*
298 * Only check if input buffer is null. How to handle zero input
299 * length depends on the mechanism in use. For secret key mechanisms,
300 * unpadded ones yeild zero length output, but padded ones always
301 * result in greater than zero length output.
302 */
303 if (pPart == NULL) {
304 rv = CKR_ARGUMENTS_BAD;
305 goto clean_exit;
306 }
307
308 /*
309 * Only check if pulEncryptedPartLen is NULL.
310 * No need to check if pEncryptedPart is NULL because
311 * application might just ask for the length of buffer to hold
312 * the ciphertext.
313 */
314 if (pulEncryptedPartLen == NULL) {
315 rv = CKR_ARGUMENTS_BAD;
316 goto clean_exit;
317 }
318
319 (void) pthread_mutex_lock(&session_p->session_mutex);
320 lock_held = B_TRUE;
321
322 /*
323 * Application must call C_EncryptInit before calling
324 * C_EncryptUpdate.
325 */
326 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
327 REFRELE(session_p, lock_held);
328 return (CKR_OPERATION_NOT_INITIALIZED);
329 }
330
331 session_p->encrypt.flags |= CRYPTO_OPERATION_UPDATE;
332
333 (void) pthread_mutex_unlock(&session_p->session_mutex);
334 lock_held = B_FALSE;
335
336 rv = kms_aes_encrypt_common(session_p, pPart, ulPartLen,
337 pEncryptedPart, pulEncryptedPartLen, B_TRUE);
338
339 /*
340 * If CKR_OK or CKR_BUFFER_TOO_SMALL, don't terminate the
341 * current encryption operation.
342 */
343 if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) {
344 REFRELE(session_p, lock_held);
345 return (rv);
346 }
347
348 clean_exit:
349 /*
350 * After an error occurred, terminate the current encrypt
351 * operation by resetting the active and update flags.
352 */
353 kms_crypt_cleanup(session_p, B_TRUE, lock_held);
354
355 return (rv);
356 }
357
358
359 CK_RV
C_EncryptFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pLastEncryptedPart,CK_ULONG_PTR pulLastEncryptedPartLen)360 C_EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart,
361 CK_ULONG_PTR pulLastEncryptedPartLen)
362 {
363
364 CK_RV rv;
365 kms_session_t *session_p;
366 boolean_t lock_held = B_FALSE;
367
368 if (!kms_initialized)
369 return (CKR_CRYPTOKI_NOT_INITIALIZED);
370
371 /* Obtain the session pointer. */
372 rv = handle2session(hSession, &session_p);
373 if (rv != CKR_OK)
374 return (rv);
375
376 if (pulLastEncryptedPartLen == NULL) {
377 rv = CKR_ARGUMENTS_BAD;
378 goto clean_exit;
379 }
380
381 (void) pthread_mutex_lock(&session_p->session_mutex);
382 lock_held = B_TRUE;
383
384 /*
385 * Application must call C_EncryptInit before calling
386 * C_EncryptFinal.
387 */
388 if (!(session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
389 REFRELE(session_p, lock_held);
390 return (CKR_OPERATION_NOT_INITIALIZED);
391 }
392
393 (void) pthread_mutex_unlock(&session_p->session_mutex);
394 lock_held = B_FALSE;
395
396 rv = kms_aes_encrypt_final(session_p, pLastEncryptedPart,
397 pulLastEncryptedPartLen);
398
399 if ((rv == CKR_BUFFER_TOO_SMALL) ||
400 (pLastEncryptedPart == NULL && rv == CKR_OK)) {
401 /*
402 * We will not terminate the active encrypt operation flag,
403 * when the application-supplied buffer is too small, or
404 * the application asks for the length of buffer to hold
405 * the ciphertext.
406 */
407 REFRELE(session_p, lock_held);
408 return (rv);
409 }
410
411 /* Terminates the active encrypt operation. */
412 (void) pthread_mutex_lock(&session_p->session_mutex);
413 session_p->encrypt.flags = 0;
414 lock_held = B_TRUE;
415 REFRELE(session_p, lock_held);
416
417 return (rv);
418
419 clean_exit:
420 /* Terminates the active encrypt operation. */
421 kms_crypt_cleanup(session_p, B_TRUE, lock_held);
422
423 return (rv);
424 }
425