xref: /titanic_50/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDSA.c (revision be6e67355fa2266ba427189118d91a9e67b9163f)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <pthread.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <sys/types.h>
33 #include <security/cryptoki.h>
34 #include <bignum.h>
35 #include "softGlobal.h"
36 #include "softSession.h"
37 #include "softObject.h"
38 #include "softDSA.h"
39 #include "softRandom.h"
40 #include "softOps.h"
41 #include "softMAC.h"
42 #include "softCrypt.h"
43 
44 /*
45  * Allocate a DSA context for the active sign or verify operation.
46  * This function is called without the session lock held.
47  */
48 CK_RV
49 soft_dsa_sign_verify_init_common(soft_session_t *session_p,
50     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
51     boolean_t sign)
52 {
53 
54 	soft_dsa_ctx_t *dsa_ctx;
55 	CK_MECHANISM digest_mech;
56 	soft_object_t *tmp_key = NULL;
57 	CK_RV rv;
58 
59 	if (sign) {
60 		if ((key_p->class != CKO_PRIVATE_KEY) ||
61 		    (key_p->key_type != CKK_DSA))
62 			return (CKR_KEY_TYPE_INCONSISTENT);
63 	} else {
64 		if ((key_p->class != CKO_PUBLIC_KEY) ||
65 		    (key_p->key_type != CKK_DSA))
66 			return (CKR_KEY_TYPE_INCONSISTENT);
67 	}
68 
69 	if (pMechanism->mechanism == CKM_DSA_SHA1) {
70 		digest_mech.mechanism = CKM_SHA_1;
71 		rv = soft_digest_init_internal(session_p, &digest_mech);
72 		if (rv != CKR_OK)
73 			return (rv);
74 	}
75 
76 	dsa_ctx = malloc(sizeof (soft_dsa_ctx_t));
77 
78 	if (dsa_ctx == NULL) {
79 		return (CKR_HOST_MEMORY);
80 	}
81 
82 	/*
83 	 * Make a copy of the signature or verification key, and save it
84 	 * in the DSA crypto context since it will be used later for
85 	 * signing/verification. We don't want to hold any object reference
86 	 * on this original key while doing signing/verification.
87 	 */
88 	(void) pthread_mutex_lock(&key_p->object_mutex);
89 	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH,
90 	    NULL);
91 
92 	if ((rv != CKR_OK) || (tmp_key == NULL)) {
93 		/* Most likely we ran out of space. */
94 		(void) pthread_mutex_unlock(&key_p->object_mutex);
95 		free(dsa_ctx);
96 		return (rv);
97 	}
98 
99 	/* No need to hold the lock on the old object. */
100 	(void) pthread_mutex_unlock(&key_p->object_mutex);
101 	dsa_ctx->key = tmp_key;
102 
103 	(void) pthread_mutex_lock(&session_p->session_mutex);
104 
105 	if (sign) {
106 		session_p->sign.context = dsa_ctx;
107 		session_p->sign.mech.mechanism = pMechanism->mechanism;
108 	} else {
109 		session_p->verify.context = dsa_ctx;
110 		session_p->verify.mech.mechanism = pMechanism->mechanism;
111 	}
112 
113 	(void) pthread_mutex_unlock(&session_p->session_mutex);
114 
115 	return (CKR_OK);
116 }
117 
118 
119 /* size is in bits */
120 BIG_ERR_CODE
121 DSA_key_init(DSAkey *key, int size)
122 {
123 	BIG_ERR_CODE err;
124 	int len, len160;
125 
126 	len = BITLEN2BIGNUMLEN(size);
127 	len160 = BIG_CHUNKS_FOR_160BITS;
128 	key->size = size;
129 	if ((err = big_init1(&(key->q), len160, NULL, 0)) != BIG_OK)
130 		return (err);
131 	if ((err = big_init1(&(key->p), len, NULL, 0)) != BIG_OK)
132 		goto ret1;
133 	if ((err = big_init1(&(key->g), len, NULL, 0)) != BIG_OK)
134 		goto ret2;
135 	if ((err = big_init1(&(key->x), len160, NULL, 0)) != BIG_OK)
136 		goto ret3;
137 	if ((err = big_init1(&(key->y), len, NULL, 0)) != BIG_OK)
138 		goto ret4;
139 	if ((err = big_init1(&(key->k), len160, NULL, 0)) != BIG_OK)
140 		goto ret5;
141 	if ((err = big_init1(&(key->r), len160, NULL, 0)) != BIG_OK)
142 		goto ret6;
143 	if ((err = big_init1(&(key->s), len160, NULL, 0)) != BIG_OK)
144 		goto ret7;
145 	if ((err = big_init1(&(key->v), len160, NULL, 0)) != BIG_OK)
146 		goto ret8;
147 
148 	return (BIG_OK);
149 
150 ret8:
151 	big_finish(&(key->s));
152 ret7:
153 	big_finish(&(key->r));
154 ret6:
155 	big_finish(&(key->k));
156 ret5:
157 	big_finish(&(key->y));
158 ret4:
159 	big_finish(&(key->x));
160 ret3:
161 	big_finish(&(key->g));
162 ret2:
163 	big_finish(&(key->p));
164 ret1:
165 	big_finish(&(key->q));
166 	return (err);
167 }
168 
169 
170 void
171 DSA_key_finish(DSAkey *key)
172 {
173 	big_finish(&(key->v));
174 	big_finish(&(key->s));
175 	big_finish(&(key->r));
176 	big_finish(&(key->k));
177 	big_finish(&(key->y));
178 	big_finish(&(key->x));
179 	big_finish(&(key->g));
180 	big_finish(&(key->p));
181 	big_finish(&(key->q));
182 }
183 
184 
185 CK_RV
186 dsa_sign(soft_object_t *key, CK_BYTE_PTR in, CK_ULONG inlen, CK_BYTE_PTR out)
187 {
188 
189 	uchar_t q[MAX_KEY_ATTR_BUFLEN];
190 	uchar_t p[MAX_KEY_ATTR_BUFLEN];
191 	uchar_t g[MAX_KEY_ATTR_BUFLEN];
192 	uchar_t x[MAX_KEY_ATTR_BUFLEN];
193 	uint_t qlen = sizeof (q);
194 	uint_t plen = sizeof (p);
195 	uint_t glen = sizeof (g);
196 	uint_t xlen = sizeof (x);
197 	DSAkey dsakey;
198 	BIGNUM msg, tmp, tmp1, tmp2;
199 	BIG_ERR_CODE err;
200 	CK_RV rv;
201 
202 	rv = soft_get_private_value(key, CKA_SUBPRIME, q, &qlen);
203 	if (rv != CKR_OK) {
204 		goto clean1;
205 	}
206 
207 	if (20 != qlen) {
208 		rv = CKR_KEY_SIZE_RANGE;
209 		goto clean1;
210 	}
211 
212 	rv = soft_get_private_value(key, CKA_PRIME, p, &plen);
213 	if (rv != CKR_OK) {
214 		goto clean1;
215 	}
216 
217 	rv = soft_get_private_value(key, CKA_BASE, g, &glen);
218 	if (rv != CKR_OK) {
219 		goto clean1;
220 	}
221 
222 	if (glen != plen) {
223 		rv = CKR_KEY_SIZE_RANGE;
224 		goto clean1;
225 	}
226 
227 	rv = soft_get_private_value(key, CKA_VALUE, x, &xlen);
228 	if (rv != CKR_OK) {
229 		goto clean1;
230 	}
231 
232 	if (20 < xlen) {
233 		rv = CKR_KEY_SIZE_RANGE;
234 		goto clean1;
235 	}
236 
237 	if ((err = DSA_key_init(&dsakey, plen * 8)) != BIG_OK) {
238 		rv = CKR_HOST_MEMORY;
239 		goto clean1;
240 	}
241 
242 	if ((err = big_init(&msg, BIG_CHUNKS_FOR_160BITS)) != BIG_OK) {
243 		goto clean6;
244 	}
245 	if ((err = big_init(&tmp, CHARLEN2BIGNUMLEN(plen) +
246 	    2 * BIG_CHUNKS_FOR_160BITS + 1)) != BIG_OK) {
247 		goto clean7;
248 	}
249 	if ((err = big_init(&tmp1, 2 * BIG_CHUNKS_FOR_160BITS + 1)) != BIG_OK) {
250 		goto clean8;
251 	}
252 	if ((err = big_init(&tmp2, BIG_CHUNKS_FOR_160BITS)) != BIG_OK) {
253 		goto clean9;
254 	}
255 
256 	bytestring2bignum(&(dsakey.g), g, plen);
257 	bytestring2bignum(&(dsakey.x), x, 20);
258 	bytestring2bignum(&(dsakey.p), p, plen);
259 	bytestring2bignum(&(dsakey.q), q, 20);
260 	bytestring2bignum(&msg, (uchar_t *)in, inlen);
261 
262 	if ((err = random_bignum(&(dsakey.k), DSA_SUBPRIME_BITS,
263 	    B_FALSE)) != BIG_OK)
264 		goto clean10;
265 
266 	if ((err = big_div_pos(NULL, &(dsakey.k), &(dsakey.k),
267 	    &(dsakey.q))) != BIG_OK)
268 		goto clean10;
269 
270 	if ((err = big_modexp(&tmp, &(dsakey.g), &(dsakey.k), &(dsakey.p),
271 	    NULL)) != BIG_OK)
272 		goto clean10;
273 
274 	if ((err = big_div_pos(NULL, &(dsakey.r), &tmp, &(dsakey.q))) !=
275 	    BIG_OK)
276 		goto clean10;
277 
278 	if ((err = big_ext_gcd_pos(NULL, NULL, &tmp, &(dsakey.q),
279 	    &(dsakey.k))) != BIG_OK)
280 		goto clean10;
281 
282 	if (tmp.sign == -1)
283 		if ((err = big_add(&tmp, &tmp, &(dsakey.q))) != BIG_OK)
284 			goto clean10;			/* tmp <- k^-1 */
285 
286 	if ((err = big_mul(&tmp1, &(dsakey.x), &(dsakey.r))) != BIG_OK)
287 		goto clean10;
288 
289 	if ((err = big_add(&tmp1, &tmp1, &msg)) != BIG_OK)
290 		goto clean10;
291 
292 	if ((err = big_mul(&tmp, &tmp1, &tmp)) != BIG_OK)
293 		goto clean10;
294 
295 	if ((err = big_div_pos(NULL, &(dsakey.s), &tmp, &(dsakey.q))) !=
296 	    BIG_OK)
297 		goto clean10;
298 
299 	bignum2bytestring((uchar_t *)out, &(dsakey.r), 20);
300 	bignum2bytestring((uchar_t *)out + 20, &(dsakey.s), 20);
301 
302 	err = BIG_OK;
303 
304 clean10:
305 	big_finish(&tmp2);
306 clean9:
307 	big_finish(&tmp1);
308 clean8:
309 	big_finish(&tmp);
310 clean7:
311 	big_finish(&msg);
312 clean6:
313 	DSA_key_finish(&dsakey);
314 	if (err == BIG_OK)
315 		rv = CKR_OK;
316 	else if (err == BIG_NO_MEM)
317 		rv = CKR_HOST_MEMORY;
318 	else
319 		rv = CKR_FUNCTION_FAILED;
320 clean1:
321 	return (rv);
322 }
323 
324 CK_RV
325 dsa_verify(soft_object_t *key, CK_BYTE_PTR data, CK_BYTE_PTR sig)
326 {
327 
328 	uchar_t g[MAX_KEY_ATTR_BUFLEN];
329 	uchar_t y[MAX_KEY_ATTR_BUFLEN];
330 	uchar_t p[MAX_KEY_ATTR_BUFLEN];
331 	uchar_t q[MAX_KEY_ATTR_BUFLEN];
332 	uint_t glen = sizeof (g);
333 	uint_t ylen = sizeof (y);
334 	uint_t plen = sizeof (p);
335 	uint_t qlen = sizeof (q);
336 	DSAkey dsakey;
337 	BIGNUM msg, tmp1, tmp2, tmp3;
338 	CK_RV rv;
339 
340 	rv = soft_get_public_value(key, CKA_SUBPRIME, q, &qlen);
341 	if (rv != CKR_OK) {
342 		goto clean1;
343 	}
344 
345 	if (20 != qlen) {
346 		rv = CKR_KEY_SIZE_RANGE;
347 		goto clean1;
348 	}
349 
350 	rv = soft_get_public_value(key, CKA_PRIME, p, &plen);
351 	if (rv != CKR_OK) {
352 		goto clean1;
353 	}
354 
355 	rv = soft_get_public_value(key, CKA_BASE, g, &glen);
356 	if (rv != CKR_OK) {
357 		goto clean1;
358 	}
359 
360 	if (plen < glen) {
361 		rv = CKR_KEY_SIZE_RANGE;
362 		goto clean1;
363 	}
364 
365 	rv = soft_get_public_value(key, CKA_VALUE, y, &ylen);
366 	if (rv != CKR_OK) {
367 		goto clean1;
368 	}
369 
370 	if (plen < ylen) {
371 		rv = CKR_KEY_SIZE_RANGE;
372 		goto clean1;
373 	}
374 
375 	if (DSA_key_init(&dsakey, plen * 8) != BIG_OK) {
376 		rv = CKR_HOST_MEMORY;
377 		goto clean1;
378 	}
379 
380 	rv = CKR_HOST_MEMORY;
381 	if (big_init(&msg, BIG_CHUNKS_FOR_160BITS) != BIG_OK) {
382 		goto clean6;
383 	}
384 	if (big_init(&tmp1, 2 * CHARLEN2BIGNUMLEN(plen)) != BIG_OK) {
385 		goto clean7;
386 	}
387 	if (big_init(&tmp2, CHARLEN2BIGNUMLEN(plen)) != BIG_OK) {
388 		goto clean8;
389 	}
390 	if (big_init(&tmp3, 2 * BIG_CHUNKS_FOR_160BITS) != BIG_OK) {
391 		goto clean9;
392 	}
393 
394 	bytestring2bignum(&(dsakey.g), g, glen);
395 	bytestring2bignum(&(dsakey.y), y, ylen);
396 	bytestring2bignum(&(dsakey.p), p, plen);
397 	bytestring2bignum(&(dsakey.q), q, 20);
398 	bytestring2bignum(&(dsakey.r), (uchar_t *)sig, 20);
399 	bytestring2bignum(&(dsakey.s), ((uchar_t *)sig) + 20, 20);
400 	bytestring2bignum(&msg, (uchar_t *)data, 20);
401 
402 	if (big_ext_gcd_pos(NULL, &tmp2, NULL, &(dsakey.s), &(dsakey.q)) !=
403 	    BIG_OK)
404 		goto clean10;
405 
406 	if (tmp2.sign == -1)
407 		if (big_add(&tmp2, &tmp2, &(dsakey.q)) != BIG_OK)
408 			goto clean10;			/* tmp2 <- w */
409 
410 	if (big_mul(&tmp1, &msg, &tmp2) != BIG_OK)
411 		goto clean10;
412 
413 	if (big_div_pos(NULL, &tmp1, &tmp1, &(dsakey.q)) != BIG_OK)
414 		goto clean10;				/* tmp1 <- u_1 */
415 
416 	if (big_mul(&tmp2, &tmp2, &(dsakey.r)) != BIG_OK)
417 		goto clean10;
418 
419 	if (big_div_pos(NULL, &tmp2, &tmp2, &(dsakey.q)) != BIG_OK)
420 		goto clean10;				/* tmp2 <- u_2 */
421 
422 	if (big_modexp(&tmp1, &(dsakey.g), &tmp1, &(dsakey.p), NULL) != BIG_OK)
423 		goto clean10;
424 
425 	if (big_modexp(&tmp2, &(dsakey.y), &tmp2, &(dsakey.p), NULL) != BIG_OK)
426 		goto clean10;
427 
428 	if (big_mul(&tmp1, &tmp1, &tmp2) != BIG_OK)
429 		goto clean10;
430 
431 	if (big_div_pos(NULL, &tmp1, &tmp1, &(dsakey.p)) != BIG_OK)
432 		goto clean10;
433 
434 	if (big_div_pos(NULL, &tmp1, &tmp1, &(dsakey.q)) != BIG_OK)
435 		goto clean10;
436 
437 	if (big_cmp_abs(&tmp1, &(dsakey.r)) == 0)
438 		rv = CKR_OK;
439 	else
440 		rv = CKR_SIGNATURE_INVALID;
441 
442 clean10:
443 	big_finish(&tmp3);
444 clean9:
445 	big_finish(&tmp2);
446 clean8:
447 	big_finish(&tmp1);
448 clean7:
449 	big_finish(&msg);
450 clean6:
451 	DSA_key_finish(&dsakey);
452 clean1:
453 	return (rv);
454 }
455 
456 
457 CK_RV
458 soft_dsa_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
459     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
460     CK_ULONG_PTR pulSignedLen, boolean_t Final)
461 {
462 
463 	CK_RV rv = CKR_OK;
464 	CK_BYTE hash[SHA1_HASH_SIZE];  /* space enough for SHA1 and MD5 */
465 	CK_ULONG hash_len = SHA1_HASH_SIZE;
466 	soft_dsa_ctx_t *dsa_ctx = session_p->sign.context;
467 	soft_object_t *key = dsa_ctx->key;
468 
469 	/* Check arguments before performing message digest. */
470 	if (pSigned == NULL) {
471 		/* Application asks for the length of the output buffer. */
472 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
473 		goto clean1;
474 	}
475 
476 	/* Is the application-supplied buffer large enough? */
477 	if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
478 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
479 		rv = CKR_BUFFER_TOO_SMALL;
480 		goto clean1;
481 	}
482 
483 	if (Final) {
484 		rv = soft_digest_final(session_p, hash, &hash_len);
485 	} else {
486 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
487 	}
488 
489 	if (rv != CKR_OK) {
490 		/* free the signature key */
491 		soft_cleanup_object(key);
492 		free(key);
493 		goto clean_exit;
494 	}
495 
496 	/*
497 	 * Now, we are ready to sign the data
498 	 * soft_dsa_sign() will free the signature key.
499 	 */
500 	rv = soft_dsa_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
501 
502 clean_exit:
503 	(void) pthread_mutex_lock(&session_p->session_mutex);
504 	/* soft_digest_common() has freed the digest context */
505 	session_p->digest.flags = 0;
506 	(void) pthread_mutex_unlock(&session_p->session_mutex);
507 
508 clean1:
509 	return (rv);
510 }
511 
512 
513 CK_RV
514 soft_dsa_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
515     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
516     CK_ULONG_PTR pulSignedLen)
517 {
518 
519 	CK_RV rv = CKR_OK;
520 	soft_dsa_ctx_t *dsa_ctx = session_p->sign.context;
521 	soft_object_t *key = dsa_ctx->key;
522 
523 	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_DSA)) {
524 		rv = CKR_KEY_TYPE_INCONSISTENT;
525 		goto clean_exit;
526 	}
527 
528 	/* Output length is always 40 bytes. */
529 	if (pSigned == NULL) {
530 		/* Application asks for the length of the output buffer. */
531 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
532 		return (CKR_OK);
533 	}
534 
535 	/* Input data length needs to be 20 bytes. */
536 	if (ulDataLen != 20) {
537 		rv = CKR_DATA_LEN_RANGE;
538 		goto clean_exit;
539 	}
540 
541 	if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
542 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
543 		return (CKR_BUFFER_TOO_SMALL);
544 	}
545 
546 	rv = dsa_sign(key, pData, ulDataLen, pSigned);
547 	if (rv == CKR_OK) {
548 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
549 	}
550 
551 clean_exit:
552 	(void) pthread_mutex_lock(&session_p->session_mutex);
553 	free(session_p->sign.context);
554 	session_p->sign.context = NULL;
555 	(void) pthread_mutex_unlock(&session_p->session_mutex);
556 	soft_cleanup_object(key);
557 	free(key);
558 	return (rv);
559 }
560 
561 
562 CK_RV
563 soft_dsa_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
564     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
565     CK_ULONG ulSignatureLen)
566 {
567 
568 	CK_RV rv = CKR_OK;
569 	soft_dsa_ctx_t *dsa_ctx = session_p->verify.context;
570 	soft_object_t *key = dsa_ctx->key;
571 
572 	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_DSA)) {
573 		rv = CKR_KEY_TYPE_INCONSISTENT;
574 		goto clean_exit;
575 	}
576 
577 	/* The signature length is always 40 bytes. */
578 	if (ulSignatureLen != DSA_SIGNATURE_LENGTH) {
579 		rv = CKR_SIGNATURE_LEN_RANGE;
580 		goto clean_exit;
581 	}
582 
583 	/* Input data length needs to be 20 bytes. */
584 	if (ulDataLen != 20) {
585 		rv = CKR_DATA_LEN_RANGE;
586 		goto clean_exit;
587 	}
588 
589 	rv = dsa_verify(key, pData, pSignature);
590 
591 clean_exit:
592 	(void) pthread_mutex_lock(&session_p->session_mutex);
593 	free(session_p->verify.context);
594 	session_p->verify.context = NULL;
595 	(void) pthread_mutex_unlock(&session_p->session_mutex);
596 	soft_cleanup_object(key);
597 	free(key);
598 	return (rv);
599 }
600 
601 
602 CK_RV
603 soft_dsa_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
604     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
605     CK_ULONG ulSignedLen, boolean_t Final)
606 {
607 
608 	CK_RV rv;
609 	CK_BYTE hash[SHA1_HASH_SIZE];  /* space enough for SHA1 and MD5 */
610 	CK_ULONG hash_len = SHA1_HASH_SIZE;
611 	soft_dsa_ctx_t *dsa_ctx = session_p->verify.context;
612 	soft_object_t *key = dsa_ctx->key;
613 
614 	if (Final) {
615 		rv = soft_digest_final(session_p, hash, &hash_len);
616 	} else {
617 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
618 	}
619 
620 	if (rv != CKR_OK) {
621 		/* free the verification key */
622 		soft_cleanup_object(key);
623 		free(key);
624 		goto clean_exit;
625 	}
626 
627 	/*
628 	 * Now, we are ready to verify the data using signature.
629 	 * soft_dsa_verify() will free the verification key.
630 	 */
631 	rv = soft_dsa_verify(session_p, hash, hash_len,
632 	    pSigned, ulSignedLen);
633 
634 clean_exit:
635 	(void) pthread_mutex_lock(&session_p->session_mutex);
636 	/* soft_digest_common() has freed the digest context */
637 	session_p->digest.flags = 0;
638 	(void) pthread_mutex_unlock(&session_p->session_mutex);
639 	return (rv);
640 }
641 
642 
643 CK_RV
644 soft_genDSAkey_set_attribute(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
645     uchar_t *value, uint32_t value_len, boolean_t public)
646 {
647 
648 	CK_RV rv = CKR_OK;
649 	biginteger_t *dst = NULL;
650 	biginteger_t src;
651 
652 
653 	switch (type) {
654 
655 	case CKA_VALUE:
656 		if (public)
657 			dst = OBJ_PUB_DSA_VALUE(key);
658 		else
659 			dst = OBJ_PRI_DSA_VALUE(key);
660 		break;
661 
662 	case CKA_PRIME:
663 		if (public)
664 			dst = OBJ_PUB_DSA_PRIME(key);
665 		else
666 			dst = OBJ_PRI_DSA_PRIME(key);
667 		break;
668 
669 	case CKA_SUBPRIME:
670 		if (public)
671 			dst = OBJ_PUB_DSA_SUBPRIME(key);
672 		else
673 			dst = OBJ_PRI_DSA_SUBPRIME(key);
674 		break;
675 
676 	case CKA_BASE:
677 		if (public)
678 			dst = OBJ_PUB_DSA_BASE(key);
679 		else
680 			dst = OBJ_PRI_DSA_BASE(key);
681 		break;
682 	}
683 
684 	src.big_value_len = value_len;
685 
686 	if ((src.big_value = malloc(value_len)) == NULL) {
687 		rv = CKR_HOST_MEMORY;
688 		goto cleanexit;
689 	}
690 	(void) memcpy(src.big_value, value, value_len);
691 
692 	/* Copy the attribute in the key object. */
693 	copy_bigint_attr(&src, dst);
694 
695 cleanexit:
696 	/* No need to free big_value because dst holds it now after copy. */
697 	return (rv);
698 
699 }
700 
701 
702 CK_RV
703 generate_dsa_key(DSAkey *key, boolean_t token_obj)
704 {
705 	BIG_ERR_CODE err;
706 
707 	do {
708 		if ((err = random_bignum(&(key->x), DSA_SUBPRIME_BITS,
709 		    token_obj)) != BIG_OK) {
710 			return (convert_rv(err));
711 		}
712 	} while (big_cmp_abs(&(key->x), &(key->q)) > 0);
713 
714 	if ((err = big_modexp(&(key->y), &(key->g), (&key->x),
715 	    (&key->p), NULL)) != BIG_OK)
716 		return (convert_rv(err));
717 
718 	return (CKR_OK);
719 }
720 
721 
722 CK_RV
723 soft_dsa_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
724 {
725 	BIG_ERR_CODE brv;
726 	CK_RV rv;
727 	uchar_t	prime[MAX_KEY_ATTR_BUFLEN];
728 	uint32_t prime_len = sizeof (prime);
729 	uchar_t	subprime[MAX_KEY_ATTR_BUFLEN];
730 	uint32_t subprime_len = sizeof (subprime);
731 	uchar_t	base[MAX_KEY_ATTR_BUFLEN];
732 	uint32_t base_len = sizeof (base);
733 	uchar_t	*pubvalue;
734 	uint32_t pubvalue_len;
735 	uchar_t	*privalue;
736 	uint32_t privalue_len;
737 	DSAkey	dsakey = {0};
738 
739 	pubvalue = NULL;
740 	privalue = NULL;
741 
742 	if ((pubkey == NULL) || (prikey == NULL)) {
743 		return (CKR_ARGUMENTS_BAD);
744 	}
745 
746 	/* lookup prime, subprime and base */
747 	rv = soft_get_public_value(pubkey, CKA_PRIME, prime, &prime_len);
748 	if (rv != CKR_OK) {
749 		rv = CKR_TEMPLATE_INCOMPLETE;
750 		goto cleanexit;
751 	}
752 
753 	if ((prime_len < MIN_DSA_KEY_LEN) ||
754 	    (prime_len > MAX_DSA_KEY_LEN)) {
755 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
756 		goto cleanexit;
757 	}
758 
759 	rv = soft_get_public_value(pubkey, CKA_SUBPRIME, subprime,
760 	    &subprime_len);
761 	if (rv != CKR_OK) {
762 		rv = CKR_TEMPLATE_INCOMPLETE;
763 		goto cleanexit;
764 	}
765 
766 	if (subprime_len != DSA_SUBPRIME_BYTES) {
767 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
768 		goto cleanexit;
769 	}
770 
771 	rv = soft_get_public_value(pubkey, CKA_BASE, base, &base_len);
772 	if (rv != CKR_OK) {
773 		rv = CKR_TEMPLATE_INCOMPLETE;
774 		goto cleanexit;
775 	}
776 
777 	/*
778 	 * initialize the dsa key
779 	 * Note: big_extend takes length in words
780 	 */
781 	if ((brv = DSA_key_init(&dsakey, prime_len * 8)) != BIG_OK) {
782 		rv = convert_rv(brv);
783 		goto cleanexit;
784 	}
785 
786 	if ((brv = big_extend(&dsakey.p,
787 	    CHARLEN2BIGNUMLEN(prime_len))) != BIG_OK) {
788 		rv = convert_rv(brv);
789 		goto cleanexit;
790 	}
791 
792 	bytestring2bignum(&dsakey.p, prime, prime_len);
793 
794 	if ((brv = big_extend(&dsakey.q, CHARLEN2BIGNUMLEN(subprime_len))) !=
795 	    BIG_OK) {
796 		rv = convert_rv(brv);
797 		goto cleanexit;
798 	}
799 
800 	bytestring2bignum(&dsakey.q, subprime, subprime_len);
801 
802 	if ((brv = big_extend(&dsakey.g, CHARLEN2BIGNUMLEN(base_len))) !=
803 	    BIG_OK) {
804 		rv = convert_rv(brv);
805 		goto cleanexit;
806 	}
807 
808 	bytestring2bignum(&dsakey.g, base, base_len);
809 
810 	/*
811 	 * generate DSA key pair
812 	 * Note: bignum.len is length of value in words
813 	 */
814 	if ((rv = generate_dsa_key(&dsakey, (IS_TOKEN_OBJECT(pubkey) ||
815 	    IS_TOKEN_OBJECT(prikey)))) != CKR_OK) {
816 		goto cleanexit;
817 	}
818 
819 	pubvalue_len = prime_len;
820 	if ((pubvalue = malloc(pubvalue_len)) == NULL) {
821 		rv = CKR_HOST_MEMORY;
822 		goto cleanexit;
823 	}
824 	bignum2bytestring(pubvalue, &dsakey.y, pubvalue_len);
825 
826 	privalue_len = DSA_SUBPRIME_BYTES;
827 	if ((privalue = malloc(privalue_len)) == NULL) {
828 		rv = CKR_HOST_MEMORY;
829 		goto cleanexit;
830 	}
831 	bignum2bytestring(privalue, &dsakey.x, privalue_len);
832 
833 	/* Update attribute in public key. */
834 	if ((rv = soft_genDSAkey_set_attribute(pubkey, CKA_VALUE,
835 	    pubvalue, pubvalue_len, B_TRUE)) != CKR_OK) {
836 		goto cleanexit;
837 	}
838 	/* Update attributes in private key. */
839 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_PRIME,
840 	    prime, prime_len, B_FALSE)) != CKR_OK) {
841 		goto cleanexit;
842 	}
843 
844 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_SUBPRIME,
845 	    subprime, subprime_len, B_FALSE)) != CKR_OK) {
846 		goto cleanexit;
847 	}
848 
849 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_BASE,
850 	    base, base_len, B_FALSE)) != CKR_OK) {
851 		goto cleanexit;
852 	}
853 
854 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_VALUE,
855 	    privalue, privalue_len, B_FALSE)) != CKR_OK) {
856 		goto cleanexit;
857 	}
858 
859 cleanexit:
860 	DSA_key_finish(&dsakey);
861 
862 	if (pubvalue != NULL) {
863 		free(pubvalue);
864 	}
865 
866 	if (privalue != NULL) {
867 		free(privalue);
868 	}
869 
870 	return (rv);
871 }
872