xref: /titanic_51/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDSA.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
560c58272Smarkfen  * Common Development and Distribution License (the "License").
660c58272Smarkfen  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*726fad2aSDina K Nimeh 
227c478bd9Sstevel@tonic-gate /*
23*726fad2aSDina K Nimeh  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <pthread.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <strings.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <security/cryptoki.h>
32*726fad2aSDina K Nimeh #include <cryptoutil.h>
337c478bd9Sstevel@tonic-gate #include "softGlobal.h"
347c478bd9Sstevel@tonic-gate #include "softSession.h"
357c478bd9Sstevel@tonic-gate #include "softObject.h"
367c478bd9Sstevel@tonic-gate #include "softDSA.h"
377c478bd9Sstevel@tonic-gate #include "softOps.h"
387c478bd9Sstevel@tonic-gate #include "softMAC.h"
397c478bd9Sstevel@tonic-gate #include "softCrypt.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * Allocate a DSA context for the active sign or verify operation.
437c478bd9Sstevel@tonic-gate  * This function is called without the session lock held.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate CK_RV
467c478bd9Sstevel@tonic-gate soft_dsa_sign_verify_init_common(soft_session_t *session_p,
477c478bd9Sstevel@tonic-gate     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
487c478bd9Sstevel@tonic-gate     boolean_t sign)
497c478bd9Sstevel@tonic-gate {
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate 	soft_dsa_ctx_t *dsa_ctx;
527c478bd9Sstevel@tonic-gate 	CK_MECHANISM digest_mech;
537c478bd9Sstevel@tonic-gate 	soft_object_t *tmp_key = NULL;
547c478bd9Sstevel@tonic-gate 	CK_RV rv;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 	if (sign) {
577c478bd9Sstevel@tonic-gate 		if ((key_p->class != CKO_PRIVATE_KEY) ||
587c478bd9Sstevel@tonic-gate 		    (key_p->key_type != CKK_DSA))
597c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
607c478bd9Sstevel@tonic-gate 	} else {
617c478bd9Sstevel@tonic-gate 		if ((key_p->class != CKO_PUBLIC_KEY) ||
627c478bd9Sstevel@tonic-gate 		    (key_p->key_type != CKK_DSA))
637c478bd9Sstevel@tonic-gate 			return (CKR_KEY_TYPE_INCONSISTENT);
647c478bd9Sstevel@tonic-gate 	}
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	if (pMechanism->mechanism == CKM_DSA_SHA1) {
677c478bd9Sstevel@tonic-gate 		digest_mech.mechanism = CKM_SHA_1;
687c478bd9Sstevel@tonic-gate 		rv = soft_digest_init_internal(session_p, &digest_mech);
697c478bd9Sstevel@tonic-gate 		if (rv != CKR_OK)
707c478bd9Sstevel@tonic-gate 			return (rv);
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	dsa_ctx = malloc(sizeof (soft_dsa_ctx_t));
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	if (dsa_ctx == NULL) {
767c478bd9Sstevel@tonic-gate 		return (CKR_HOST_MEMORY);
777c478bd9Sstevel@tonic-gate 	}
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/*
807c478bd9Sstevel@tonic-gate 	 * Make a copy of the signature or verification key, and save it
817c478bd9Sstevel@tonic-gate 	 * in the DSA crypto context since it will be used later for
827c478bd9Sstevel@tonic-gate 	 * signing/verification. We don't want to hold any object reference
837c478bd9Sstevel@tonic-gate 	 * on this original key while doing signing/verification.
847c478bd9Sstevel@tonic-gate 	 */
857c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&key_p->object_mutex);
867c478bd9Sstevel@tonic-gate 	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH,
877c478bd9Sstevel@tonic-gate 	    NULL);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if ((rv != CKR_OK) || (tmp_key == NULL)) {
907c478bd9Sstevel@tonic-gate 		/* Most likely we ran out of space. */
917c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&key_p->object_mutex);
927c478bd9Sstevel@tonic-gate 		free(dsa_ctx);
937c478bd9Sstevel@tonic-gate 		return (rv);
947c478bd9Sstevel@tonic-gate 	}
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	/* No need to hold the lock on the old object. */
977c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&key_p->object_mutex);
987c478bd9Sstevel@tonic-gate 	dsa_ctx->key = tmp_key;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	if (sign) {
1037c478bd9Sstevel@tonic-gate 		session_p->sign.context = dsa_ctx;
1047c478bd9Sstevel@tonic-gate 		session_p->sign.mech.mechanism = pMechanism->mechanism;
1057c478bd9Sstevel@tonic-gate 	} else {
1067c478bd9Sstevel@tonic-gate 		session_p->verify.context = dsa_ctx;
1077c478bd9Sstevel@tonic-gate 		session_p->verify.mech.mechanism = pMechanism->mechanism;
1087c478bd9Sstevel@tonic-gate 	}
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	return (CKR_OK);
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
115b60f2a0bSfr41279 
116*726fad2aSDina K Nimeh static CK_RV
117*726fad2aSDina K Nimeh local_dsa_sign(soft_object_t *key, CK_BYTE_PTR in, CK_ULONG inlen,
118*726fad2aSDina K Nimeh     CK_BYTE_PTR out)
1197c478bd9Sstevel@tonic-gate {
120*726fad2aSDina K Nimeh 	CK_RV rv;
1217c478bd9Sstevel@tonic-gate 	uchar_t q[MAX_KEY_ATTR_BUFLEN];
1227c478bd9Sstevel@tonic-gate 	uchar_t p[MAX_KEY_ATTR_BUFLEN];
1237c478bd9Sstevel@tonic-gate 	uchar_t g[MAX_KEY_ATTR_BUFLEN];
1247c478bd9Sstevel@tonic-gate 	uchar_t x[MAX_KEY_ATTR_BUFLEN];
1257c478bd9Sstevel@tonic-gate 	uint_t qlen = sizeof (q);
1267c478bd9Sstevel@tonic-gate 	uint_t plen = sizeof (p);
1277c478bd9Sstevel@tonic-gate 	uint_t glen = sizeof (g);
1287c478bd9Sstevel@tonic-gate 	uint_t xlen = sizeof (x);
129*726fad2aSDina K Nimeh 	DSAbytekey k;
1307c478bd9Sstevel@tonic-gate 
131*726fad2aSDina K Nimeh 	rv = soft_get_private_value(key, CKA_PRIME, p, &plen);
1327c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1337c478bd9Sstevel@tonic-gate 		goto clean1;
1347c478bd9Sstevel@tonic-gate 	}
1357c478bd9Sstevel@tonic-gate 
136*726fad2aSDina K Nimeh 	rv = soft_get_private_value(key, CKA_SUBPRIME, q, &qlen);
1377c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1387c478bd9Sstevel@tonic-gate 		goto clean1;
1397c478bd9Sstevel@tonic-gate 	}
1407c478bd9Sstevel@tonic-gate 
141c64d15a5Smcpowers 	rv = soft_get_private_value(key, CKA_BASE, g, &glen);
1427c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1437c478bd9Sstevel@tonic-gate 		goto clean1;
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 
146c64d15a5Smcpowers 	rv = soft_get_private_value(key, CKA_VALUE, x, &xlen);
1477c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1487c478bd9Sstevel@tonic-gate 		goto clean1;
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
151*726fad2aSDina K Nimeh 	k.prime = p;
152*726fad2aSDina K Nimeh 	k.prime_bits = CRYPTO_BYTES2BITS(plen);
153*726fad2aSDina K Nimeh 	k.subprime = q;
154*726fad2aSDina K Nimeh 	k.subprime_bits = CRYPTO_BYTES2BITS(qlen);
155*726fad2aSDina K Nimeh 	k.base = g;
156*726fad2aSDina K Nimeh 	k.base_bytes = glen;
157*726fad2aSDina K Nimeh 	k.private_x_bits = CRYPTO_BYTES2BITS(xlen);
158*726fad2aSDina K Nimeh 	k.private_x = x;
159*726fad2aSDina K Nimeh 	k.rfunc = NULL;
1607c478bd9Sstevel@tonic-gate 
161*726fad2aSDina K Nimeh 	rv = dsa_sign(&k, in, inlen, out);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate clean1:
1647c478bd9Sstevel@tonic-gate 	return (rv);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
167*726fad2aSDina K Nimeh static CK_RV
168*726fad2aSDina K Nimeh local_dsa_verify(soft_object_t *key, CK_BYTE_PTR data, CK_BYTE_PTR sig)
1697c478bd9Sstevel@tonic-gate {
170*726fad2aSDina K Nimeh 	CK_RV rv;
1717c478bd9Sstevel@tonic-gate 	uchar_t g[MAX_KEY_ATTR_BUFLEN];
1727c478bd9Sstevel@tonic-gate 	uchar_t y[MAX_KEY_ATTR_BUFLEN];
1737c478bd9Sstevel@tonic-gate 	uchar_t p[MAX_KEY_ATTR_BUFLEN];
1747c478bd9Sstevel@tonic-gate 	uchar_t q[MAX_KEY_ATTR_BUFLEN];
1757c478bd9Sstevel@tonic-gate 	uint_t glen = sizeof (g);
1767c478bd9Sstevel@tonic-gate 	uint_t ylen = sizeof (y);
1777c478bd9Sstevel@tonic-gate 	uint_t plen = sizeof (p);
1787c478bd9Sstevel@tonic-gate 	uint_t qlen = sizeof (q);
179*726fad2aSDina K Nimeh 	DSAbytekey k;
1807c478bd9Sstevel@tonic-gate 
181*726fad2aSDina K Nimeh 	rv = soft_get_public_value(key, CKA_PRIME, p, &plen);
1827c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1837c478bd9Sstevel@tonic-gate 		goto clean1;
1847c478bd9Sstevel@tonic-gate 	}
1857c478bd9Sstevel@tonic-gate 
186*726fad2aSDina K Nimeh 	rv = soft_get_public_value(key, CKA_SUBPRIME, q, &qlen);
1877c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1887c478bd9Sstevel@tonic-gate 		goto clean1;
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
191c64d15a5Smcpowers 	rv = soft_get_public_value(key, CKA_BASE, g, &glen);
1927c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1937c478bd9Sstevel@tonic-gate 		goto clean1;
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 
196c64d15a5Smcpowers 	rv = soft_get_public_value(key, CKA_VALUE, y, &ylen);
1977c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
1987c478bd9Sstevel@tonic-gate 		goto clean1;
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
201*726fad2aSDina K Nimeh 	k.prime = p;
202*726fad2aSDina K Nimeh 	k.prime_bits = CRYPTO_BYTES2BITS(plen);
203*726fad2aSDina K Nimeh 	k.subprime = q;
204*726fad2aSDina K Nimeh 	k.subprime_bits = CRYPTO_BYTES2BITS(qlen);
205*726fad2aSDina K Nimeh 	k.base = g;
206*726fad2aSDina K Nimeh 	k.base_bytes = glen;
207*726fad2aSDina K Nimeh 	k.public_y_bits = CRYPTO_BYTES2BITS(ylen);
208*726fad2aSDina K Nimeh 	k.public_y = y;
209*726fad2aSDina K Nimeh 	k.rfunc = NULL;
2107c478bd9Sstevel@tonic-gate 
211*726fad2aSDina K Nimeh 	rv = dsa_verify(&k, data, sig);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate clean1:
2147c478bd9Sstevel@tonic-gate 	return (rv);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate CK_RV
2197c478bd9Sstevel@tonic-gate soft_dsa_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
2207c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
2217c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulSignedLen, boolean_t Final)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
2257c478bd9Sstevel@tonic-gate 	CK_BYTE hash[SHA1_HASH_SIZE];  /* space enough for SHA1 and MD5 */
2267c478bd9Sstevel@tonic-gate 	CK_ULONG hash_len = SHA1_HASH_SIZE;
2277c478bd9Sstevel@tonic-gate 	soft_dsa_ctx_t *dsa_ctx = session_p->sign.context;
2287c478bd9Sstevel@tonic-gate 	soft_object_t *key = dsa_ctx->key;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/* Check arguments before performing message digest. */
2317c478bd9Sstevel@tonic-gate 	if (pSigned == NULL) {
2327c478bd9Sstevel@tonic-gate 		/* Application asks for the length of the output buffer. */
2337c478bd9Sstevel@tonic-gate 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
2347c478bd9Sstevel@tonic-gate 		goto clean1;
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/* Is the application-supplied buffer large enough? */
2387c478bd9Sstevel@tonic-gate 	if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
2397c478bd9Sstevel@tonic-gate 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
2407c478bd9Sstevel@tonic-gate 		rv = CKR_BUFFER_TOO_SMALL;
2417c478bd9Sstevel@tonic-gate 		goto clean1;
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (Final) {
2457c478bd9Sstevel@tonic-gate 		rv = soft_digest_final(session_p, hash, &hash_len);
2467c478bd9Sstevel@tonic-gate 	} else {
2477c478bd9Sstevel@tonic-gate 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
2517c478bd9Sstevel@tonic-gate 		/* free the signature key */
2527c478bd9Sstevel@tonic-gate 		soft_cleanup_object(key);
2537c478bd9Sstevel@tonic-gate 		free(key);
2547c478bd9Sstevel@tonic-gate 		goto clean_exit;
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	/*
2587c478bd9Sstevel@tonic-gate 	 * Now, we are ready to sign the data
2597c478bd9Sstevel@tonic-gate 	 * soft_dsa_sign() will free the signature key.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	rv = soft_dsa_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate clean_exit:
2647c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
2657c478bd9Sstevel@tonic-gate 	/* soft_digest_common() has freed the digest context */
2667c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
2677c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate clean1:
2707c478bd9Sstevel@tonic-gate 	return (rv);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate CK_RV
2757c478bd9Sstevel@tonic-gate soft_dsa_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
2767c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
2777c478bd9Sstevel@tonic-gate     CK_ULONG_PTR pulSignedLen)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
2817c478bd9Sstevel@tonic-gate 	soft_dsa_ctx_t *dsa_ctx = session_p->sign.context;
2827c478bd9Sstevel@tonic-gate 	soft_object_t *key = dsa_ctx->key;
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_DSA)) {
2857c478bd9Sstevel@tonic-gate 		rv = CKR_KEY_TYPE_INCONSISTENT;
2867c478bd9Sstevel@tonic-gate 		goto clean_exit;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	/* Output length is always 40 bytes. */
2907c478bd9Sstevel@tonic-gate 	if (pSigned == NULL) {
2917c478bd9Sstevel@tonic-gate 		/* Application asks for the length of the output buffer. */
2927c478bd9Sstevel@tonic-gate 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
2937c478bd9Sstevel@tonic-gate 		return (CKR_OK);
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/* Input data length needs to be 20 bytes. */
297d288ba74SAnthony Scarpino 	if (ulDataLen != DSA_SUBPRIME_BYTES) {
2987c478bd9Sstevel@tonic-gate 		rv = CKR_DATA_LEN_RANGE;
2997c478bd9Sstevel@tonic-gate 		goto clean_exit;
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	if (*pulSignedLen < DSA_SIGNATURE_LENGTH) {
3037c478bd9Sstevel@tonic-gate 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
3047c478bd9Sstevel@tonic-gate 		return (CKR_BUFFER_TOO_SMALL);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
307*726fad2aSDina K Nimeh 	rv = local_dsa_sign(key, pData, ulDataLen, pSigned);
3087c478bd9Sstevel@tonic-gate 	if (rv == CKR_OK) {
3097c478bd9Sstevel@tonic-gate 		*pulSignedLen = DSA_SIGNATURE_LENGTH;
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate clean_exit:
3137c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
3147c478bd9Sstevel@tonic-gate 	free(session_p->sign.context);
3157c478bd9Sstevel@tonic-gate 	session_p->sign.context = NULL;
3167c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
3177c478bd9Sstevel@tonic-gate 	soft_cleanup_object(key);
3187c478bd9Sstevel@tonic-gate 	free(key);
3197c478bd9Sstevel@tonic-gate 	return (rv);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate CK_RV
3247c478bd9Sstevel@tonic-gate soft_dsa_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
3257c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
3267c478bd9Sstevel@tonic-gate     CK_ULONG ulSignatureLen)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
3307c478bd9Sstevel@tonic-gate 	soft_dsa_ctx_t *dsa_ctx = session_p->verify.context;
3317c478bd9Sstevel@tonic-gate 	soft_object_t *key = dsa_ctx->key;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_DSA)) {
3347c478bd9Sstevel@tonic-gate 		rv = CKR_KEY_TYPE_INCONSISTENT;
3357c478bd9Sstevel@tonic-gate 		goto clean_exit;
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	/* Input data length needs to be 20 bytes. */
339d288ba74SAnthony Scarpino 	if (ulDataLen != DSA_SUBPRIME_BYTES) {
3407c478bd9Sstevel@tonic-gate 		rv = CKR_DATA_LEN_RANGE;
3417c478bd9Sstevel@tonic-gate 		goto clean_exit;
3427c478bd9Sstevel@tonic-gate 	}
3437c478bd9Sstevel@tonic-gate 
344*726fad2aSDina K Nimeh 	/* The signature length is always 40 bytes. */
345*726fad2aSDina K Nimeh 	if (ulSignatureLen != DSA_SIGNATURE_LENGTH) {
346*726fad2aSDina K Nimeh 		rv = CKR_SIGNATURE_LEN_RANGE;
347*726fad2aSDina K Nimeh 		goto clean_exit;
348*726fad2aSDina K Nimeh 	}
349*726fad2aSDina K Nimeh 
350*726fad2aSDina K Nimeh 	rv = local_dsa_verify(key, pData, pSignature);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate clean_exit:
3537c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
3547c478bd9Sstevel@tonic-gate 	free(session_p->verify.context);
3557c478bd9Sstevel@tonic-gate 	session_p->verify.context = NULL;
3567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
3577c478bd9Sstevel@tonic-gate 	soft_cleanup_object(key);
3587c478bd9Sstevel@tonic-gate 	free(key);
3597c478bd9Sstevel@tonic-gate 	return (rv);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate CK_RV
3647c478bd9Sstevel@tonic-gate soft_dsa_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
3657c478bd9Sstevel@tonic-gate     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
3667c478bd9Sstevel@tonic-gate     CK_ULONG ulSignedLen, boolean_t Final)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	CK_RV rv;
3707c478bd9Sstevel@tonic-gate 	CK_BYTE hash[SHA1_HASH_SIZE];  /* space enough for SHA1 and MD5 */
3717c478bd9Sstevel@tonic-gate 	CK_ULONG hash_len = SHA1_HASH_SIZE;
3727c478bd9Sstevel@tonic-gate 	soft_dsa_ctx_t *dsa_ctx = session_p->verify.context;
3737c478bd9Sstevel@tonic-gate 	soft_object_t *key = dsa_ctx->key;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	if (Final) {
3767c478bd9Sstevel@tonic-gate 		rv = soft_digest_final(session_p, hash, &hash_len);
3777c478bd9Sstevel@tonic-gate 	} else {
3787c478bd9Sstevel@tonic-gate 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
3797c478bd9Sstevel@tonic-gate 	}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
3827c478bd9Sstevel@tonic-gate 		/* free the verification key */
3837c478bd9Sstevel@tonic-gate 		soft_cleanup_object(key);
3847c478bd9Sstevel@tonic-gate 		free(key);
3857c478bd9Sstevel@tonic-gate 		goto clean_exit;
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/*
3897c478bd9Sstevel@tonic-gate 	 * Now, we are ready to verify the data using signature.
3907c478bd9Sstevel@tonic-gate 	 * soft_dsa_verify() will free the verification key.
3917c478bd9Sstevel@tonic-gate 	 */
3927c478bd9Sstevel@tonic-gate 	rv = soft_dsa_verify(session_p, hash, hash_len,
3937c478bd9Sstevel@tonic-gate 	    pSigned, ulSignedLen);
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate clean_exit:
3967c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&session_p->session_mutex);
3977c478bd9Sstevel@tonic-gate 	/* soft_digest_common() has freed the digest context */
3987c478bd9Sstevel@tonic-gate 	session_p->digest.flags = 0;
3997c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&session_p->session_mutex);
4007c478bd9Sstevel@tonic-gate 	return (rv);
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 
404*726fad2aSDina K Nimeh static CK_RV
4057c478bd9Sstevel@tonic-gate soft_genDSAkey_set_attribute(soft_object_t *key, CK_ATTRIBUTE_TYPE type,
4067c478bd9Sstevel@tonic-gate     uchar_t *value, uint32_t value_len, boolean_t public)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	CK_RV rv = CKR_OK;
4107c478bd9Sstevel@tonic-gate 	biginteger_t *dst = NULL;
4117c478bd9Sstevel@tonic-gate 	biginteger_t src;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	switch (type) {
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	case CKA_VALUE:
4167c478bd9Sstevel@tonic-gate 		if (public)
4177c478bd9Sstevel@tonic-gate 			dst = OBJ_PUB_DSA_VALUE(key);
4187c478bd9Sstevel@tonic-gate 		else
4197c478bd9Sstevel@tonic-gate 			dst = OBJ_PRI_DSA_VALUE(key);
4207c478bd9Sstevel@tonic-gate 		break;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	case CKA_PRIME:
4237c478bd9Sstevel@tonic-gate 		if (public)
4247c478bd9Sstevel@tonic-gate 			dst = OBJ_PUB_DSA_PRIME(key);
4257c478bd9Sstevel@tonic-gate 		else
4267c478bd9Sstevel@tonic-gate 			dst = OBJ_PRI_DSA_PRIME(key);
4277c478bd9Sstevel@tonic-gate 		break;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	case CKA_SUBPRIME:
4307c478bd9Sstevel@tonic-gate 		if (public)
4317c478bd9Sstevel@tonic-gate 			dst = OBJ_PUB_DSA_SUBPRIME(key);
4327c478bd9Sstevel@tonic-gate 		else
4337c478bd9Sstevel@tonic-gate 			dst = OBJ_PRI_DSA_SUBPRIME(key);
4347c478bd9Sstevel@tonic-gate 		break;
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	case CKA_BASE:
4377c478bd9Sstevel@tonic-gate 		if (public)
4387c478bd9Sstevel@tonic-gate 			dst = OBJ_PUB_DSA_BASE(key);
4397c478bd9Sstevel@tonic-gate 		else
4407c478bd9Sstevel@tonic-gate 			dst = OBJ_PRI_DSA_BASE(key);
4417c478bd9Sstevel@tonic-gate 		break;
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
444*726fad2aSDina K Nimeh 	/* Note: removal of preceding 0x00 imitates similar code in RSA */
445*726fad2aSDina K Nimeh 	while (value[0] == 0) {		/* remove preceding 0x00 */
446*726fad2aSDina K Nimeh 		value++;
447*726fad2aSDina K Nimeh 		value_len--;
4487c478bd9Sstevel@tonic-gate 	}
449*726fad2aSDina K Nimeh 
450*726fad2aSDina K Nimeh 	if ((rv = dup_bigint_attr(&src, value, value_len)) != CKR_OK)
451*726fad2aSDina K Nimeh 		goto cleanexit;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/* Copy the attribute in the key object. */
4547c478bd9Sstevel@tonic-gate 	copy_bigint_attr(&src, dst);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate cleanexit:
4577c478bd9Sstevel@tonic-gate 	/* No need to free big_value because dst holds it now after copy. */
4587c478bd9Sstevel@tonic-gate 	return (rv);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate CK_RV
4647c478bd9Sstevel@tonic-gate soft_dsa_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	CK_RV rv;
4677c478bd9Sstevel@tonic-gate 	uchar_t prime[MAX_KEY_ATTR_BUFLEN];
4687c478bd9Sstevel@tonic-gate 	uint32_t prime_len = sizeof (prime);
4697c478bd9Sstevel@tonic-gate 	uchar_t	subprime[MAX_KEY_ATTR_BUFLEN];
4707c478bd9Sstevel@tonic-gate 	uint32_t subprime_len = sizeof (subprime);
4717c478bd9Sstevel@tonic-gate 	uchar_t	base[MAX_KEY_ATTR_BUFLEN];
4727c478bd9Sstevel@tonic-gate 	uint32_t base_len = sizeof (base);
473*726fad2aSDina K Nimeh 	uchar_t	pubvalue[MAX_KEY_ATTR_BUFLEN];
474*726fad2aSDina K Nimeh 	uint32_t pubvalue_len = sizeof (pubvalue);
475*726fad2aSDina K Nimeh 	uchar_t	privalue[DSA_SUBPRIME_BYTES];
476*726fad2aSDina K Nimeh 	uint32_t privalue_len = sizeof (privalue);
477*726fad2aSDina K Nimeh 	DSAbytekey k;
47860c58272Smarkfen 
4797c478bd9Sstevel@tonic-gate 	if ((pubkey == NULL) || (prikey == NULL)) {
4807c478bd9Sstevel@tonic-gate 		return (CKR_ARGUMENTS_BAD);
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/* lookup prime, subprime and base */
484c64d15a5Smcpowers 	rv = soft_get_public_value(pubkey, CKA_PRIME, prime, &prime_len);
4857c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
4867c478bd9Sstevel@tonic-gate 		rv = CKR_TEMPLATE_INCOMPLETE;
4877c478bd9Sstevel@tonic-gate 		goto cleanexit;
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
490c64d15a5Smcpowers 	rv = soft_get_public_value(pubkey, CKA_SUBPRIME, subprime,
4917c478bd9Sstevel@tonic-gate 	    &subprime_len);
4927c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
4937c478bd9Sstevel@tonic-gate 		rv = CKR_TEMPLATE_INCOMPLETE;
4947c478bd9Sstevel@tonic-gate 		goto cleanexit;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
497c64d15a5Smcpowers 	rv = soft_get_public_value(pubkey, CKA_BASE, base, &base_len);
4987c478bd9Sstevel@tonic-gate 	if (rv != CKR_OK) {
4997c478bd9Sstevel@tonic-gate 		rv = CKR_TEMPLATE_INCOMPLETE;
5007c478bd9Sstevel@tonic-gate 		goto cleanexit;
5017c478bd9Sstevel@tonic-gate 	}
5027c478bd9Sstevel@tonic-gate 
503*726fad2aSDina K Nimeh 	/* Inputs to DSA key pair generation. */
504*726fad2aSDina K Nimeh 	k.prime = prime;
505*726fad2aSDina K Nimeh 	k.prime_bits = CRYPTO_BYTES2BITS(prime_len);
506*726fad2aSDina K Nimeh 	k.subprime = subprime;
507*726fad2aSDina K Nimeh 	k.subprime_bits = CRYPTO_BYTES2BITS(subprime_len);
508*726fad2aSDina K Nimeh 	k.base = base;
509*726fad2aSDina K Nimeh 	k.base_bytes = base_len;
510*726fad2aSDina K Nimeh 	k.rfunc = (IS_TOKEN_OBJECT(pubkey) || IS_TOKEN_OBJECT(prikey)) ?
511*726fad2aSDina K Nimeh 	    pkcs11_get_random : pkcs11_get_urandom;
512*726fad2aSDina K Nimeh 
513*726fad2aSDina K Nimeh 	/* Outputs from DSA key pair generation. */
514*726fad2aSDina K Nimeh 	k.public_y = pubvalue;
515*726fad2aSDina K Nimeh 	k.public_y_bits = CRYPTO_BYTES2BITS(pubvalue_len);
516*726fad2aSDina K Nimeh 	k.private_x = privalue;
517*726fad2aSDina K Nimeh 	k.private_x_bits = CRYPTO_BYTES2BITS(privalue_len);
518*726fad2aSDina K Nimeh 
519*726fad2aSDina K Nimeh 	rv = dsa_genkey_pair(&k);
520*726fad2aSDina K Nimeh 
521*726fad2aSDina K Nimeh 	if (rv != CKR_OK) {
5227c478bd9Sstevel@tonic-gate 		goto cleanexit;
5237c478bd9Sstevel@tonic-gate 	}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	/* Update attribute in public key. */
5267c478bd9Sstevel@tonic-gate 	if ((rv = soft_genDSAkey_set_attribute(pubkey, CKA_VALUE,
527*726fad2aSDina K Nimeh 	    pubvalue, CRYPTO_BITS2BYTES(k.public_y_bits), B_TRUE)) != CKR_OK) {
5287c478bd9Sstevel@tonic-gate 		goto cleanexit;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 	/* Update attributes in private key. */
5317c478bd9Sstevel@tonic-gate 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_PRIME,
532*726fad2aSDina K Nimeh 	    prime, CRYPTO_BITS2BYTES(k.prime_bits), B_FALSE)) != CKR_OK) {
5337c478bd9Sstevel@tonic-gate 		goto cleanexit;
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
536*726fad2aSDina K Nimeh 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_SUBPRIME, subprime,
537*726fad2aSDina K Nimeh 	    CRYPTO_BITS2BYTES(k.subprime_bits), B_FALSE)) != CKR_OK) {
5387c478bd9Sstevel@tonic-gate 		goto cleanexit;
5397c478bd9Sstevel@tonic-gate 	}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_BASE,
542*726fad2aSDina K Nimeh 	    base, k.base_bytes, B_FALSE)) != CKR_OK) {
5437c478bd9Sstevel@tonic-gate 		goto cleanexit;
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
546*726fad2aSDina K Nimeh 	if ((rv = soft_genDSAkey_set_attribute(prikey, CKA_VALUE, privalue,
547*726fad2aSDina K Nimeh 	    CRYPTO_BITS2BYTES(k.private_x_bits), B_FALSE)) != CKR_OK) {
5487c478bd9Sstevel@tonic-gate 		goto cleanexit;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate cleanexit:
5527c478bd9Sstevel@tonic-gate 	return (rv);
5537c478bd9Sstevel@tonic-gate }
554