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