xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDecrypt.c (revision 2bda830b1b393f809c54b105ec8ab418c3e505a1)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <pthread.h>
30 #include <security/cryptoki.h>
31 #include "softGlobal.h"
32 #include "softSession.h"
33 #include "softObject.h"
34 #include "softOps.h"
35 
36 
37 CK_RV
38 C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
39     CK_OBJECT_HANDLE hKey)
40 {
41 
42 	CK_RV		rv;
43 	soft_session_t	*session_p;
44 	soft_object_t	*key_p;
45 	boolean_t	lock_held = B_FALSE;
46 
47 	if (!softtoken_initialized)
48 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
49 
50 	/* Obtain the session pointer. */
51 	rv = handle2session(hSession, &session_p);
52 	if (rv != CKR_OK)
53 		return (rv);
54 
55 	if (pMechanism == NULL) {
56 		rv = CKR_ARGUMENTS_BAD;
57 		goto clean_exit;
58 	}
59 
60 	/* Obtain the object pointer. */
61 	HANDLE2OBJECT(hKey, key_p, rv);
62 	if (rv != CKR_OK)
63 		goto clean_exit;
64 
65 	/* Check to see if key object allows for decryption. */
66 	if (!(key_p->bool_attr_mask & DECRYPT_BOOL_ON)) {
67 		rv = CKR_KEY_TYPE_INCONSISTENT;
68 		goto clean_exit1;
69 	}
70 
71 	(void) pthread_mutex_lock(&session_p->session_mutex);
72 	lock_held = B_TRUE;
73 
74 	/* Check to see if decrypt operation is already active. */
75 	if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
76 		/* free the memory to avoid memory leak */
77 		soft_crypt_cleanup(session_p, B_FALSE, lock_held);
78 	}
79 
80 	/*
81 	 * This active flag will remain ON until application calls either
82 	 * C_Decrypt or C_DecryptFinal to actually obtain the final piece
83 	 * of plaintext.
84 	 */
85 	session_p->decrypt.flags = CRYPTO_OPERATION_ACTIVE;
86 
87 	(void) pthread_mutex_unlock(&session_p->session_mutex);
88 	lock_held = B_FALSE;
89 
90 	rv = soft_decrypt_init(session_p, pMechanism, key_p);
91 
92 	if (rv != CKR_OK) {
93 		(void) pthread_mutex_lock(&session_p->session_mutex);
94 		session_p->decrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
95 		lock_held = B_TRUE;
96 	}
97 
98 clean_exit1:
99 	OBJ_REFRELE(key_p);
100 clean_exit:
101 	SES_REFRELE(session_p, lock_held);
102 	return (rv);
103 }
104 
105 
106 CK_RV
107 C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData,
108     CK_ULONG ulEncryptedData, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
109 {
110 
111 	CK_RV		rv;
112 	soft_session_t	*session_p;
113 	boolean_t	lock_held = B_FALSE;
114 
115 	if (!softtoken_initialized)
116 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
117 
118 	/* Obatin the session pointer. */
119 	rv = handle2session(hSession, &session_p);
120 	if (rv != CKR_OK)
121 		return (rv);
122 
123 	/*
124 	 * No need to check pData because application might
125 	 * just want to know the length of decrypted data.
126 	 */
127 	if (pulDataLen == NULL) {
128 		rv = CKR_ARGUMENTS_BAD;
129 		goto clean_exit;
130 	}
131 
132 	(void) pthread_mutex_lock(&session_p->session_mutex);
133 	lock_held = B_TRUE;
134 
135 	/* Application must call C_DecryptInit before calling C_Decrypt. */
136 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
137 		SES_REFRELE(session_p, lock_held);
138 		return (CKR_OPERATION_NOT_INITIALIZED);
139 	}
140 
141 	/*
142 	 * C_Decrypt must be called without intervening C_DecryptUpdate
143 	 * calls.
144 	 */
145 	if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
146 		/*
147 		 * C_Decrypt can not be used to terminate a multi-part
148 		 * operation, so we'll leave the active decrypt operation
149 		 * flag on and let the application continue with the
150 		 * decrypt update operation.
151 		 */
152 		SES_REFRELE(session_p, lock_held);
153 		return (CKR_FUNCTION_FAILED);
154 	}
155 
156 	(void) pthread_mutex_unlock(&session_p->session_mutex);
157 	lock_held = B_FALSE;
158 
159 	rv = soft_decrypt(session_p, pEncryptedData, ulEncryptedData,
160 	    pData, pulDataLen);
161 
162 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
163 	    (pData == NULL && rv == CKR_OK)) {
164 		/*
165 		 * We will not terminate the active decrypt operation flag,
166 		 * when the application-supplied buffer is too small, or
167 		 * the application asks for the length of buffer to hold
168 		 * the plaintext.
169 		 */
170 		SES_REFRELE(session_p, lock_held);
171 		return (rv);
172 	}
173 
174 	/*
175 	 * Normal exit.
176 	 * Terminates the active encrypt operation.
177 	 * Application needs to call C_EncryptInit again for next
178 	 * encrypt operation.
179 	 */
180 	(void) pthread_mutex_lock(&session_p->session_mutex);
181 	session_p->decrypt.flags = 0;
182 	lock_held = B_TRUE;
183 	SES_REFRELE(session_p, lock_held);
184 	return (rv);
185 
186 clean_exit:
187 	soft_crypt_cleanup(session_p, B_FALSE, lock_held);
188 
189 	return (rv);
190 }
191 
192 
193 CK_RV
194 C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart,
195     CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart,
196     CK_ULONG_PTR pulPartLen)
197 {
198 
199 	CK_RV		rv;
200 	soft_session_t	*session_p;
201 	boolean_t	lock_held = B_FALSE;
202 
203 	if (!softtoken_initialized)
204 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
205 
206 	/* Obtain the session pointer. */
207 	rv = handle2session(hSession, &session_p);
208 	if (rv != CKR_OK)
209 		return (rv);
210 
211 	if (ulEncryptedPartLen == 0) {
212 		SES_REFRELE(session_p, lock_held);
213 		return (CKR_OK);
214 	}
215 
216 	if (pEncryptedPart == NULL) {
217 		rv = CKR_ARGUMENTS_BAD;
218 		goto clean_exit;
219 	}
220 
221 	/*
222 	 * Only check if pulPartLen is NULL.
223 	 * No need to check if pPart is NULL because application
224 	 * might just ask for the length of buffer to hold the
225 	 * recovered data.
226 	 */
227 	if (pulPartLen == NULL) {
228 		rv = CKR_ARGUMENTS_BAD;
229 		goto clean_exit;
230 	}
231 
232 	(void) pthread_mutex_lock(&session_p->session_mutex);
233 	lock_held = B_TRUE;
234 
235 	/*
236 	 * Application must call C_DecryptInit before calling
237 	 * C_DecryptUpdate.
238 	 */
239 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
240 		SES_REFRELE(session_p, lock_held);
241 		return (CKR_OPERATION_NOT_INITIALIZED);
242 	}
243 
244 	session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
245 
246 	(void) pthread_mutex_unlock(&session_p->session_mutex);
247 	lock_held = B_FALSE;
248 
249 	rv = soft_decrypt_update(session_p, pEncryptedPart,
250 	    ulEncryptedPartLen, pPart, pulPartLen);
251 
252 	/*
253 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, don't terminate the
254 	 * current decryption operation.
255 	 */
256 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) {
257 		SES_REFRELE(session_p, lock_held);
258 		return (rv);
259 	}
260 
261 clean_exit:
262 	/*
263 	 * After an error occurred, terminate the current decrypt
264 	 * operation by resetting the active and update flags.
265 	 */
266 	soft_crypt_cleanup(session_p, B_FALSE, lock_held);
267 
268 	return (rv);
269 }
270 
271 CK_RV
272 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
273     CK_ULONG_PTR pulLastPartLen)
274 {
275 
276 	CK_RV		rv;
277 	soft_session_t	*session_p;
278 	boolean_t	lock_held = B_FALSE;
279 
280 	if (!softtoken_initialized)
281 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
282 
283 	/* Obtain the session pointer. */
284 	rv = handle2session(hSession, &session_p);
285 	if (rv != CKR_OK)
286 		return (rv);
287 
288 	if (pulLastPartLen == NULL) {
289 		rv = CKR_ARGUMENTS_BAD;
290 		goto clean_exit;
291 	}
292 
293 	(void) pthread_mutex_lock(&session_p->session_mutex);
294 	lock_held = B_TRUE;
295 
296 	/*
297 	 * Application must call C_DecryptInit before calling
298 	 * C_DecryptFinal.
299 	 */
300 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
301 		SES_REFRELE(session_p, lock_held);
302 		return (CKR_OPERATION_NOT_INITIALIZED);
303 	}
304 
305 	(void) pthread_mutex_unlock(&session_p->session_mutex);
306 	lock_held = B_FALSE;
307 
308 	rv = soft_decrypt_final(session_p, pLastPart, pulLastPartLen);
309 
310 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
311 	    (pLastPart == NULL && rv == CKR_OK)) {
312 		/*
313 		 * We will not terminate the active decrypt operation flag,
314 		 * when the application-supplied buffer is too small, or
315 		 * the application asks for the length of buffer to hold
316 		 * the plaintext.
317 		 */
318 		SES_REFRELE(session_p, lock_held);
319 		return (rv);
320 	}
321 
322 	/* Terminates the active encrypt operation. */
323 	(void) pthread_mutex_lock(&session_p->session_mutex);
324 	session_p->decrypt.flags = 0;
325 	lock_held = B_TRUE;
326 	SES_REFRELE(session_p, lock_held);
327 	return (rv);
328 
329 clean_exit:
330 	/* Terminates the active decrypt operation */
331 	soft_crypt_cleanup(session_p, B_FALSE, lock_held);
332 
333 	return (rv);
334 }
335