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