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 2005 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 "softOps.h"
33 #include "softSession.h"
34 
35 
36 CK_RV
37 C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism)
38 {
39 
40 	CK_RV		rv;
41 	soft_session_t	*session_p;
42 	boolean_t lock_held = B_TRUE;
43 
44 	if (!softtoken_initialized)
45 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
46 
47 	/*
48 	 * Obtain the session pointer. Also, increment the session
49 	 * reference count.
50 	 */
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 	/* Acquire the session lock */
61 	(void) pthread_mutex_lock(&session_p->session_mutex);
62 
63 	/* Check to see if digest operation is already active */
64 	if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
65 		/*
66 		 * Free the memory to avoid memory leak.
67 		 * digest.context is only a flat structure.
68 		 */
69 
70 		if (session_p->digest.context)
71 			free(session_p->digest.context);
72 	}
73 
74 	/*
75 	 * This active flag will remain ON until application calls either
76 	 * C_Digest or C_DigestFinal to actually obtain the value of
77 	 * the message digest.
78 	 */
79 	session_p->digest.flags = CRYPTO_OPERATION_ACTIVE;
80 
81 	(void) pthread_mutex_unlock(&session_p->session_mutex);
82 
83 	rv = soft_digest_init(session_p, pMechanism);
84 
85 	if (rv != CKR_OK) {
86 		(void) pthread_mutex_lock(&session_p->session_mutex);
87 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
88 		/*
89 		 * Decrement the session reference count.
90 		 * We hold the session lock, and SES_REFRELE()
91 		 * will release the session lock for us.
92 		 */
93 		SES_REFRELE(session_p, lock_held);
94 		return (rv);
95 	}
96 
97 clean_exit:
98 	/*
99 	 * Decrement the session reference count.
100 	 * We do not hold the session lock.
101 	 */
102 	lock_held = B_FALSE;
103 	SES_REFRELE(session_p, lock_held);
104 	return (rv);
105 }
106 
107 
108 CK_RV
109 C_Digest(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
110     CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
111 {
112 
113 	CK_RV		rv;
114 	soft_session_t	*session_p;
115 	boolean_t lock_held = B_TRUE;
116 
117 	if (!softtoken_initialized)
118 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
119 
120 	/*
121 	 * Obtain the session pointer. Also, increment the session
122 	 * reference count.
123 	 */
124 	rv = handle2session(hSession, &session_p);
125 	if (rv != CKR_OK)
126 		return (rv);
127 
128 	if (pData == NULL || pulDigestLen == NULL) {
129 		rv = CKR_ARGUMENTS_BAD;
130 		goto clean_exit;
131 	}
132 
133 	/* Acquire the session lock */
134 	(void) pthread_mutex_lock(&session_p->session_mutex);
135 
136 	/* Application must call C_DigestInit before calling C_Digest */
137 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
138 		/*
139 		 * Decrement the session reference count.
140 		 * We hold the session lock, and SES_REFRELE()
141 		 * will release the session lock for us.
142 		 */
143 		SES_REFRELE(session_p, lock_held);
144 		return (CKR_OPERATION_NOT_INITIALIZED);
145 	}
146 
147 	/*
148 	 * C_Digest must be called without intervening C_DigestUpdate
149 	 * calls.
150 	 */
151 	if (session_p->digest.flags & CRYPTO_OPERATION_UPDATE) {
152 		/*
153 		 * C_Digest can not be used to terminate a multi-part
154 		 * operation, so we'll leave the active digest operation
155 		 * flag on and let the application continue with the
156 		 * digest update operation.
157 		 *
158 		 * Decrement the session reference count.
159 		 * We hold the session lock, and SES_REFRELE()
160 		 * will release the session lock for us.
161 		 */
162 		SES_REFRELE(session_p, lock_held);
163 		return (CKR_FUNCTION_FAILED);
164 	}
165 
166 	(void) pthread_mutex_unlock(&session_p->session_mutex);
167 
168 	rv = soft_digest(session_p, pData, ulDataLen, pDigest, pulDigestLen);
169 
170 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
171 	    (pDigest == NULL && rv == CKR_OK)) {
172 		/*
173 		 * We will not terminate the active digest 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 message digest.
177 		 *
178 		 * Decrement the session reference count.
179 		 * We do not hold the session lock.
180 		 */
181 		lock_held = B_FALSE;
182 		SES_REFRELE(session_p, lock_held);
183 		return (rv);
184 	}
185 
186 clean_exit:
187 	/*
188 	 * Terminates the active digest operation.
189 	 * Application needs to call C_DigestInit again for next
190 	 * digest operation.
191 	 */
192 	(void) pthread_mutex_lock(&session_p->session_mutex);
193 	session_p->digest.flags = 0;
194 
195 	/*
196 	 * Decrement the session reference count.
197 	 * We hold the session lock, and SES_REFRELE()
198 	 * will release the session lock for us.
199 	 */
200 	SES_REFRELE(session_p, lock_held);
201 
202 	return (rv);
203 }
204 
205 
206 CK_RV
207 C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart,
208     CK_ULONG ulPartLen)
209 {
210 
211 	CK_RV		rv;
212 	soft_session_t	*session_p;
213 	boolean_t lock_held = B_TRUE;
214 
215 	if (!softtoken_initialized)
216 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
217 
218 	/*
219 	 * Obtain the session pointer. Also, increment the session
220 	 * reference count.
221 	 */
222 	rv = handle2session(hSession, &session_p);
223 	if (rv != CKR_OK)
224 		return (rv);
225 
226 	if (pPart == NULL) {
227 		rv = CKR_ARGUMENTS_BAD;
228 		goto clean_exit;
229 	}
230 
231 	/* Acquire the session lock */
232 	(void) pthread_mutex_lock(&session_p->session_mutex);
233 
234 	/*
235 	 * Application must call C_DigestInit before calling
236 	 * C_DigestUpdate.
237 	 */
238 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
239 		/*
240 		 * Decrement the session reference count.
241 		 * We hold the session lock, and SES_REFRELE()
242 		 * will release the session lock for us.
243 		 */
244 		SES_REFRELE(session_p, lock_held);
245 		return (CKR_OPERATION_NOT_INITIALIZED);
246 	}
247 
248 	/* Set update flag to protect C_Digest */
249 	session_p->digest.flags |= CRYPTO_OPERATION_UPDATE;
250 
251 	(void) pthread_mutex_unlock(&session_p->session_mutex);
252 
253 	rv = soft_digest_update(session_p, pPart, ulPartLen);
254 
255 	if (rv == CKR_OK) {
256 		/*
257 		 * Decrement the session reference count.
258 		 * We do not hold the session lock.
259 		 */
260 		lock_held = B_FALSE;
261 		SES_REFRELE(session_p, lock_held);
262 		return (CKR_OK);
263 	}
264 
265 clean_exit:
266 	/*
267 	 * After an error occurred, terminate the current digest
268 	 * operation by resetting the active and update flags.
269 	 */
270 	(void) pthread_mutex_lock(&session_p->session_mutex);
271 	session_p->digest.flags = 0;
272 
273 	/*
274 	 * Decrement the session reference count.
275 	 * We hold the session lock, and SES_REFRELE()
276 	 * will release the session lock for us.
277 	 */
278 	SES_REFRELE(session_p, lock_held);
279 
280 	return (rv);
281 }
282 
283 
284 CK_RV
285 C_DigestKey(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hKey)
286 {
287 
288 	CK_RV		rv;
289 	soft_session_t	*session_p;
290 	soft_object_t	*key_p;
291 	boolean_t lock_held = B_TRUE;
292 
293 	if (!softtoken_initialized)
294 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
295 
296 	/*
297 	 * Obtain the session pointer. Also, increment the session
298 	 * reference count.
299 	 */
300 	rv = handle2session(hSession, &session_p);
301 	if (rv != CKR_OK)
302 		return (rv);
303 
304 	/* Obtain the object pointer. */
305 	HANDLE2OBJECT(hKey, key_p, rv);
306 	if (rv != CKR_OK)
307 		goto clean_exit;
308 
309 	(void) pthread_mutex_lock(&session_p->session_mutex);
310 
311 	/*
312 	 * Application must call C_DigestInit before calling
313 	 * C_DigestKey.
314 	 */
315 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
316 		/*
317 		 * Decrement the session reference count.
318 		 * We hold the session lock, and SES_REFRELE()
319 		 * will release the session lock for us.
320 		 */
321 		OBJ_REFRELE(key_p);
322 		SES_REFRELE(session_p, lock_held);
323 		return (CKR_OPERATION_NOT_INITIALIZED);
324 	}
325 
326 	/*
327 	 * Remember the fact that a key was thrown into the mix, so that
328 	 * C_DigestFinal bzero()'s the digest context before freeing it.
329 	 */
330 	session_p->digest.flags |= (CRYPTO_KEY_DIGESTED |
331 	    CRYPTO_OPERATION_UPDATE);
332 
333 	(void) pthread_mutex_unlock(&session_p->session_mutex);
334 
335 	rv = soft_digest_key(session_p, key_p);
336 
337 	if (rv == CKR_OK) {
338 		/*
339 		 * Decrement the session reference count.
340 		 * We do not hold the session lock.
341 		 */
342 		lock_held = B_FALSE;
343 		OBJ_REFRELE(key_p);
344 		SES_REFRELE(session_p, lock_held);
345 		return (CKR_OK);
346 	}
347 
348 	OBJ_REFRELE(key_p);
349 clean_exit:
350 	/*
351 	 * After an error occurred, terminate the current digest
352 	 * operation by resetting the active and update flags.
353 	 */
354 	(void) pthread_mutex_lock(&session_p->session_mutex);
355 	session_p->digest.flags = 0;
356 
357 	/*
358 	 * Decrement the session reference count.
359 	 * We hold the session lock, and SES_REFRELE()
360 	 * will release the session lock for us.
361 	 */
362 	SES_REFRELE(session_p, lock_held);
363 	return (rv);
364 }
365 
366 
367 CK_RV
368 C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest,
369     CK_ULONG_PTR pulDigestLen)
370 {
371 
372 	CK_RV		rv;
373 	soft_session_t	*session_p;
374 	boolean_t lock_held = B_TRUE;
375 
376 	if (!softtoken_initialized)
377 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
378 
379 	/*
380 	 * Obtain the session pointer. Also, increment the session
381 	 * reference count.
382 	 */
383 	rv = handle2session(hSession, &session_p);
384 	if (rv != CKR_OK)
385 		return (rv);
386 
387 	if (pulDigestLen == NULL) {
388 		rv = CKR_ARGUMENTS_BAD;
389 		goto clean_exit;
390 	}
391 
392 	/* Acquire the session lock */
393 	(void) pthread_mutex_lock(&session_p->session_mutex);
394 
395 	/*
396 	 * Application must call C_DigestInit before calling
397 	 * C_DigestFinal.
398 	 */
399 	if (!(session_p->digest.flags & CRYPTO_OPERATION_ACTIVE)) {
400 		/*
401 		 * Decrement the session reference count.
402 		 * We hold the session lock, and SES_REFRELE()
403 		 * will release the session lock for us.
404 		 */
405 		SES_REFRELE(session_p, lock_held);
406 		return (CKR_OPERATION_NOT_INITIALIZED);
407 	}
408 
409 	(void) pthread_mutex_unlock(&session_p->session_mutex);
410 
411 	rv = soft_digest_final(session_p, pDigest, pulDigestLen);
412 
413 	if ((rv == CKR_BUFFER_TOO_SMALL) ||
414 	    (pDigest == NULL && rv == CKR_OK)) {
415 		/*
416 		 * We will not terminate the active digest operation flag,
417 		 * when the application-supplied buffer is too small, or
418 		 * the application asks for the length of buffer to hold
419 		 * the message digest.
420 		 *
421 		 * Decrement the session reference count.
422 		 * We do not hold the session lock.
423 		 */
424 		lock_held = B_FALSE;
425 		SES_REFRELE(session_p, lock_held);
426 		return (rv);
427 	}
428 
429 clean_exit:
430 	/* Terminates the active digest operation */
431 	(void) pthread_mutex_lock(&session_p->session_mutex);
432 	session_p->digest.flags = 0;
433 
434 	/*
435 	 * Decrement the session reference count.
436 	 * We hold the session lock, and SES_REFRELE()
437 	 * will release the session lock for us.
438 	 */
439 	SES_REFRELE(session_p, lock_held);
440 
441 	return (rv);
442 }
443