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