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