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 <strings.h>
30 #include <md5.h>
31 #include <pthread.h>
32 #include <stdlib.h>
33 #include <sys/sha1.h>
34 #include <sys/sha2.h>
35 #include <sys/types.h>
36 #include <security/cryptoki.h>
37 #include "softGlobal.h"
38 #include "softOps.h"
39 #include "softSession.h"
40 #include "softObject.h"
41 
42 
43 /*
44  * soft_digest_init()
45  *
46  * Arguments:
47  *	session_p:	pointer to soft_session_t struct
48  *	pMechanism:	pointer to CK_MECHANISM struct provided by application
49  *
50  * Description:
51  *	called by C_DigestInit(). This function allocates space for
52  *  	context, then calls the corresponding software provided digest
53  *	init routine based on the mechanism.
54  *
55  * Returns:
56  *	CKR_OK: success
57  *	CKR_HOST_MEMORY: run out of system memory
58  *	CKR_MECHANISM_INVALID: invalid mechanism type
59  */
60 CK_RV
61 soft_digest_init(soft_session_t *session_p, CK_MECHANISM_PTR pMechanism)
62 {
63 
64 	switch (pMechanism->mechanism) {
65 
66 	case CKM_MD5:
67 		(void) pthread_mutex_lock(&session_p->session_mutex);
68 
69 		session_p->digest.context = malloc(sizeof (MD5_CTX));
70 
71 		if (session_p->digest.context == NULL) {
72 			(void) pthread_mutex_unlock(&session_p->session_mutex);
73 			return (CKR_HOST_MEMORY);
74 		}
75 
76 		session_p->digest.mech.mechanism = CKM_MD5;
77 		(void) pthread_mutex_unlock(&session_p->session_mutex);
78 
79 		MD5Init((MD5_CTX *)session_p->digest.context);
80 
81 		break;
82 
83 	case CKM_SHA_1:
84 
85 		(void) pthread_mutex_lock(&session_p->session_mutex);
86 
87 		session_p->digest.context = malloc(sizeof (SHA1_CTX));
88 
89 		if (session_p->digest.context == NULL) {
90 			(void) pthread_mutex_unlock(&session_p->session_mutex);
91 			return (CKR_HOST_MEMORY);
92 		}
93 
94 		session_p->digest.mech.mechanism = CKM_SHA_1;
95 		session_p->digest.mech.pParameter = pMechanism->pParameter;
96 		session_p->digest.mech.ulParameterLen =
97 		    pMechanism->ulParameterLen;
98 		(void) pthread_mutex_unlock(&session_p->session_mutex);
99 
100 		SHA1Init((SHA1_CTX *)session_p->digest.context);
101 
102 		break;
103 
104 	case CKM_SHA256:
105 	case CKM_SHA384:
106 	case CKM_SHA512:
107 
108 		(void) pthread_mutex_lock(&session_p->session_mutex);
109 
110 		session_p->digest.context = malloc(sizeof (SHA2_CTX));
111 
112 		if (session_p->digest.context == NULL) {
113 			(void) pthread_mutex_unlock(&session_p->session_mutex);
114 			return (CKR_HOST_MEMORY);
115 		}
116 
117 		switch (pMechanism->mechanism) {
118 		case CKM_SHA256:
119 			session_p->digest.mech.mechanism = CKM_SHA256;
120 			(void) pthread_mutex_unlock(&session_p->session_mutex);
121 			SHA2Init(SHA256,
122 			    (SHA2_CTX *)session_p->digest.context);
123 			break;
124 
125 		case CKM_SHA384:
126 			session_p->digest.mech.mechanism = CKM_SHA384;
127 			(void) pthread_mutex_unlock(&session_p->session_mutex);
128 			SHA2Init(SHA384,
129 			    (SHA2_CTX *)session_p->digest.context);
130 			break;
131 
132 		case CKM_SHA512:
133 			session_p->digest.mech.mechanism = CKM_SHA512;
134 			(void) pthread_mutex_unlock(&session_p->session_mutex);
135 			SHA2Init(SHA512,
136 			    (SHA2_CTX *)session_p->digest.context);
137 			break;
138 		}
139 		break;
140 
141 	default:
142 		return (CKR_MECHANISM_INVALID);
143 	}
144 
145 	return (CKR_OK);
146 }
147 
148 
149 /*
150  * soft_digest_common()
151  *
152  * Arguments:
153  *      session_p:	pointer to soft_session_t struct
154  *	pData:		pointer to the input data to be digested
155  *	ulDataLen:	length of the input data
156  *	pDigest:	pointer to the output data after digesting
157  *	pulDigestLen:	length of the output data
158  *
159  * Description:
160  *      called by soft_digest() or soft_digest_final(). This function
161  *      determines the length of output buffer and calls the corresponding
162  *	software provided digest routine based on the mechanism.
163  *
164  * Returns:
165  *      CKR_OK: success
166  *      CKR_MECHANISM_INVALID: invalid mechanism type
167  *      CKR_BUFFER_TOO_SMALL: the output buffer provided by application
168  *			      is too small
169  */
170 CK_RV
171 soft_digest_common(soft_session_t *session_p, CK_BYTE_PTR pData,
172 	CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
173 {
174 
175 	CK_ULONG digestLen = 0;
176 	size_t len = 0;
177 
178 	/*
179 	 * Determine the output data length based on the mechanism
180 	 */
181 	switch (session_p->digest.mech.mechanism) {
182 
183 	case CKM_MD5:
184 		digestLen = 16;
185 		break;
186 
187 	case CKM_SHA_1:
188 		digestLen = 20;
189 		break;
190 
191 	case CKM_SHA256:
192 		digestLen = 32;
193 		break;
194 
195 	case CKM_SHA384:
196 		digestLen = 48;
197 		break;
198 
199 	case CKM_SHA512:
200 		digestLen = 64;
201 		break;
202 
203 	default:
204 		return (CKR_MECHANISM_INVALID);
205 	}
206 
207 	if (pDigest == NULL) {
208 		/*
209 		 * Application only wants to know the length of the
210 		 * buffer needed to hold the message digest.
211 		 */
212 		*pulDigestLen = digestLen;
213 		return (CKR_OK);
214 	}
215 
216 	if (*pulDigestLen < digestLen) {
217 		/*
218 		 * Application provides buffer too small to hold the
219 		 * digest message. Return the length of buffer needed
220 		 * to the application.
221 		 */
222 		*pulDigestLen = digestLen;
223 		return (CKR_BUFFER_TOO_SMALL);
224 	}
225 
226 	/*
227 	 * Call the corresponding system provided software digest routine.
228 	 * If the soft_digest_common() is called by soft_digest_final()
229 	 * the pData is NULL, and the ulDataLen is zero.
230 	 */
231 	switch (session_p->digest.mech.mechanism) {
232 
233 	case CKM_MD5:
234 		if (pData != NULL) {
235 			/*
236 			 * this is called by soft_digest()
237 			 */
238 #ifdef	__sparcv9
239 			MD5Update((MD5_CTX *)session_p->digest.context,
240 			    /* LINTED */
241 			    pData, (uint_t)ulDataLen);
242 #else	/* !__sparcv9 */
243 			MD5Update((MD5_CTX *)session_p->digest.context,
244 			    pData, ulDataLen);
245 #endif	/* __sparcv9 */
246 			MD5Final(pDigest, (MD5_CTX *)session_p->digest.context);
247 		} else {
248 			/*
249 			 * this is called by soft_digest_final()
250 			 */
251 			MD5Final(pDigest, (MD5_CTX *)session_p->digest.context);
252 			len = sizeof (MD5_CTX);
253 		}
254 		break;
255 
256 	case CKM_SHA_1:
257 		if (pData != NULL) {
258 			/*
259 			 * this is called by soft_digest()
260 			 */
261 
262 #ifdef	__sparcv9
263 			SHA1Update((SHA1_CTX *)session_p->digest.context,
264 			    /* LINTED */
265 			    pData, (uint32_t)ulDataLen);
266 #else	/* !__sparcv9 */
267 			SHA1Update((SHA1_CTX *)session_p->digest.context,
268 			    pData, ulDataLen);
269 #endif	/* __sparcv9 */
270 			SHA1Final(pDigest,
271 			    (SHA1_CTX *)session_p->digest.context);
272 		} else {
273 			/*
274 			 * this is called by soft_digest_final()
275 			 */
276 			SHA1Final(pDigest,
277 			    (SHA1_CTX *)session_p->digest.context);
278 			len = sizeof (SHA1_CTX);
279 		}
280 		break;
281 	case CKM_SHA256:
282 	case CKM_SHA384:
283 	case CKM_SHA512:
284 		if (pData != NULL) {
285 			/*
286 			 * this is called by soft_digest()
287 			 */
288 
289 			SHA2Update((SHA2_CTX *)session_p->digest.context,
290 			    pData, ulDataLen);
291 
292 			SHA2Final(pDigest,
293 			    (SHA2_CTX *)session_p->digest.context);
294 		} else {
295 			/*
296 			 * this is called by soft_digest_final()
297 			 */
298 			SHA2Final(pDigest,
299 			    (SHA2_CTX *)session_p->digest.context);
300 			len = sizeof (SHA2_CTX);
301 		}
302 
303 		break;
304 	}
305 
306 	/* Paranoia on behalf of C_DigestKey callers: bzero the context */
307 	if (session_p->digest.flags & CRYPTO_KEY_DIGESTED) {
308 		bzero(session_p->digest.context, len);
309 		session_p->digest.flags &= ~CRYPTO_KEY_DIGESTED;
310 	}
311 	*pulDigestLen = digestLen;
312 	(void) pthread_mutex_lock(&session_p->session_mutex);
313 	free(session_p->digest.context);
314 	session_p->digest.context = NULL;
315 	(void) pthread_mutex_unlock(&session_p->session_mutex);
316 
317 	return (CKR_OK);
318 }
319 
320 
321 /*
322  * soft_digest()
323  *
324  * Arguments:
325  *      session_p:	pointer to soft_session_t struct
326  *      pData:		pointer to the input data to be digested
327  *      ulDataLen:	length of the input data
328  *      pDigest:	pointer to the output data after digesting
329  *      pulDigestLen:	length of the output data
330  *
331  * Description:
332  *      called by C_Digest(). This function calls soft_digest_common().
333  *
334  * Returns:
335  *      see return values in soft_digest_common().
336  */
337 CK_RV
338 soft_digest(soft_session_t *session_p, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
339 	CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
340 {
341 
342 	return (soft_digest_common(session_p, pData, ulDataLen,
343 	    pDigest, pulDigestLen));
344 }
345 
346 
347 /*
348  * soft_digest_update()
349  *
350  * Arguments:
351  *      session_p:	pointer to soft_session_t struct
352  *      pPart:		pointer to the input data to be digested
353  *      ulPartLen:	length of the input data
354  *
355  * Description:
356  *      called by C_DigestUpdate(). This function calls the corresponding
357  *	software provided digest update routine based on the mechanism.
358  *
359  * Returns:
360  *      CKR_OK: success
361  *      CKR_MECHANISM_INVALID: invalid MECHANISM type.
362  */
363 CK_RV
364 soft_digest_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
365 	CK_ULONG ulPartLen)
366 {
367 
368 	switch (session_p->digest.mech.mechanism) {
369 
370 	case CKM_MD5:
371 #ifdef	__sparcv9
372 		MD5Update((MD5_CTX *)session_p->digest.context,
373 		    /* LINTED */
374 		    pPart, (uint_t)ulPartLen);
375 #else	/* !__sparcv9 */
376 		MD5Update((MD5_CTX *)session_p->digest.context,
377 		    pPart, ulPartLen);
378 #endif	/* __sparcv9 */
379 		break;
380 
381 	case CKM_SHA_1:
382 #ifdef	__sparcv9
383 		SHA1Update((SHA1_CTX *)session_p->digest.context,
384 		    /* LINTED */
385 		    pPart, (uint32_t)ulPartLen);
386 #else	/* !__sparcv9 */
387 		SHA1Update((SHA1_CTX *)session_p->digest.context,
388 		    pPart, ulPartLen);
389 #endif	/* __sparcv9 */
390 		break;
391 
392 	case CKM_SHA256:
393 	case CKM_SHA384:
394 	case CKM_SHA512:
395 		SHA2Update((SHA2_CTX *)session_p->digest.context,
396 		    pPart, ulPartLen);
397 		break;
398 
399 	default:
400 		return (CKR_MECHANISM_INVALID);
401 	}
402 
403 	return (CKR_OK);
404 }
405 
406 
407 /*
408  * soft_digest_final()
409  *
410  * Arguments:
411  *      session_p:	pointer to soft_session_t struct
412  *      pDigest:	pointer to the output data after digesting
413  *      pulDigestLen:	length of the output data
414  *
415  * Description:
416  *      called by C_DigestFinal(). This function calls soft_digest_common().
417  *
418  * Returns:
419  *	see return values in soft_digest_common().
420  */
421 CK_RV
422 soft_digest_final(soft_session_t *session_p, CK_BYTE_PTR pDigest,
423 	CK_ULONG_PTR pulDigestLen)
424 {
425 
426 	return (soft_digest_common(session_p, NULL, 0,
427 	    pDigest, pulDigestLen));
428 }
429 
430 /*
431  * Perform digest init operation internally for the support of
432  * CKM_MD5_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA1_KEY_DERIVATION
433  * and CKM_MD5_KEY_DERIVATION mechanisms.
434  *
435  * This function is called with the session being held, and without
436  * its mutex taken.
437  */
438 CK_RV
439 soft_digest_init_internal(soft_session_t *session_p, CK_MECHANISM_PTR
440 	pMechanism)
441 {
442 
443 	CK_RV rv;
444 
445 	(void) pthread_mutex_lock(&session_p->session_mutex);
446 
447 	/* Check to see if digest operation is already active */
448 	if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
449 		(void) pthread_mutex_unlock(&session_p->session_mutex);
450 		return (CKR_OPERATION_ACTIVE);
451 	}
452 
453 	session_p->digest.flags = CRYPTO_OPERATION_ACTIVE;
454 
455 	(void) pthread_mutex_unlock(&session_p->session_mutex);
456 
457 	rv = soft_digest_init(session_p, pMechanism);
458 
459 	if (rv != CKR_OK) {
460 		(void) pthread_mutex_lock(&session_p->session_mutex);
461 		session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
462 		(void) pthread_mutex_unlock(&session_p->session_mutex);
463 	}
464 
465 	return (rv);
466 }
467 
468 /*
469  * Call soft_digest_update() function with the value of a secret key.
470  */
471 CK_RV
472 soft_digest_key(soft_session_t *session_p, soft_object_t *key_p)
473 {
474 
475 	CK_RV rv;
476 
477 	/* Only secret key is allowed to be digested */
478 	if (key_p->class != CKO_SECRET_KEY)
479 		return (CKR_KEY_INDIGESTIBLE);
480 
481 	if ((OBJ_SEC_VALUE(key_p) == NULL) ||
482 	    (OBJ_SEC_VALUE_LEN(key_p) == 0))
483 		return (CKR_KEY_SIZE_RANGE);
484 
485 	rv = soft_digest_update(session_p, OBJ_SEC_VALUE(key_p),
486 	    OBJ_SEC_VALUE_LEN(key_p));
487 
488 	return (rv);
489 
490 }
491