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