kmsDecrypt.c revision 12720:3db6e0082404
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 */
51CK_RV
52kms_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
111CK_RV
112C_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
171clean_exit1:
172	OBJ_REFRELE(key_p);
173clean_exit:
174	REFRELE(session_p, lock_held);
175	return (rv);
176}
177
178CK_RV
179C_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
256clean_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
263CK_RV
264C_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
332clean_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
342CK_RV
343C_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
400clean_exit:
401	/* Terminates the active decrypt operation */
402	kms_crypt_cleanup(session_p, B_FALSE, lock_held);
403
404	return (rv);
405}
406