softEC.c revision 9127:39de79f2e5d5
1193323Sed/*
2193323Sed * CDDL HEADER START
3193323Sed *
4193323Sed * The contents of this file are subject to the terms of the
5193323Sed * Common Development and Distribution License (the "License").
6193323Sed * You may not use this file except in compliance with the License.
7193323Sed *
8193323Sed * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9193323Sed * or http://www.opensolaris.org/os/licensing.
10193323Sed * See the License for the specific language governing permissions
11193323Sed * and limitations under the License.
12193323Sed *
13193323Sed * When distributing Covered Code, include this CDDL HEADER in each
14193323Sed * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15201360Srdivacky * If applicable, add the following below this CDDL HEADER, with the
16201360Srdivacky * fields enclosed by brackets "[]" replaced with your own identifying
17193323Sed * information: Portions Copyright [yyyy] [name of copyright owner]
18193323Sed *
19193323Sed * CDDL HEADER END
20201360Srdivacky */
21193323Sed/*
22201360Srdivacky * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23201360Srdivacky * Use is subject to license terms.
24201360Srdivacky */
25201360Srdivacky
26201360Srdivacky#include <stdlib.h>
27201360Srdivacky#include <string.h>
28201360Srdivacky#include <strings.h>
29201360Srdivacky#include <sys/types.h>
30201360Srdivacky#include <sys/crypto/common.h>
31201360Srdivacky#include <security/cryptoki.h>
32201360Srdivacky#include <bignum.h>
33201360Srdivacky#include <des_impl.h>
34201360Srdivacky#include "softGlobal.h"
35201360Srdivacky#include "softSession.h"
36201360Srdivacky#include "softObject.h"
37201360Srdivacky#include "softEC.h"
38201360Srdivacky#include "softCrypt.h"
39201360Srdivacky#include "softOps.h"
40201360Srdivacky#include "softMAC.h"
41201360Srdivacky
42201360Srdivackyvoid
43201360Srdivackysoft_free_ecparams(ECParams *params, boolean_t freeit)
44201360Srdivacky{
45201360Srdivacky	SECITEM_FreeItem(&params->fieldID.u.prime, B_FALSE);
46201360Srdivacky	SECITEM_FreeItem(&params->curve.a, B_FALSE);
47201360Srdivacky	SECITEM_FreeItem(&params->curve.b, B_FALSE);
48201360Srdivacky	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
49201360Srdivacky	SECITEM_FreeItem(&params->base, B_FALSE);
50201360Srdivacky	SECITEM_FreeItem(&params->order, B_FALSE);
51201360Srdivacky	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
52201360Srdivacky	SECITEM_FreeItem(&params->curveOID, B_FALSE);
53201360Srdivacky	if (freeit)
54201360Srdivacky		free(params);
55201360Srdivacky}
56201360Srdivacky
57201360Srdivackystatic void
58201360Srdivackysoft_free_ecc_context(soft_ecc_ctx_t *ecc_ctx)
59201360Srdivacky{
60201360Srdivacky	if (ecc_ctx != NULL) {
61201360Srdivacky		if (ecc_ctx->key != NULL) {
62201360Srdivacky			soft_cleanup_object(ecc_ctx->key);
63201360Srdivacky			free(ecc_ctx->key);
64201360Srdivacky		}
65201360Srdivacky
66201360Srdivacky		soft_free_ecparams(&ecc_ctx->ecparams, B_FALSE);
67201360Srdivacky		free(ecc_ctx);
68201360Srdivacky	}
69201360Srdivacky}
70201360Srdivacky
71201360Srdivackyvoid
72201360Srdivackysoft_free_ecprivkey(ECPrivateKey *key)
73201360Srdivacky{
74201360Srdivacky	soft_free_ecparams(&key->ecParams, B_FALSE);
75201360Srdivacky	/*
76201360Srdivacky	 * Don't free publicValue or privateValue
77201360Srdivacky	 * as these values are copied into objects.
78201360Srdivacky	 */
79201360Srdivacky	SECITEM_FreeItem(&key->version, B_FALSE);
80201360Srdivacky	free(key);
81218893Sdim}
82218893Sdim
83218893Sdim/*
84218893Sdim * Called from init routines to do basic sanity checks. Init routines,
85193323Sed * e.g. sign_init should fail rather than subsequent operations.
86201360Srdivacky */
87193323Sedstatic int
88193323Sedcheck_key(soft_object_t *key_p, boolean_t sign)
89193323Sed{
90193323Sed	biginteger_t *p;
91201360Srdivacky	ulong_t len;
92193323Sed
93210299Sed	if (sign) {
94210299Sed		if ((key_p->class != CKO_PRIVATE_KEY) ||
95193323Sed		    (key_p->key_type != CKK_EC))
96201360Srdivacky			return (CKR_KEY_TYPE_INCONSISTENT);
97193323Sed
98193323Sed		p = OBJ_PRI_EC_VALUE(key_p);
99193323Sed		len = p->big_value_len;
100193323Sed		if (p->big_value == NULL)
101201360Srdivacky			len = 0;
102193323Sed
103201360Srdivacky		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) ||
104201360Srdivacky		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN))
105201360Srdivacky			return (CKR_KEY_SIZE_RANGE);
106201360Srdivacky	} else {
107201360Srdivacky		if ((key_p->class != CKO_PUBLIC_KEY) ||
108201360Srdivacky		    (key_p->key_type != CKK_EC))
109201360Srdivacky			return (CKR_KEY_TYPE_INCONSISTENT);
110201360Srdivacky
111201360Srdivacky		p = OBJ_PUB_EC_POINT(key_p);
112201360Srdivacky		len = p->big_value_len;
113201360Srdivacky		if (p->big_value == NULL)
114201360Srdivacky			len = 0;
115201360Srdivacky
116201360Srdivacky		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) * 2 + 1 ||
117201360Srdivacky		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN) * 2 + 1)
118201360Srdivacky			return (CKR_KEY_SIZE_RANGE);
119201360Srdivacky	}
120201360Srdivacky
121201360Srdivacky	return (CKR_OK);
122201360Srdivacky}
123201360Srdivacky
124201360Srdivacky/*
125201360Srdivacky * This function places the octet string of the specified attribute
126201360Srdivacky * into the corresponding key object.
127201360Srdivacky */
128201360Srdivackystatic void
129201360Srdivackysoft_genECkey_set_attribute(soft_object_t *key, biginteger_t *bi,
130201360Srdivacky    CK_ATTRIBUTE_TYPE type)
131201360Srdivacky{
132201360Srdivacky	biginteger_t *dst;
133201360Srdivacky
134201360Srdivacky	switch (type) {
135201360Srdivacky	case CKA_VALUE:
136201360Srdivacky		dst = OBJ_PRI_EC_VALUE(key);
137201360Srdivacky		break;
138201360Srdivacky
139201360Srdivacky	case CKA_EC_POINT:
140201360Srdivacky		dst = OBJ_PUB_EC_POINT(key);
141201360Srdivacky		break;
142201360Srdivacky	}
143201360Srdivacky	copy_bigint_attr(bi, dst);
144201360Srdivacky}
145201360Srdivacky
146201360SrdivackyCK_RV
147201360Srdivackysoft_ec_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
148201360Srdivacky{
149201360Srdivacky	CK_RV rv;
150201360Srdivacky	CK_ATTRIBUTE template;
151201360Srdivacky	ECPrivateKey *privKey;	/* contains both public and private values */
152201360Srdivacky	ECParams *ecparams;
153201360Srdivacky	SECKEYECParams params_item;
154201360Srdivacky	biginteger_t bi;
155201360Srdivacky	uchar_t param_buffer[EC_MAX_OID_LEN];
156201360Srdivacky	uint_t paramlen;
157201360Srdivacky
158201360Srdivacky	if ((pubkey->class != CKO_PUBLIC_KEY) ||
159201360Srdivacky	    (pubkey->key_type != CKK_EC))
160201360Srdivacky		return (CKR_KEY_TYPE_INCONSISTENT);
161201360Srdivacky
162201360Srdivacky	if ((prikey->class != CKO_PRIVATE_KEY) ||
163201360Srdivacky	    (prikey->key_type != CKK_EC))
164201360Srdivacky		return (CKR_KEY_TYPE_INCONSISTENT);
165201360Srdivacky
166201360Srdivacky	template.type = CKA_EC_PARAMS;
167201360Srdivacky	template.pValue = param_buffer;
168201360Srdivacky	template.ulValueLen = sizeof (param_buffer);
169201360Srdivacky	rv = soft_get_public_key_attribute(pubkey, &template);
170201360Srdivacky	if (rv != CKR_OK) {
171201360Srdivacky		return (rv);
172201360Srdivacky	}
173201360Srdivacky	paramlen = template.ulValueLen;
174201360Srdivacky
175201360Srdivacky	/* private key also has CKA_EC_PARAMS attribute */
176201360Srdivacky	rv = set_extra_attr_to_object(prikey, CKA_EC_PARAMS, &template);
177201360Srdivacky	if (rv != CKR_OK) {
178201360Srdivacky		return (rv);
179201360Srdivacky	}
180201360Srdivacky
181201360Srdivacky	/* ASN1 check */
182201360Srdivacky	if (param_buffer[0] != 0x06 ||
183201360Srdivacky	    param_buffer[1] != paramlen - 2) {
184201360Srdivacky		return (CKR_ATTRIBUTE_VALUE_INVALID);
185201360Srdivacky	}
186201360Srdivacky	params_item.len = paramlen;
187201360Srdivacky	params_item.data = param_buffer;
188201360Srdivacky	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
189201360Srdivacky		/* bad curve OID */
190201360Srdivacky		return (CKR_ARGUMENTS_BAD);
191201360Srdivacky	}
192201360Srdivacky
193201360Srdivacky	if (EC_NewKey(ecparams, &privKey, 0) != SECSuccess) {
194201360Srdivacky		soft_free_ecparams(ecparams, B_TRUE);
195201360Srdivacky		return (CKR_FUNCTION_FAILED);
196201360Srdivacky	}
197201360Srdivacky
198201360Srdivacky	bi.big_value = privKey->privateValue.data;
199201360Srdivacky	bi.big_value_len = privKey->privateValue.len;
200201360Srdivacky	soft_genECkey_set_attribute(prikey, &bi, CKA_VALUE);
201201360Srdivacky
202201360Srdivacky	bi.big_value = privKey->publicValue.data;
203207618Srdivacky	bi.big_value_len = privKey->publicValue.len;
204201360Srdivacky	soft_genECkey_set_attribute(pubkey, &bi, CKA_EC_POINT);
205207618Srdivacky
206221345Sdim	soft_free_ecprivkey(privKey);
207221345Sdim	soft_free_ecparams(ecparams, B_TRUE);
208221345Sdim
209221345Sdim	return (CKR_OK);
210193323Sed}
211201360Srdivacky
212193323SedCK_RV
213193323Sedsoft_ec_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
214193323Sed    void *mech_params, size_t mech_params_len)
215193323Sed{
216201360Srdivacky	CK_RV		rv;
217193323Sed	CK_ATTRIBUTE	template;
218210299Sed	CK_ECDH1_DERIVE_PARAMS *ecdh1_derive_params = mech_params;
219210299Sed	uchar_t		value[EC_MAX_VALUE_LEN];
220210299Sed	uint32_t	value_len = sizeof (value);
221210299Sed	uchar_t		params[EC_MAX_OID_LEN];
222210299Sed	uint32_t	params_len = sizeof (params);
223210299Sed	uint32_t	keylen;
224210299Sed	ECParams	*ecparams;
225210299Sed	SECKEYECParams	params_item;
226210299Sed	SECItem		public_value_item, private_value_item, secret_item;
227210299Sed	uchar_t		*buf;
228210299Sed
229210299Sed	if (mech_params_len != sizeof (CK_ECDH1_DERIVE_PARAMS) ||
230210299Sed	    ecdh1_derive_params->kdf != CKD_NULL) {
231210299Sed		return (CKR_MECHANISM_PARAM_INVALID);
232210299Sed	}
233210299Sed
234210299Sed	template.type = CKA_VALUE;
235210299Sed	template.pValue = value;
236210299Sed	template.ulValueLen = value_len;
237210299Sed	rv = soft_get_private_key_attribute(basekey, &template);
238210299Sed	if (rv != CKR_OK) {
239193323Sed		return (rv);
240201360Srdivacky	}
241193323Sed	value_len = template.ulValueLen;
242193323Sed	private_value_item.data = value;
243193323Sed	private_value_item.len = value_len;
244193323Sed
245201360Srdivacky	template.type = CKA_EC_PARAMS;
246193323Sed	template.pValue = params;
247210299Sed	template.ulValueLen = params_len;
248210299Sed	rv = soft_get_private_key_attribute(basekey, &template);
249210299Sed	if (rv != CKR_OK) {
250210299Sed		return (rv);
251210299Sed	}
252210299Sed	params_len = template.ulValueLen;
253210299Sed
254210299Sed	switch (secretkey->key_type) {
255210299Sed	case CKK_DES:
256210299Sed		keylen = DES_KEYSIZE;
257210299Sed		break;
258210299Sed	case CKK_DES2:
259210299Sed		keylen = DES2_KEYSIZE;
260210299Sed		break;
261210299Sed	case CKK_DES3:
262210299Sed		keylen = DES3_KEYSIZE;
263210299Sed		break;
264210299Sed	case CKK_RC4:
265210299Sed	case CKK_AES:
266210299Sed	case CKK_GENERIC_SECRET:
267210299Sed#ifdef	__sparcv9
268210299Sed		/* LINTED */
269210299Sed		keylen = (uint32_t)OBJ_SEC_VALUE_LEN(secretkey);
270210299Sed#else	/* !__sparcv9 */
271210299Sed		keylen = OBJ_SEC_VALUE_LEN(secretkey);
272210299Sed#endif	/* __sparcv9 */
273210299Sed		break;
274210299Sed	}
275210299Sed
276210299Sed	/* ASN1 check */
277210299Sed	if (params[0] != 0x06 ||
278210299Sed	    params[1] != params_len - 2) {
279210299Sed		return (CKR_ATTRIBUTE_VALUE_INVALID);
280210299Sed	}
281210299Sed	params_item.data = params;
282210299Sed	params_item.len = params_len;
283210299Sed	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
284210299Sed		/* bad curve OID */
285210299Sed		return (CKR_ARGUMENTS_BAD);
286210299Sed	}
287210299Sed
288210299Sed	public_value_item.data = ecdh1_derive_params->pPublicData;
289210299Sed	public_value_item.len = ecdh1_derive_params->ulPublicDataLen;
290210299Sed
291210299Sed	secret_item.data = NULL;
292210299Sed	secret_item.len = 0;
293210299Sed
294210299Sed	if (ECDH_Derive(&public_value_item, ecparams, &private_value_item,
295210299Sed	    B_FALSE, &secret_item, 0) != SECSuccess) {
296210299Sed		soft_free_ecparams(ecparams, B_TRUE);
297210299Sed		return (CKR_FUNCTION_FAILED);
298210299Sed	} else {
299210299Sed		rv = CKR_OK;
300210299Sed	}
301210299Sed
302210299Sed	if (keylen == 0)
303210299Sed		keylen = secret_item.len;
304210299Sed
305210299Sed	if (keylen > secret_item.len) {
306210299Sed		rv = CKR_ATTRIBUTE_VALUE_INVALID;
307210299Sed		goto out;
308210299Sed	}
309210299Sed	buf = malloc(keylen);
310210299Sed	if (buf == NULL) {
311210299Sed		rv = CKR_HOST_MEMORY;
312210299Sed		goto out;
313210299Sed	}
314210299Sed	bcopy(secret_item.data + secret_item.len - keylen, buf, keylen);
315210299Sed	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
316210299Sed	OBJ_SEC_VALUE(secretkey) = buf;
317210299Sed
318210299Sedout:
319210299Sed	soft_free_ecparams(ecparams, B_TRUE);
320210299Sed	SECITEM_FreeItem(&secret_item, B_FALSE);
321210299Sed
322210299Sed	return (rv);
323210299Sed}
324210299Sed
325210299Sed/*
326210299Sed * Allocate a ECC context for the active sign or verify operation.
327210299Sed * This function is called without the session lock held.
328210299Sed */
329210299SedCK_RV
330210299Sedsoft_ecc_sign_verify_init_common(soft_session_t *session_p,
331210299Sed    CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
332210299Sed    boolean_t sign)
333210299Sed{
334210299Sed	CK_RV rv;
335210299Sed	CK_ATTRIBUTE template;
336210299Sed	CK_MECHANISM digest_mech;
337210299Sed	soft_ecc_ctx_t *ecc_ctx;
338210299Sed	soft_object_t *tmp_key = NULL;
339210299Sed	uchar_t params[EC_MAX_OID_LEN];
340210299Sed	ECParams *ecparams;
341210299Sed	SECKEYECParams params_item;
342210299Sed
343210299Sed	if ((rv = check_key(key_p, sign)) != CKR_OK)
344210299Sed		return (rv);
345210299Sed
346210299Sed	if (pMechanism->mechanism == CKM_ECDSA_SHA1) {
347210299Sed		digest_mech.mechanism = CKM_SHA_1;
348210299Sed		rv = soft_digest_init_internal(session_p, &digest_mech);
349210299Sed		if (rv != CKR_OK)
350210299Sed			return (rv);
351210299Sed	}
352210299Sed
353210299Sed	ecc_ctx = malloc(sizeof (soft_ecc_ctx_t));
354210299Sed	if (ecc_ctx == NULL) {
355210299Sed		return (CKR_HOST_MEMORY);
356210299Sed	}
357210299Sed
358210299Sed	/*
359210299Sed	 * Make a copy of the signature or verification key, and save it
360210299Sed	 * in the ECC crypto context since it will be used later for
361210299Sed	 * signing/verification. We don't want to hold any object reference
362210299Sed	 * on this original key while doing signing/verification.
363210299Sed	 */
364210299Sed	(void) pthread_mutex_lock(&key_p->object_mutex);
365210299Sed	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH, NULL);
366210299Sed	if ((rv != CKR_OK) || (tmp_key == NULL)) {
367210299Sed		/* Most likely we ran out of space. */
368210299Sed		(void) pthread_mutex_unlock(&key_p->object_mutex);
369210299Sed		free(ecc_ctx);
370210299Sed		return (rv);
371210299Sed	}
372210299Sed
373210299Sed
374210299Sed	template.type = CKA_EC_PARAMS;
375210299Sed	template.pValue = params;
376210299Sed	template.ulValueLen = sizeof (params);
377210299Sed	rv = soft_get_private_key_attribute(key_p, &template);
378210299Sed	(void) pthread_mutex_unlock(&key_p->object_mutex);
379210299Sed	if (rv != CKR_OK) {
380210299Sed		goto out;
381210299Sed	}
382210299Sed
383210299Sed	/* ASN1 check */
384210299Sed	if (params[0] != 0x06 ||
385210299Sed	    params[1] != template.ulValueLen - 2) {
386210299Sed		rv = CKR_ATTRIBUTE_VALUE_INVALID;
387210299Sed		goto out;
388210299Sed	}
389210299Sed	params_item.data = params;
390210299Sed	params_item.len = template.ulValueLen;
391210299Sed
392210299Sed	ecc_ctx->key = tmp_key;
393210299Sed
394210299Sed	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
395210299Sed		/* bad curve OID */
396210299Sed		rv = CKR_ARGUMENTS_BAD;
397210299Sed		goto out;
398221345Sdim	}
399210299Sed	ecc_ctx->ecparams = *ecparams;
400210299Sed	free(ecparams);
401193323Sed
402201360Srdivacky	(void) pthread_mutex_lock(&session_p->session_mutex);
403193323Sed
404193323Sed	if (sign) {
405193323Sed		session_p->sign.context = ecc_ctx;
406193323Sed		session_p->sign.mech.mechanism = pMechanism->mechanism;
407201360Srdivacky	} else {
408193323Sed		session_p->verify.context = ecc_ctx;
409210299Sed		session_p->verify.mech.mechanism = pMechanism->mechanism;
410210299Sed	}
411210299Sed
412210299Sed	(void) pthread_mutex_unlock(&session_p->session_mutex);
413210299Sed	return (CKR_OK);
414210299Sed
415210299Sedout:
416210299Sed	soft_cleanup_object(tmp_key);
417210299Sed	free(tmp_key);
418210299Sed	free(ecc_ctx);
419210299Sed
420210299Sed	return (rv);
421210299Sed}
422210299Sed
423210299SedCK_RV
424210299Sedsoft_ecc_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
425210299Sed    CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
426193323Sed    CK_ULONG_PTR pulSignedLen, boolean_t Final)
427201360Srdivacky{
428193323Sed	CK_RV rv = CKR_OK;
429193323Sed	CK_BYTE hash[SHA1_HASH_SIZE];
430193323Sed	CK_ULONG hash_len = SHA1_HASH_SIZE;
431193323Sed
432201360Srdivacky	if (pSigned != NULL) {
433193323Sed		if (Final) {
434210299Sed			rv = soft_digest_final(session_p, hash, &hash_len);
435210299Sed		} else {
436210299Sed			rv = soft_digest(session_p, pData, ulDataLen, hash,
437210299Sed			    &hash_len);
438210299Sed		}
439193323Sed
440201360Srdivacky		if (rv != CKR_OK) {
441193323Sed			(void) pthread_mutex_lock(&session_p->session_mutex);
442193323Sed			soft_free_ecc_context(session_p->sign.context);
443193323Sed			session_p->sign.context = NULL;
444193323Sed			session_p->digest.flags = 0;
445201360Srdivacky			(void) pthread_mutex_unlock(&session_p->session_mutex);
446193323Sed			return (rv);
447210299Sed		}
448210299Sed	}
449210299Sed
450210299Sed	rv = soft_ecc_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
451210299Sed
452193323Sedclean_exit:
453201360Srdivacky	(void) pthread_mutex_lock(&session_p->session_mutex);
454193323Sed	/* soft_digest_common() has freed the digest context */
455193323Sed	session_p->digest.flags = 0;
456193323Sed	(void) pthread_mutex_unlock(&session_p->session_mutex);
457193323Sed
458201360Srdivackyclean1:
459193323Sed	return (rv);
460201360Srdivacky}
461210299Sed
462210299SedCK_RV
463210299Sedsoft_ecc_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
464193323Sed    CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
465201360Srdivacky    CK_ULONG_PTR pulSignedLen)
466193323Sed{
467193323Sed	CK_RV rv = CKR_OK;
468193323Sed	SECStatus ss;
469193323Sed	soft_ecc_ctx_t *ecc_ctx = session_p->sign.context;
470201360Srdivacky	soft_object_t *key = ecc_ctx->key;
471193323Sed	uchar_t value[EC_MAX_VALUE_LEN];
472210299Sed	ECPrivateKey ECkey;
473210299Sed	SECItem signature_item;
474210299Sed	SECItem digest_item;
475193323Sed	uint_t value_len;
476201360Srdivacky
477193323Sed	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_EC)) {
478193323Sed		rv = CKR_KEY_TYPE_INCONSISTENT;
479193323Sed		goto clean_exit;
480193323Sed	}
481201360Srdivacky
482193323Sed	if (ulDataLen > EC_MAX_DIGEST_LEN) {
483210299Sed		rv = CKR_DATA_LEN_RANGE;
484210299Sed		goto clean_exit;
485210299Sed	}
486193323Sed
487201360Srdivacky	/* structure assignment */
488193323Sed	ECkey.ecParams = ecc_ctx->ecparams;
489193323Sed
490193323Sed	value_len = EC_MAX_VALUE_LEN;
491193323Sed	rv = soft_get_private_value(key, CKA_VALUE, value, &value_len);
492201360Srdivacky	if (rv != CKR_OK) {
493193323Sed		goto clean_exit;
494210299Sed	}
495210299Sed
496210299Sed	ECkey.privateValue.data = value;
497210299Sed	ECkey.privateValue.len = value_len;
498210299Sed
499210299Sed	signature_item.data = pSigned;
500210299Sed	signature_item.len = *pulSignedLen;
501210299Sed
502210299Sed	digest_item.data = pData;
503210299Sed	digest_item.len = ulDataLen;
504210299Sed
505210299Sed	if ((ss = ECDSA_SignDigest(&ECkey, &signature_item, &digest_item, 0))
506210299Sed	    != SECSuccess) {
507210299Sed		if (ss == SECBufferTooSmall)
508210299Sed			return (CKR_BUFFER_TOO_SMALL);
509210299Sed
510210299Sed		rv = CKR_FUNCTION_FAILED;
511210299Sed		goto clean_exit;
512210299Sed	}
513210299Sed
514210299Sed	if (rv == CKR_OK) {
515193323Sed		*pulSignedLen = signature_item.len;
516201360Srdivacky		if (pSigned == NULL)
517193323Sed			return (rv);
518193323Sed	}
519193323Sed
520193323Sedclean_exit:
521201360Srdivacky	(void) pthread_mutex_lock(&session_p->session_mutex);
522201360Srdivacky	soft_free_ecc_context(session_p->sign.context);
523210299Sed	session_p->sign.context = NULL;
524210299Sed	(void) pthread_mutex_unlock(&session_p->session_mutex);
525210299Sed	return (rv);
526210299Sed}
527193323Sed
528201360SrdivackyCK_RV
529193323Sedsoft_ecc_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
530193323Sed    CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
531193323Sed    CK_ULONG ulSignatureLen)
532193323Sed{
533201360Srdivacky	CK_RV rv = CKR_OK;
534193323Sed	soft_ecc_ctx_t *ecc_ctx = session_p->verify.context;
535210299Sed	soft_object_t *key = ecc_ctx->key;
536210299Sed	uchar_t point[EC_MAX_POINT_LEN];
537210299Sed	CK_ATTRIBUTE template;
538210299Sed	ECPublicKey ECkey;
539210299Sed	SECItem signature_item;
540193323Sed	SECItem digest_item;
541201360Srdivacky
542193323Sed	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_EC)) {
543193323Sed		rv = CKR_KEY_TYPE_INCONSISTENT;
544193323Sed		goto clean_exit;
545193323Sed	}
546201360Srdivacky
547201360Srdivacky	if (ulSignatureLen > EC_MAX_SIG_LEN) {
548210299Sed		rv = CKR_SIGNATURE_LEN_RANGE;
549210299Sed		goto clean_exit;
550210299Sed	}
551210299Sed
552193323Sed	if (ulDataLen > EC_MAX_DIGEST_LEN) {
553201360Srdivacky		rv = CKR_DATA_LEN_RANGE;
554193323Sed		goto clean_exit;
555193323Sed	}
556193323Sed
557193323Sed	/* structure assignment */
558201360Srdivacky	ECkey.ecParams = ecc_ctx->ecparams;
559201360Srdivacky
560210299Sed	template.type = CKA_EC_POINT;
561210299Sed	template.pValue = point;
562193323Sed	template.ulValueLen = sizeof (point);
563201360Srdivacky	rv = soft_get_public_key_attribute(key, &template);
564193323Sed	if (rv != CKR_OK) {
565193323Sed		goto clean_exit;
566193323Sed	}
567193323Sed
568201360Srdivacky	ECkey.publicValue.data = point;
569201360Srdivacky	ECkey.publicValue.len = template.ulValueLen;
570210299Sed
571210299Sed	signature_item.data = pSignature;
572193323Sed	signature_item.len = ulSignatureLen;
573201360Srdivacky
574193323Sed	digest_item.data = pData;
575193323Sed	digest_item.len = ulDataLen;
576193323Sed
577193323Sed	if (ECDSA_VerifyDigest(&ECkey, &signature_item, &digest_item, 0)
578201360Srdivacky	    != SECSuccess) {
579201360Srdivacky		rv = CKR_SIGNATURE_INVALID;
580210299Sed	} else {
581210299Sed		rv = CKR_OK;
582210299Sed	}
583210299Sed
584210299Sedclean_exit:
585210299Sed	(void) pthread_mutex_lock(&session_p->session_mutex);
586210299Sed	soft_free_ecc_context(session_p->verify.context);
587210299Sed	session_p->verify.context = NULL;
588210299Sed	(void) pthread_mutex_unlock(&session_p->session_mutex);
589210299Sed	return (rv);
590210299Sed}
591210299Sed
592193323Sed
593201360SrdivackyCK_RV
594193323Sedsoft_ecc_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
595193323Sed    CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
596193323Sed    CK_ULONG ulSignedLen, boolean_t Final)
597193323Sed{
598201360Srdivacky	CK_RV rv;
599201360Srdivacky	CK_BYTE hash[SHA1_HASH_SIZE];
600201360Srdivacky	CK_ULONG hash_len = SHA1_HASH_SIZE;
601210299Sed
602210299Sed	if (Final) {
603210299Sed		rv = soft_digest_final(session_p, hash, &hash_len);
604210299Sed	} else {
605210299Sed		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
606193323Sed	}
607201360Srdivacky
608193323Sed	if (rv != CKR_OK) {
609193323Sed		(void) pthread_mutex_lock(&session_p->session_mutex);
610193323Sed		soft_free_ecc_context(session_p->verify.context);
611193323Sed		session_p->verify.context = NULL;
612201360Srdivacky		session_p->digest.flags = 0;
613201360Srdivacky		(void) pthread_mutex_unlock(&session_p->session_mutex);
614201360Srdivacky		return (rv);
615210299Sed	}
616210299Sed
617210299Sed	/*
618210299Sed	 * Now, we are ready to verify the data using signature.
619210299Sed	 * soft_ecc_verify() will free the verification key.
620193323Sed	 */
621201360Srdivacky	rv = soft_ecc_verify(session_p, hash, hash_len,
622193323Sed	    pSigned, ulSignedLen);
623193323Sed
624193323Sedclean_exit:
625193323Sed	(void) pthread_mutex_lock(&session_p->session_mutex);
626201360Srdivacky	/* soft_digest_common() has freed the digest context */
627201360Srdivacky	session_p->digest.flags = 0;
628210299Sed	(void) pthread_mutex_unlock(&session_p->session_mutex);
629210299Sed	return (rv);
630210299Sed}
631210299Sed