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
soft_digest_init(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism)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 case CKM_SHA512_224:
106 case CKM_SHA512_256:
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 session_p->digest.mech.mechanism = pMechanism->mechanism;
118 (void) pthread_mutex_unlock(&session_p->session_mutex);
119
120 switch (pMechanism->mechanism) {
121 case CKM_SHA256:
122 SHA2Init(SHA256,
123 (SHA2_CTX *)session_p->digest.context);
124 break;
125
126 case CKM_SHA384:
127 SHA2Init(SHA384,
128 (SHA2_CTX *)session_p->digest.context);
129 break;
130
131 case CKM_SHA512:
132 SHA2Init(SHA512,
133 (SHA2_CTX *)session_p->digest.context);
134 break;
135 case CKM_SHA512_224:
136 SHA2Init(SHA512_224,
137 (SHA2_CTX *)session_p->digest.context);
138 break;
139 case CKM_SHA512_256:
140 SHA2Init(SHA512_256,
141 (SHA2_CTX *)session_p->digest.context);
142 break;
143 }
144 break;
145
146 default:
147 return (CKR_MECHANISM_INVALID);
148 }
149
150 return (CKR_OK);
151 }
152
153
154 /*
155 * soft_digest_common()
156 *
157 * Arguments:
158 * session_p: pointer to soft_session_t struct
159 * pData: pointer to the input data to be digested
160 * ulDataLen: length of the input data
161 * pDigest: pointer to the output data after digesting
162 * pulDigestLen: length of the output data
163 *
164 * Description:
165 * called by soft_digest() or soft_digest_final(). This function
166 * determines the length of output buffer and calls the corresponding
167 * software provided digest routine based on the mechanism.
168 *
169 * Returns:
170 * CKR_OK: success
171 * CKR_MECHANISM_INVALID: invalid mechanism type
172 * CKR_BUFFER_TOO_SMALL: the output buffer provided by application
173 * is too small
174 */
175 CK_RV
soft_digest_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)176 soft_digest_common(soft_session_t *session_p, CK_BYTE_PTR pData,
177 CK_ULONG ulDataLen, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
178 {
179
180 CK_ULONG digestLen = 0;
181 size_t len = 0;
182
183 /*
184 * Determine the output data length based on the mechanism
185 */
186 switch (session_p->digest.mech.mechanism) {
187
188 case CKM_MD5:
189 digestLen = 16;
190 break;
191
192 case CKM_SHA_1:
193 digestLen = SHA1_DIGEST_LENGTH;
194 break;
195
196 case CKM_SHA256:
197 digestLen = SHA256_DIGEST_LENGTH;
198 break;
199
200 case CKM_SHA384:
201 digestLen = SHA384_DIGEST_LENGTH;
202 break;
203
204 case CKM_SHA512:
205 digestLen = SHA512_DIGEST_LENGTH;
206 break;
207
208 case CKM_SHA512_224:
209 digestLen = SHA512_224_DIGEST_LENGTH;
210 break;
211
212 case CKM_SHA512_256:
213 digestLen = SHA512_256_DIGEST_LENGTH;
214 break;
215
216 default:
217 return (CKR_MECHANISM_INVALID);
218 }
219
220 if (pDigest == NULL) {
221 /*
222 * Application only wants to know the length of the
223 * buffer needed to hold the message digest.
224 */
225 *pulDigestLen = digestLen;
226 return (CKR_OK);
227 }
228
229 if (*pulDigestLen < digestLen) {
230 /*
231 * Application provides buffer too small to hold the
232 * digest message. Return the length of buffer needed
233 * to the application.
234 */
235 *pulDigestLen = digestLen;
236 return (CKR_BUFFER_TOO_SMALL);
237 }
238
239 /*
240 * Call the corresponding system provided software digest routine.
241 * If the soft_digest_common() is called by soft_digest_final()
242 * the pData is NULL, and the ulDataLen is zero.
243 */
244 switch (session_p->digest.mech.mechanism) {
245
246 case CKM_MD5:
247 if (pData != NULL) {
248 /*
249 * this is called by soft_digest()
250 */
251 #ifdef __sparcv9
252 MD5Update((MD5_CTX *)session_p->digest.context,
253 /* LINTED */
254 pData, (uint_t)ulDataLen);
255 #else /* !__sparcv9 */
256 MD5Update((MD5_CTX *)session_p->digest.context,
257 pData, ulDataLen);
258 #endif /* __sparcv9 */
259 MD5Final(pDigest, (MD5_CTX *)session_p->digest.context);
260 } else {
261 /*
262 * this is called by soft_digest_final()
263 */
264 MD5Final(pDigest, (MD5_CTX *)session_p->digest.context);
265 len = sizeof (MD5_CTX);
266 }
267 break;
268
269 case CKM_SHA_1:
270 if (pData != NULL) {
271 /*
272 * this is called by soft_digest()
273 */
274
275 #ifdef __sparcv9
276 SHA1Update((SHA1_CTX *)session_p->digest.context,
277 /* LINTED */
278 pData, (uint32_t)ulDataLen);
279 #else /* !__sparcv9 */
280 SHA1Update((SHA1_CTX *)session_p->digest.context,
281 pData, ulDataLen);
282 #endif /* __sparcv9 */
283 SHA1Final(pDigest,
284 (SHA1_CTX *)session_p->digest.context);
285 } else {
286 /*
287 * this is called by soft_digest_final()
288 */
289 SHA1Final(pDigest,
290 (SHA1_CTX *)session_p->digest.context);
291 len = sizeof (SHA1_CTX);
292 }
293 break;
294 case CKM_SHA256:
295 case CKM_SHA384:
296 case CKM_SHA512:
297 case CKM_SHA512_224:
298 case CKM_SHA512_256:
299 if (pData != NULL) {
300 /*
301 * this is called by soft_digest()
302 */
303
304 SHA2Update((SHA2_CTX *)session_p->digest.context,
305 pData, ulDataLen);
306
307 SHA2Final(pDigest,
308 (SHA2_CTX *)session_p->digest.context);
309 } else {
310 /*
311 * this is called by soft_digest_final()
312 */
313 SHA2Final(pDigest,
314 (SHA2_CTX *)session_p->digest.context);
315 len = sizeof (SHA2_CTX);
316 }
317
318 break;
319 }
320
321 /* Paranoia on behalf of C_DigestKey callers: bzero the context */
322 if (session_p->digest.flags & CRYPTO_KEY_DIGESTED) {
323 explicit_bzero(session_p->digest.context, len);
324 session_p->digest.flags &= ~CRYPTO_KEY_DIGESTED;
325 }
326 *pulDigestLen = digestLen;
327 (void) pthread_mutex_lock(&session_p->session_mutex);
328 free(session_p->digest.context);
329 session_p->digest.context = NULL;
330 (void) pthread_mutex_unlock(&session_p->session_mutex);
331
332 return (CKR_OK);
333 }
334
335
336 /*
337 * soft_digest()
338 *
339 * Arguments:
340 * session_p: pointer to soft_session_t struct
341 * pData: pointer to the input data to be digested
342 * ulDataLen: length of the input data
343 * pDigest: pointer to the output data after digesting
344 * pulDigestLen: length of the output data
345 *
346 * Description:
347 * called by C_Digest(). This function calls soft_digest_common().
348 *
349 * Returns:
350 * see return values in soft_digest_common().
351 */
352 CK_RV
soft_digest(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)353 soft_digest(soft_session_t *session_p, CK_BYTE_PTR pData, CK_ULONG ulDataLen,
354 CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen)
355 {
356
357 return (soft_digest_common(session_p, pData, ulDataLen,
358 pDigest, pulDigestLen));
359 }
360
361
362 /*
363 * soft_digest_update()
364 *
365 * Arguments:
366 * session_p: pointer to soft_session_t struct
367 * pPart: pointer to the input data to be digested
368 * ulPartLen: length of the input data
369 *
370 * Description:
371 * called by C_DigestUpdate(). This function calls the corresponding
372 * software provided digest update routine based on the mechanism.
373 *
374 * Returns:
375 * CKR_OK: success
376 * CKR_MECHANISM_INVALID: invalid MECHANISM type.
377 */
378 CK_RV
soft_digest_update(soft_session_t * session_p,CK_BYTE_PTR pPart,CK_ULONG ulPartLen)379 soft_digest_update(soft_session_t *session_p, CK_BYTE_PTR pPart,
380 CK_ULONG ulPartLen)
381 {
382
383 switch (session_p->digest.mech.mechanism) {
384
385 case CKM_MD5:
386 #ifdef __sparcv9
387 MD5Update((MD5_CTX *)session_p->digest.context,
388 /* LINTED */
389 pPart, (uint_t)ulPartLen);
390 #else /* !__sparcv9 */
391 MD5Update((MD5_CTX *)session_p->digest.context,
392 pPart, ulPartLen);
393 #endif /* __sparcv9 */
394 break;
395
396 case CKM_SHA_1:
397 #ifdef __sparcv9
398 SHA1Update((SHA1_CTX *)session_p->digest.context,
399 /* LINTED */
400 pPart, (uint32_t)ulPartLen);
401 #else /* !__sparcv9 */
402 SHA1Update((SHA1_CTX *)session_p->digest.context,
403 pPart, ulPartLen);
404 #endif /* __sparcv9 */
405 break;
406
407 case CKM_SHA256:
408 case CKM_SHA384:
409 case CKM_SHA512:
410 case CKM_SHA512_224:
411 case CKM_SHA512_256:
412 SHA2Update((SHA2_CTX *)session_p->digest.context,
413 pPart, ulPartLen);
414 break;
415
416 default:
417 return (CKR_MECHANISM_INVALID);
418 }
419
420 return (CKR_OK);
421 }
422
423
424 /*
425 * soft_digest_final()
426 *
427 * Arguments:
428 * session_p: pointer to soft_session_t struct
429 * pDigest: pointer to the output data after digesting
430 * pulDigestLen: length of the output data
431 *
432 * Description:
433 * called by C_DigestFinal(). This function calls soft_digest_common().
434 *
435 * Returns:
436 * see return values in soft_digest_common().
437 */
438 CK_RV
soft_digest_final(soft_session_t * session_p,CK_BYTE_PTR pDigest,CK_ULONG_PTR pulDigestLen)439 soft_digest_final(soft_session_t *session_p, CK_BYTE_PTR pDigest,
440 CK_ULONG_PTR pulDigestLen)
441 {
442
443 return (soft_digest_common(session_p, NULL, 0,
444 pDigest, pulDigestLen));
445 }
446
447 /*
448 * Perform digest init operation internally for the support of
449 * CKM_MD5_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA1_KEY_DERIVATION
450 * and CKM_MD5_KEY_DERIVATION mechanisms.
451 *
452 * This function is called with the session being held, and without
453 * its mutex taken.
454 */
455 CK_RV
soft_digest_init_internal(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism)456 soft_digest_init_internal(soft_session_t *session_p,
457 CK_MECHANISM_PTR pMechanism)
458 {
459
460 CK_RV rv;
461
462 (void) pthread_mutex_lock(&session_p->session_mutex);
463
464 /* Check to see if digest operation is already active */
465 if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
466 (void) pthread_mutex_unlock(&session_p->session_mutex);
467 return (CKR_OPERATION_ACTIVE);
468 }
469
470 session_p->digest.flags = CRYPTO_OPERATION_ACTIVE;
471
472 (void) pthread_mutex_unlock(&session_p->session_mutex);
473
474 rv = soft_digest_init(session_p, pMechanism);
475
476 if (rv != CKR_OK) {
477 (void) pthread_mutex_lock(&session_p->session_mutex);
478 session_p->digest.flags &= ~CRYPTO_OPERATION_ACTIVE;
479 (void) pthread_mutex_unlock(&session_p->session_mutex);
480 }
481
482 return (rv);
483 }
484
485 /*
486 * Call soft_digest_update() function with the value of a secret key.
487 */
488 CK_RV
soft_digest_key(soft_session_t * session_p,soft_object_t * key_p)489 soft_digest_key(soft_session_t *session_p, soft_object_t *key_p)
490 {
491
492 CK_RV rv;
493
494 /* Only secret key is allowed to be digested */
495 if (key_p->class != CKO_SECRET_KEY)
496 return (CKR_KEY_INDIGESTIBLE);
497
498 if ((OBJ_SEC_VALUE(key_p) == NULL) ||
499 (OBJ_SEC_VALUE_LEN(key_p) == 0))
500 return (CKR_KEY_SIZE_RANGE);
501
502 rv = soft_digest_update(session_p, OBJ_SEC_VALUE(key_p),
503 OBJ_SEC_VALUE_LEN(key_p));
504
505 return (rv);
506
507 }
508
509 /*
510 * This function releases allocated digest context. The caller
511 * may (lock_held == B_TRUE) or may not (lock_held == B_FALSE)
512 * hold a session mutex.
513 */
514 void
soft_digest_cleanup(soft_session_t * session_p,boolean_t lock_held)515 soft_digest_cleanup(soft_session_t *session_p, boolean_t lock_held)
516 {
517 boolean_t lock_true = B_TRUE;
518
519 if (!lock_held)
520 (void) pthread_mutex_lock(&session_p->session_mutex);
521
522 if (session_p->digest.context != NULL) {
523 free(session_p->digest.context);
524 session_p->digest.context = NULL;
525 }
526
527 session_p->digest.flags = 0;
528
529 if (!lock_held)
530 SES_REFRELE(session_p, lock_true);
531
532 }
533