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, CK_MECHANISM_PTR
438 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 }