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