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 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <pthread.h>
27 #include <security/cryptoki.h>
28 #include "softGlobal.h"
29 #include "softSession.h"
30 #include "softObject.h"
31 #include "softOps.h"
32 
33 
34 CK_RV
C_DecryptInit(CK_SESSION_HANDLE hSession,CK_MECHANISM_PTR pMechanism,CK_OBJECT_HANDLE hKey)35 C_DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
36     CK_OBJECT_HANDLE hKey)
37 {
38 
39 	CK_RV		rv;
40 	soft_session_t	*session_p;
41 	soft_object_t	*key_p;
42 	boolean_t	lock_held = B_FALSE;
43 
44 	if (!softtoken_initialized)
45 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
46 
47 	/* Obtain the session pointer. */
48 	rv = handle2session(hSession, &session_p);
49 	if (rv != CKR_OK)
50 		return (rv);
51 
52 	if (pMechanism == NULL) {
53 		rv = CKR_ARGUMENTS_BAD;
54 		goto clean_exit;
55 	}
56 
57 	/* Obtain the object pointer. */
58 	HANDLE2OBJECT(hKey, key_p, rv);
59 	if (rv != CKR_OK)
60 		goto clean_exit;
61 
62 	/* Check to see if key object allows for decryption. */
63 	if (!(key_p->bool_attr_mask & DECRYPT_BOOL_ON)) {
64 		rv = CKR_KEY_FUNCTION_NOT_PERMITTED;
65 		goto clean_exit1;
66 	}
67 
68 	(void) pthread_mutex_lock(&session_p->session_mutex);
69 	lock_held = B_TRUE;
70 
71 	/* Check to see if decrypt operation is already active. */
72 	if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
73 		/* free the memory to avoid memory leak */
74 		soft_crypt_cleanup(session_p, B_FALSE, lock_held);
75 	}
76 
77 	/*
78 	 * This active flag will remain ON until application calls either
79 	 * C_Decrypt or C_DecryptFinal to actually obtain the final piece
80 	 * of plaintext.
81 	 */
82 	session_p->decrypt.flags = CRYPTO_OPERATION_ACTIVE;
83 
84 	(void) pthread_mutex_unlock(&session_p->session_mutex);
85 	lock_held = B_FALSE;
86 
87 	rv = soft_decrypt_init(session_p, pMechanism, key_p);
88 
89 	if (rv != CKR_OK) {
90 		(void) pthread_mutex_lock(&session_p->session_mutex);
91 		session_p->decrypt.flags &= ~CRYPTO_OPERATION_ACTIVE;
92 		lock_held = B_TRUE;
93 	}
94 
95 clean_exit1:
96 	OBJ_REFRELE(key_p);
97 clean_exit:
98 	SES_REFRELE(session_p, lock_held);
99 	return (rv);
100 }
101 
102 
103 CK_RV
C_Decrypt(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)104 C_Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData,
105     CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
106 {
107 
108 	CK_RV		rv;
109 	soft_session_t	*session_p;
110 	boolean_t	lock_held = B_FALSE;
111 
112 	if (!softtoken_initialized)
113 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
114 
115 	/* Obatin the session pointer. */
116 	rv = handle2session(hSession, &session_p);
117 	if (rv != CKR_OK)
118 		return (rv);
119 
120 	/*
121 	 * Only check if input buffer is null.  How to handle zero input
122 	 * length depents on the mechanism in use.  For secret key mechanisms,
123 	 * unpadded ones yield zero length output, but padded ones always
124 	 * result in smaller than original, possibly zero, length output.
125 	 */
126 	if (pEncryptedData == NULL) {
127 		rv = CKR_ARGUMENTS_BAD;
128 		goto clean_exit;
129 	}
130 
131 	/*
132 	 * No need to check pData because application might
133 	 * just want to know the length of decrypted data.
134 	 */
135 	if (pulDataLen == NULL) {
136 		rv = CKR_ARGUMENTS_BAD;
137 		goto clean_exit;
138 	}
139 
140 	(void) pthread_mutex_lock(&session_p->session_mutex);
141 	lock_held = B_TRUE;
142 
143 	/* Application must call C_DecryptInit before calling C_Decrypt. */
144 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
145 		SES_REFRELE(session_p, lock_held);
146 		return (CKR_OPERATION_NOT_INITIALIZED);
147 	}
148 
149 	/*
150 	 * C_Decrypt must be called without intervening C_DecryptUpdate
151 	 * calls.
152 	 */
153 	if (session_p->decrypt.flags & CRYPTO_OPERATION_UPDATE) {
154 		/*
155 		 * C_Decrypt can not be used to terminate a multi-part
156 		 * operation, so we'll leave the active decrypt operation
157 		 * flag on and let the application continue with the
158 		 * decrypt update operation.
159 		 */
160 		SES_REFRELE(session_p, lock_held);
161 		return (CKR_FUNCTION_FAILED);
162 	}
163 
164 	(void) pthread_mutex_unlock(&session_p->session_mutex);
165 	lock_held = B_FALSE;
166 
167 	rv = soft_decrypt(session_p, pEncryptedData, ulEncryptedDataLen,
168 	    pData, pulDataLen);
169 
170 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
171 	    (pData == NULL && rv == CKR_OK)) {
172 		/*
173 		 * We will not terminate the active decrypt operation flag,
174 		 * when the application-supplied buffer is too small, or
175 		 * the application asks for the length of buffer to hold
176 		 * the plaintext.
177 		 */
178 		SES_REFRELE(session_p, lock_held);
179 		return (rv);
180 	}
181 
182 clean_exit:
183 	/* Clear context, free key, and release session counter */
184 	soft_crypt_cleanup(session_p, B_FALSE, B_FALSE);
185 
186 	return (rv);
187 }
188 
189 
190 CK_RV
C_DecryptUpdate(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pEncryptedPart,CK_ULONG ulEncryptedPartLen,CK_BYTE_PTR pPart,CK_ULONG_PTR pulPartLen)191 C_DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart,
192     CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart,
193     CK_ULONG_PTR pulPartLen)
194 {
195 
196 	CK_RV		rv;
197 	soft_session_t	*session_p;
198 	boolean_t	lock_held = B_FALSE;
199 
200 	if (!softtoken_initialized)
201 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
202 
203 	/* Obtain the session pointer. */
204 	rv = handle2session(hSession, &session_p);
205 	if (rv != CKR_OK)
206 		return (rv);
207 
208 	/*
209 	 * Only check if input buffer is null.  How to handle zero input
210 	 * length depents on the mechanism in use.  For secret key mechanisms,
211 	 * unpadded ones yeild zero length output, but padded ones always
212 	 * result in smaller than original, possibly zero, length output.
213 	 */
214 	if (pEncryptedPart == NULL) {
215 		rv = CKR_ARGUMENTS_BAD;
216 		goto clean_exit;
217 	}
218 
219 	/*
220 	 * Only check if pulPartLen is NULL.
221 	 * No need to check if pPart is NULL because application
222 	 * might just ask for the length of buffer to hold the
223 	 * recovered data.
224 	 */
225 	if (pulPartLen == NULL) {
226 		rv = CKR_ARGUMENTS_BAD;
227 		goto clean_exit;
228 	}
229 
230 	(void) pthread_mutex_lock(&session_p->session_mutex);
231 	lock_held = B_TRUE;
232 
233 	/*
234 	 * Application must call C_DecryptInit before calling
235 	 * C_DecryptUpdate.
236 	 */
237 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
238 		SES_REFRELE(session_p, lock_held);
239 		return (CKR_OPERATION_NOT_INITIALIZED);
240 	}
241 
242 	session_p->decrypt.flags |= CRYPTO_OPERATION_UPDATE;
243 
244 	(void) pthread_mutex_unlock(&session_p->session_mutex);
245 	lock_held = B_FALSE;
246 
247 	rv = soft_decrypt_update(session_p, pEncryptedPart,
248 	    ulEncryptedPartLen, pPart, pulPartLen);
249 
250 	/*
251 	 * If CKR_OK or CKR_BUFFER_TOO_SMALL, don't terminate the
252 	 * current decryption operation.
253 	 */
254 	if ((rv == CKR_OK) || (rv == CKR_BUFFER_TOO_SMALL)) {
255 		SES_REFRELE(session_p, lock_held);
256 		return (rv);
257 	}
258 
259 clean_exit:
260 	/*
261 	 * After an error occurred, terminate the current decrypt
262 	 * operation by resetting the active and update flags.
263 	 */
264 	soft_crypt_cleanup(session_p, B_FALSE, lock_held);
265 
266 	return (rv);
267 }
268 
269 CK_RV
C_DecryptFinal(CK_SESSION_HANDLE hSession,CK_BYTE_PTR pLastPart,CK_ULONG_PTR pulLastPartLen)270 C_DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart,
271     CK_ULONG_PTR pulLastPartLen)
272 {
273 
274 	CK_RV		rv;
275 	soft_session_t	*session_p;
276 	boolean_t	lock_held = B_FALSE;
277 
278 	if (!softtoken_initialized)
279 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
280 
281 	/* Obtain the session pointer. */
282 	rv = handle2session(hSession, &session_p);
283 	if (rv != CKR_OK)
284 		return (rv);
285 
286 	if (pulLastPartLen == NULL) {
287 		rv = CKR_ARGUMENTS_BAD;
288 		goto clean_exit;
289 	}
290 
291 	(void) pthread_mutex_lock(&session_p->session_mutex);
292 	lock_held = B_TRUE;
293 
294 	/*
295 	 * Application must call C_DecryptInit before calling
296 	 * C_DecryptFinal.
297 	 */
298 	if (!(session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE)) {
299 		SES_REFRELE(session_p, lock_held);
300 		return (CKR_OPERATION_NOT_INITIALIZED);
301 	}
302 
303 	(void) pthread_mutex_unlock(&session_p->session_mutex);
304 	lock_held = B_FALSE;
305 
306 	rv = soft_decrypt_final(session_p, pLastPart, pulLastPartLen);
307 
308 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
309 	    (pLastPart == NULL && rv == CKR_OK)) {
310 		/*
311 		 * We will not terminate the active decrypt operation flag,
312 		 * when the application-supplied buffer is too small, or
313 		 * the application asks for the length of buffer to hold
314 		 * the plaintext.
315 		 */
316 		SES_REFRELE(session_p, lock_held);
317 		return (rv);
318 	}
319 
320 	/* Terminates the active encrypt operation. */
321 	(void) pthread_mutex_lock(&session_p->session_mutex);
322 	session_p->decrypt.flags = 0;
323 	lock_held = B_TRUE;
324 	SES_REFRELE(session_p, lock_held);
325 	return (rv);
326 
327 clean_exit:
328 	/* Terminates the active decrypt operation */
329 	soft_crypt_cleanup(session_p, B_FALSE, lock_held);
330 
331 	return (rv);
332 }
333