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