xref: /onnv-gate/usr/src/lib/pkcs11/pkcs11_kms/common/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  */
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