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