1f9fbec18Smcpowers /*
2f9fbec18Smcpowers  * CDDL HEADER START
3f9fbec18Smcpowers  *
4f9fbec18Smcpowers  * The contents of this file are subject to the terms of the
5f9fbec18Smcpowers  * Common Development and Distribution License (the "License").
6f9fbec18Smcpowers  * You may not use this file except in compliance with the License.
7f9fbec18Smcpowers  *
8f9fbec18Smcpowers  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f9fbec18Smcpowers  * or http://www.opensolaris.org/os/licensing.
10f9fbec18Smcpowers  * See the License for the specific language governing permissions
11f9fbec18Smcpowers  * and limitations under the License.
12f9fbec18Smcpowers  *
13f9fbec18Smcpowers  * When distributing Covered Code, include this CDDL HEADER in each
14f9fbec18Smcpowers  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f9fbec18Smcpowers  * If applicable, add the following below this CDDL HEADER, with the
16f9fbec18Smcpowers  * fields enclosed by brackets "[]" replaced with your own identifying
17f9fbec18Smcpowers  * information: Portions Copyright [yyyy] [name of copyright owner]
18f9fbec18Smcpowers  *
19f9fbec18Smcpowers  * CDDL HEADER END
20f9fbec18Smcpowers  */
21f9fbec18Smcpowers /*
22*7b79d846SDina K Nimeh  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23f9fbec18Smcpowers  * Use is subject to license terms.
24f9fbec18Smcpowers  */
25f9fbec18Smcpowers 
26f9fbec18Smcpowers #include <stdlib.h>
27f9fbec18Smcpowers #include <string.h>
28f9fbec18Smcpowers #include <strings.h>
29f9fbec18Smcpowers #include <sys/types.h>
30f9fbec18Smcpowers #include <sys/crypto/common.h>
31f9fbec18Smcpowers #include <security/cryptoki.h>
32f9fbec18Smcpowers #include <bignum.h>
33f9fbec18Smcpowers #include <des_impl.h>
34f9fbec18Smcpowers #include "softGlobal.h"
35f9fbec18Smcpowers #include "softSession.h"
36f9fbec18Smcpowers #include "softObject.h"
37f9fbec18Smcpowers #include "softEC.h"
38f9fbec18Smcpowers #include "softCrypt.h"
39f9fbec18Smcpowers #include "softOps.h"
40f9fbec18Smcpowers #include "softMAC.h"
41f9fbec18Smcpowers 
42f9fbec18Smcpowers void
soft_free_ecparams(ECParams * params,boolean_t freeit)43f9fbec18Smcpowers soft_free_ecparams(ECParams *params, boolean_t freeit)
44f9fbec18Smcpowers {
45f9fbec18Smcpowers 	SECITEM_FreeItem(&params->fieldID.u.prime, B_FALSE);
46f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curve.a, B_FALSE);
47f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curve.b, B_FALSE);
48f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
49f9fbec18Smcpowers 	SECITEM_FreeItem(&params->base, B_FALSE);
50f9fbec18Smcpowers 	SECITEM_FreeItem(&params->order, B_FALSE);
51f9fbec18Smcpowers 	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
52f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curveOID, B_FALSE);
53f9fbec18Smcpowers 	if (freeit)
54f9fbec18Smcpowers 		free(params);
55f9fbec18Smcpowers }
56f9fbec18Smcpowers 
57f9fbec18Smcpowers static void
soft_free_ecc_context(soft_ecc_ctx_t * ecc_ctx)58f9fbec18Smcpowers soft_free_ecc_context(soft_ecc_ctx_t *ecc_ctx)
59f9fbec18Smcpowers {
60f9fbec18Smcpowers 	if (ecc_ctx != NULL) {
61f9fbec18Smcpowers 		if (ecc_ctx->key != NULL) {
62f9fbec18Smcpowers 			soft_cleanup_object(ecc_ctx->key);
63f9fbec18Smcpowers 			free(ecc_ctx->key);
64f9fbec18Smcpowers 		}
65f9fbec18Smcpowers 
66f9fbec18Smcpowers 		soft_free_ecparams(&ecc_ctx->ecparams, B_FALSE);
67f9fbec18Smcpowers 		free(ecc_ctx);
68f9fbec18Smcpowers 	}
69f9fbec18Smcpowers }
70f9fbec18Smcpowers 
71f9fbec18Smcpowers void
soft_free_ecprivkey(ECPrivateKey * key)72f9fbec18Smcpowers soft_free_ecprivkey(ECPrivateKey *key)
73f9fbec18Smcpowers {
74f9fbec18Smcpowers 	soft_free_ecparams(&key->ecParams, B_FALSE);
75f9fbec18Smcpowers 	/*
76f9fbec18Smcpowers 	 * Don't free publicValue or privateValue
77f9fbec18Smcpowers 	 * as these values are copied into objects.
78f9fbec18Smcpowers 	 */
79f9fbec18Smcpowers 	SECITEM_FreeItem(&key->version, B_FALSE);
80f9fbec18Smcpowers 	free(key);
81f9fbec18Smcpowers }
82f9fbec18Smcpowers 
83f9fbec18Smcpowers /*
84f9fbec18Smcpowers  * Called from init routines to do basic sanity checks. Init routines,
85f9fbec18Smcpowers  * e.g. sign_init should fail rather than subsequent operations.
86f9fbec18Smcpowers  */
87f9fbec18Smcpowers static int
check_key(soft_object_t * key_p,boolean_t sign)88f9fbec18Smcpowers check_key(soft_object_t *key_p, boolean_t sign)
89f9fbec18Smcpowers {
90f9fbec18Smcpowers 	biginteger_t *p;
91f9fbec18Smcpowers 	ulong_t len;
92f9fbec18Smcpowers 
93f9fbec18Smcpowers 	if (sign) {
94f9fbec18Smcpowers 		if ((key_p->class != CKO_PRIVATE_KEY) ||
95f9fbec18Smcpowers 		    (key_p->key_type != CKK_EC))
96f9fbec18Smcpowers 			return (CKR_KEY_TYPE_INCONSISTENT);
97f9fbec18Smcpowers 
98f9fbec18Smcpowers 		p = OBJ_PRI_EC_VALUE(key_p);
99f9fbec18Smcpowers 		len = p->big_value_len;
100f9fbec18Smcpowers 		if (p->big_value == NULL)
101f9fbec18Smcpowers 			len = 0;
102f9fbec18Smcpowers 
103f9fbec18Smcpowers 		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) ||
104f9fbec18Smcpowers 		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN))
105f9fbec18Smcpowers 			return (CKR_KEY_SIZE_RANGE);
106f9fbec18Smcpowers 	} else {
107f9fbec18Smcpowers 		if ((key_p->class != CKO_PUBLIC_KEY) ||
108f9fbec18Smcpowers 		    (key_p->key_type != CKK_EC))
109f9fbec18Smcpowers 			return (CKR_KEY_TYPE_INCONSISTENT);
110f9fbec18Smcpowers 
111f9fbec18Smcpowers 		p = OBJ_PUB_EC_POINT(key_p);
112f9fbec18Smcpowers 		len = p->big_value_len;
113f9fbec18Smcpowers 		if (p->big_value == NULL)
114f9fbec18Smcpowers 			len = 0;
115f9fbec18Smcpowers 
116f9fbec18Smcpowers 		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) * 2 + 1 ||
117f9fbec18Smcpowers 		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN) * 2 + 1)
118f9fbec18Smcpowers 			return (CKR_KEY_SIZE_RANGE);
119f9fbec18Smcpowers 	}
120f9fbec18Smcpowers 
121f9fbec18Smcpowers 	return (CKR_OK);
122f9fbec18Smcpowers }
123f9fbec18Smcpowers 
124f9fbec18Smcpowers /*
125f9fbec18Smcpowers  * This function places the octet string of the specified attribute
126f9fbec18Smcpowers  * into the corresponding key object.
127f9fbec18Smcpowers  */
128f9fbec18Smcpowers static void
soft_genECkey_set_attribute(soft_object_t * key,biginteger_t * bi,CK_ATTRIBUTE_TYPE type)129f9fbec18Smcpowers soft_genECkey_set_attribute(soft_object_t *key, biginteger_t *bi,
130f9fbec18Smcpowers     CK_ATTRIBUTE_TYPE type)
131f9fbec18Smcpowers {
132f9fbec18Smcpowers 	biginteger_t *dst;
133f9fbec18Smcpowers 
134f9fbec18Smcpowers 	switch (type) {
135f9fbec18Smcpowers 	case CKA_VALUE:
136f9fbec18Smcpowers 		dst = OBJ_PRI_EC_VALUE(key);
137f9fbec18Smcpowers 		break;
138f9fbec18Smcpowers 
139f9fbec18Smcpowers 	case CKA_EC_POINT:
140f9fbec18Smcpowers 		dst = OBJ_PUB_EC_POINT(key);
141f9fbec18Smcpowers 		break;
142f9fbec18Smcpowers 	}
143f9fbec18Smcpowers 	copy_bigint_attr(bi, dst);
144f9fbec18Smcpowers }
145f9fbec18Smcpowers 
146f9fbec18Smcpowers CK_RV
soft_ec_genkey_pair(soft_object_t * pubkey,soft_object_t * prikey)147f9fbec18Smcpowers soft_ec_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
148f9fbec18Smcpowers {
149f9fbec18Smcpowers 	CK_RV rv;
150f9fbec18Smcpowers 	CK_ATTRIBUTE template;
151f9fbec18Smcpowers 	ECPrivateKey *privKey;	/* contains both public and private values */
152f9fbec18Smcpowers 	ECParams *ecparams;
153f9fbec18Smcpowers 	SECKEYECParams params_item;
154f9fbec18Smcpowers 	biginteger_t bi;
155f9fbec18Smcpowers 	uchar_t param_buffer[EC_MAX_OID_LEN];
156f9fbec18Smcpowers 	uint_t paramlen;
157f9fbec18Smcpowers 
158f9fbec18Smcpowers 	if ((pubkey->class != CKO_PUBLIC_KEY) ||
159f9fbec18Smcpowers 	    (pubkey->key_type != CKK_EC))
160f9fbec18Smcpowers 		return (CKR_KEY_TYPE_INCONSISTENT);
161f9fbec18Smcpowers 
162f9fbec18Smcpowers 	if ((prikey->class != CKO_PRIVATE_KEY) ||
163f9fbec18Smcpowers 	    (prikey->key_type != CKK_EC))
164f9fbec18Smcpowers 		return (CKR_KEY_TYPE_INCONSISTENT);
165f9fbec18Smcpowers 
166f9fbec18Smcpowers 	template.type = CKA_EC_PARAMS;
167f9fbec18Smcpowers 	template.pValue = param_buffer;
168f9fbec18Smcpowers 	template.ulValueLen = sizeof (param_buffer);
169f9fbec18Smcpowers 	rv = soft_get_public_key_attribute(pubkey, &template);
170f9fbec18Smcpowers 	if (rv != CKR_OK) {
171f9fbec18Smcpowers 		return (rv);
172f9fbec18Smcpowers 	}
173f9fbec18Smcpowers 	paramlen = template.ulValueLen;
174f9fbec18Smcpowers 
175f9fbec18Smcpowers 	/* private key also has CKA_EC_PARAMS attribute */
176f9fbec18Smcpowers 	rv = set_extra_attr_to_object(prikey, CKA_EC_PARAMS, &template);
177f9fbec18Smcpowers 	if (rv != CKR_OK) {
178f9fbec18Smcpowers 		return (rv);
179f9fbec18Smcpowers 	}
180f9fbec18Smcpowers 
181f9fbec18Smcpowers 	/* ASN1 check */
182f9fbec18Smcpowers 	if (param_buffer[0] != 0x06 ||
183f9fbec18Smcpowers 	    param_buffer[1] != paramlen - 2) {
184f9fbec18Smcpowers 		return (CKR_ATTRIBUTE_VALUE_INVALID);
185f9fbec18Smcpowers 	}
186f9fbec18Smcpowers 	params_item.len = paramlen;
187f9fbec18Smcpowers 	params_item.data = param_buffer;
188f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
189f9fbec18Smcpowers 		/* bad curve OID */
190f9fbec18Smcpowers 		return (CKR_ARGUMENTS_BAD);
191f9fbec18Smcpowers 	}
192f9fbec18Smcpowers 
193f9fbec18Smcpowers 	if (EC_NewKey(ecparams, &privKey, 0) != SECSuccess) {
194f9fbec18Smcpowers 		soft_free_ecparams(ecparams, B_TRUE);
195f9fbec18Smcpowers 		return (CKR_FUNCTION_FAILED);
196f9fbec18Smcpowers 	}
197f9fbec18Smcpowers 
198f9fbec18Smcpowers 	bi.big_value = privKey->privateValue.data;
199f9fbec18Smcpowers 	bi.big_value_len = privKey->privateValue.len;
200f9fbec18Smcpowers 	soft_genECkey_set_attribute(prikey, &bi, CKA_VALUE);
201f9fbec18Smcpowers 
202f9fbec18Smcpowers 	bi.big_value = privKey->publicValue.data;
203f9fbec18Smcpowers 	bi.big_value_len = privKey->publicValue.len;
204f9fbec18Smcpowers 	soft_genECkey_set_attribute(pubkey, &bi, CKA_EC_POINT);
205f9fbec18Smcpowers 
206f9fbec18Smcpowers 	soft_free_ecprivkey(privKey);
207f9fbec18Smcpowers 	soft_free_ecparams(ecparams, B_TRUE);
208f9fbec18Smcpowers 
209f9fbec18Smcpowers 	return (CKR_OK);
210f9fbec18Smcpowers }
211f9fbec18Smcpowers 
212f9fbec18Smcpowers CK_RV
soft_ec_key_derive(soft_object_t * basekey,soft_object_t * secretkey,void * mech_params,size_t mech_params_len)213f9fbec18Smcpowers soft_ec_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
214f9fbec18Smcpowers     void *mech_params, size_t mech_params_len)
215f9fbec18Smcpowers {
216f9fbec18Smcpowers 	CK_RV		rv;
217f9fbec18Smcpowers 	CK_ATTRIBUTE	template;
218f9fbec18Smcpowers 	CK_ECDH1_DERIVE_PARAMS *ecdh1_derive_params = mech_params;
219f9fbec18Smcpowers 	uchar_t		value[EC_MAX_VALUE_LEN];
220f9fbec18Smcpowers 	uint32_t	value_len = sizeof (value);
221f9fbec18Smcpowers 	uchar_t		params[EC_MAX_OID_LEN];
222f9fbec18Smcpowers 	uint32_t	params_len = sizeof (params);
223f9fbec18Smcpowers 	uint32_t	keylen;
224f9fbec18Smcpowers 	ECParams	*ecparams;
225f9fbec18Smcpowers 	SECKEYECParams	params_item;
226f9fbec18Smcpowers 	SECItem		public_value_item, private_value_item, secret_item;
227f9fbec18Smcpowers 	uchar_t		*buf;
228f9fbec18Smcpowers 
229f9fbec18Smcpowers 	if (mech_params_len != sizeof (CK_ECDH1_DERIVE_PARAMS) ||
230f9fbec18Smcpowers 	    ecdh1_derive_params->kdf != CKD_NULL) {
231f9fbec18Smcpowers 		return (CKR_MECHANISM_PARAM_INVALID);
232f9fbec18Smcpowers 	}
233f9fbec18Smcpowers 
234f9fbec18Smcpowers 	template.type = CKA_VALUE;
235f9fbec18Smcpowers 	template.pValue = value;
236f9fbec18Smcpowers 	template.ulValueLen = value_len;
237f9fbec18Smcpowers 	rv = soft_get_private_key_attribute(basekey, &template);
238f9fbec18Smcpowers 	if (rv != CKR_OK) {
239f9fbec18Smcpowers 		return (rv);
240f9fbec18Smcpowers 	}
241f9fbec18Smcpowers 	value_len = template.ulValueLen;
242f9fbec18Smcpowers 	private_value_item.data = value;
243f9fbec18Smcpowers 	private_value_item.len = value_len;
244f9fbec18Smcpowers 
245f9fbec18Smcpowers 	template.type = CKA_EC_PARAMS;
246f9fbec18Smcpowers 	template.pValue = params;
247f9fbec18Smcpowers 	template.ulValueLen = params_len;
248f9fbec18Smcpowers 	rv = soft_get_private_key_attribute(basekey, &template);
249f9fbec18Smcpowers 	if (rv != CKR_OK) {
250f9fbec18Smcpowers 		return (rv);
251f9fbec18Smcpowers 	}
252f9fbec18Smcpowers 	params_len = template.ulValueLen;
253f9fbec18Smcpowers 
254f9fbec18Smcpowers 	switch (secretkey->key_type) {
255f9fbec18Smcpowers 	case CKK_DES:
256f9fbec18Smcpowers 		keylen = DES_KEYSIZE;
257f9fbec18Smcpowers 		break;
258f9fbec18Smcpowers 	case CKK_DES2:
259f9fbec18Smcpowers 		keylen = DES2_KEYSIZE;
260f9fbec18Smcpowers 		break;
261f9fbec18Smcpowers 	case CKK_DES3:
262f9fbec18Smcpowers 		keylen = DES3_KEYSIZE;
263f9fbec18Smcpowers 		break;
264f9fbec18Smcpowers 	case CKK_RC4:
265f9fbec18Smcpowers 	case CKK_AES:
266f9fbec18Smcpowers 	case CKK_GENERIC_SECRET:
267f9fbec18Smcpowers #ifdef	__sparcv9
268f9fbec18Smcpowers 		/* LINTED */
269f9fbec18Smcpowers 		keylen = (uint32_t)OBJ_SEC_VALUE_LEN(secretkey);
270f9fbec18Smcpowers #else	/* !__sparcv9 */
271f9fbec18Smcpowers 		keylen = OBJ_SEC_VALUE_LEN(secretkey);
272f9fbec18Smcpowers #endif	/* __sparcv9 */
273f9fbec18Smcpowers 		break;
274f9fbec18Smcpowers 	}
275f9fbec18Smcpowers 
276f9fbec18Smcpowers 	/* ASN1 check */
277f9fbec18Smcpowers 	if (params[0] != 0x06 ||
278f9fbec18Smcpowers 	    params[1] != params_len - 2) {
279f9fbec18Smcpowers 		return (CKR_ATTRIBUTE_VALUE_INVALID);
280f9fbec18Smcpowers 	}
281f9fbec18Smcpowers 	params_item.data = params;
282f9fbec18Smcpowers 	params_item.len = params_len;
283f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
284f9fbec18Smcpowers 		/* bad curve OID */
285f9fbec18Smcpowers 		return (CKR_ARGUMENTS_BAD);
286f9fbec18Smcpowers 	}
287f9fbec18Smcpowers 
288f9fbec18Smcpowers 	public_value_item.data = ecdh1_derive_params->pPublicData;
289f9fbec18Smcpowers 	public_value_item.len = ecdh1_derive_params->ulPublicDataLen;
290f9fbec18Smcpowers 
291f9fbec18Smcpowers 	secret_item.data = NULL;
292f9fbec18Smcpowers 	secret_item.len = 0;
293f9fbec18Smcpowers 
294f9fbec18Smcpowers 	if (ECDH_Derive(&public_value_item, ecparams, &private_value_item,
295f9fbec18Smcpowers 	    B_FALSE, &secret_item, 0) != SECSuccess) {
296f9fbec18Smcpowers 		soft_free_ecparams(ecparams, B_TRUE);
297f9fbec18Smcpowers 		return (CKR_FUNCTION_FAILED);
298f9fbec18Smcpowers 	} else {
299f9fbec18Smcpowers 		rv = CKR_OK;
300f9fbec18Smcpowers 	}
301f9fbec18Smcpowers 
302f9fbec18Smcpowers 	if (keylen == 0)
303f9fbec18Smcpowers 		keylen = secret_item.len;
304f9fbec18Smcpowers 
305f9fbec18Smcpowers 	if (keylen > secret_item.len) {
306f9fbec18Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
307f9fbec18Smcpowers 		goto out;
308f9fbec18Smcpowers 	}
309f9fbec18Smcpowers 	buf = malloc(keylen);
310f9fbec18Smcpowers 	if (buf == NULL) {
311f9fbec18Smcpowers 		rv = CKR_HOST_MEMORY;
312f9fbec18Smcpowers 		goto out;
313f9fbec18Smcpowers 	}
314f9fbec18Smcpowers 	bcopy(secret_item.data + secret_item.len - keylen, buf, keylen);
315f9fbec18Smcpowers 	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
316f9fbec18Smcpowers 	OBJ_SEC_VALUE(secretkey) = buf;
317f9fbec18Smcpowers 
318f9fbec18Smcpowers out:
319f9fbec18Smcpowers 	soft_free_ecparams(ecparams, B_TRUE);
320f9fbec18Smcpowers 	SECITEM_FreeItem(&secret_item, B_FALSE);
321f9fbec18Smcpowers 
322f9fbec18Smcpowers 	return (rv);
323f9fbec18Smcpowers }
324f9fbec18Smcpowers 
325f9fbec18Smcpowers /*
326f9fbec18Smcpowers  * Allocate a ECC context for the active sign or verify operation.
327f9fbec18Smcpowers  * This function is called without the session lock held.
328f9fbec18Smcpowers  */
329f9fbec18Smcpowers CK_RV
soft_ecc_sign_verify_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t sign)330f9fbec18Smcpowers soft_ecc_sign_verify_init_common(soft_session_t *session_p,
331f9fbec18Smcpowers     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
332f9fbec18Smcpowers     boolean_t sign)
333f9fbec18Smcpowers {
334f9fbec18Smcpowers 	CK_RV rv;
335f9fbec18Smcpowers 	CK_ATTRIBUTE template;
336f9fbec18Smcpowers 	CK_MECHANISM digest_mech;
337f9fbec18Smcpowers 	soft_ecc_ctx_t *ecc_ctx;
338f9fbec18Smcpowers 	soft_object_t *tmp_key = NULL;
339f9fbec18Smcpowers 	uchar_t params[EC_MAX_OID_LEN];
340f9fbec18Smcpowers 	ECParams *ecparams;
341f9fbec18Smcpowers 	SECKEYECParams params_item;
342f9fbec18Smcpowers 
343f9fbec18Smcpowers 	if ((rv = check_key(key_p, sign)) != CKR_OK)
344f9fbec18Smcpowers 		return (rv);
345f9fbec18Smcpowers 
346f9fbec18Smcpowers 	if (pMechanism->mechanism == CKM_ECDSA_SHA1) {
347f9fbec18Smcpowers 		digest_mech.mechanism = CKM_SHA_1;
348f9fbec18Smcpowers 		rv = soft_digest_init_internal(session_p, &digest_mech);
349f9fbec18Smcpowers 		if (rv != CKR_OK)
350f9fbec18Smcpowers 			return (rv);
351f9fbec18Smcpowers 	}
352f9fbec18Smcpowers 
353f9fbec18Smcpowers 	ecc_ctx = malloc(sizeof (soft_ecc_ctx_t));
354f9fbec18Smcpowers 	if (ecc_ctx == NULL) {
355f9fbec18Smcpowers 		return (CKR_HOST_MEMORY);
356f9fbec18Smcpowers 	}
357f9fbec18Smcpowers 
358f9fbec18Smcpowers 	/*
359f9fbec18Smcpowers 	 * Make a copy of the signature or verification key, and save it
360f9fbec18Smcpowers 	 * in the ECC crypto context since it will be used later for
361f9fbec18Smcpowers 	 * signing/verification. We don't want to hold any object reference
362f9fbec18Smcpowers 	 * on this original key while doing signing/verification.
363f9fbec18Smcpowers 	 */
364f9fbec18Smcpowers 	(void) pthread_mutex_lock(&key_p->object_mutex);
365f9fbec18Smcpowers 	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH, NULL);
366f9fbec18Smcpowers 	if ((rv != CKR_OK) || (tmp_key == NULL)) {
367f9fbec18Smcpowers 		/* Most likely we ran out of space. */
368f9fbec18Smcpowers 		(void) pthread_mutex_unlock(&key_p->object_mutex);
369f9fbec18Smcpowers 		free(ecc_ctx);
370f9fbec18Smcpowers 		return (rv);
371f9fbec18Smcpowers 	}
372f9fbec18Smcpowers 
373f9fbec18Smcpowers 
374f9fbec18Smcpowers 	template.type = CKA_EC_PARAMS;
375f9fbec18Smcpowers 	template.pValue = params;
376f9fbec18Smcpowers 	template.ulValueLen = sizeof (params);
377f9fbec18Smcpowers 	rv = soft_get_private_key_attribute(key_p, &template);
378f9fbec18Smcpowers 	(void) pthread_mutex_unlock(&key_p->object_mutex);
379f9fbec18Smcpowers 	if (rv != CKR_OK) {
380f9fbec18Smcpowers 		goto out;
381f9fbec18Smcpowers 	}
382f9fbec18Smcpowers 
383f9fbec18Smcpowers 	/* ASN1 check */
384f9fbec18Smcpowers 	if (params[0] != 0x06 ||
385f9fbec18Smcpowers 	    params[1] != template.ulValueLen - 2) {
386f9fbec18Smcpowers 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
387f9fbec18Smcpowers 		goto out;
388f9fbec18Smcpowers 	}
389f9fbec18Smcpowers 	params_item.data = params;
390f9fbec18Smcpowers 	params_item.len = template.ulValueLen;
391f9fbec18Smcpowers 
392f9fbec18Smcpowers 	ecc_ctx->key = tmp_key;
393f9fbec18Smcpowers 
394f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
395f9fbec18Smcpowers 		/* bad curve OID */
396f9fbec18Smcpowers 		rv = CKR_ARGUMENTS_BAD;
397f9fbec18Smcpowers 		goto out;
398f9fbec18Smcpowers 	}
399f9fbec18Smcpowers 	ecc_ctx->ecparams = *ecparams;
400f9fbec18Smcpowers 	free(ecparams);
401f9fbec18Smcpowers 
402f9fbec18Smcpowers 	(void) pthread_mutex_lock(&session_p->session_mutex);
403f9fbec18Smcpowers 
404f9fbec18Smcpowers 	if (sign) {
405f9fbec18Smcpowers 		session_p->sign.context = ecc_ctx;
406f9fbec18Smcpowers 		session_p->sign.mech.mechanism = pMechanism->mechanism;
407f9fbec18Smcpowers 	} else {
408f9fbec18Smcpowers 		session_p->verify.context = ecc_ctx;
409f9fbec18Smcpowers 		session_p->verify.mech.mechanism = pMechanism->mechanism;
410f9fbec18Smcpowers 	}
411f9fbec18Smcpowers 
412f9fbec18Smcpowers 	(void) pthread_mutex_unlock(&session_p->session_mutex);
413f9fbec18Smcpowers 	return (CKR_OK);
414f9fbec18Smcpowers 
415f9fbec18Smcpowers out:
416f9fbec18Smcpowers 	soft_cleanup_object(tmp_key);
417f9fbec18Smcpowers 	free(tmp_key);
418f9fbec18Smcpowers 	free(ecc_ctx);
419f9fbec18Smcpowers 
420f9fbec18Smcpowers 	return (rv);
421f9fbec18Smcpowers }
422f9fbec18Smcpowers 
423f9fbec18Smcpowers CK_RV
soft_ecc_digest_sign_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen,boolean_t Final)424f9fbec18Smcpowers soft_ecc_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
425f9fbec18Smcpowers     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
426f9fbec18Smcpowers     CK_ULONG_PTR pulSignedLen, boolean_t Final)
427f9fbec18Smcpowers {
428f9fbec18Smcpowers 	CK_RV rv = CKR_OK;
429f9fbec18Smcpowers 	CK_BYTE hash[SHA1_HASH_SIZE];
430f9fbec18Smcpowers 	CK_ULONG hash_len = SHA1_HASH_SIZE;
431f9fbec18Smcpowers 
432f9fbec18Smcpowers 	if (pSigned != NULL) {
433f9fbec18Smcpowers 		if (Final) {
434f9fbec18Smcpowers 			rv = soft_digest_final(session_p, hash, &hash_len);
435f9fbec18Smcpowers 		} else {
436f9fbec18Smcpowers 			rv = soft_digest(session_p, pData, ulDataLen, hash,
437f9fbec18Smcpowers 			    &hash_len);
438f9fbec18Smcpowers 		}
439f9fbec18Smcpowers 
440f9fbec18Smcpowers 		if (rv != CKR_OK) {
441f9fbec18Smcpowers 			(void) pthread_mutex_lock(&session_p->session_mutex);
442f9fbec18Smcpowers 			soft_free_ecc_context(session_p->sign.context);
443f9fbec18Smcpowers 			session_p->sign.context = NULL;
444f9fbec18Smcpowers 			session_p->digest.flags = 0;
445f9fbec18Smcpowers 			(void) pthread_mutex_unlock(&session_p->session_mutex);
446f9fbec18Smcpowers 			return (rv);
447f9fbec18Smcpowers 		}
448f9fbec18Smcpowers 	}
449f9fbec18Smcpowers 
450f9fbec18Smcpowers 	rv = soft_ecc_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
451f9fbec18Smcpowers 
452f9fbec18Smcpowers clean_exit:
453f9fbec18Smcpowers 	(void) pthread_mutex_lock(&session_p->session_mutex);
454f9fbec18Smcpowers 	/* soft_digest_common() has freed the digest context */
455f9fbec18Smcpowers 	session_p->digest.flags = 0;
456f9fbec18Smcpowers 	(void) pthread_mutex_unlock(&session_p->session_mutex);
457f9fbec18Smcpowers 
458f9fbec18Smcpowers clean1:
459f9fbec18Smcpowers 	return (rv);
460f9fbec18Smcpowers }
461f9fbec18Smcpowers 
462f9fbec18Smcpowers CK_RV
soft_ecc_sign(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen)463f9fbec18Smcpowers soft_ecc_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
464f9fbec18Smcpowers     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
465f9fbec18Smcpowers     CK_ULONG_PTR pulSignedLen)
466f9fbec18Smcpowers {
467f9fbec18Smcpowers 	CK_RV rv = CKR_OK;
468f9fbec18Smcpowers 	SECStatus ss;
469f9fbec18Smcpowers 	soft_ecc_ctx_t *ecc_ctx = session_p->sign.context;
470f9fbec18Smcpowers 	soft_object_t *key = ecc_ctx->key;
471f9fbec18Smcpowers 	uchar_t value[EC_MAX_VALUE_LEN];
472f9fbec18Smcpowers 	ECPrivateKey ECkey;
473f9fbec18Smcpowers 	SECItem signature_item;
474f9fbec18Smcpowers 	SECItem digest_item;
475c64d15a5Smcpowers 	uint_t value_len;
476f9fbec18Smcpowers 
477f9fbec18Smcpowers 	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_EC)) {
478f9fbec18Smcpowers 		rv = CKR_KEY_TYPE_INCONSISTENT;
479f9fbec18Smcpowers 		goto clean_exit;
480f9fbec18Smcpowers 	}
481f9fbec18Smcpowers 
482f9fbec18Smcpowers 	if (ulDataLen > EC_MAX_DIGEST_LEN) {
483f9fbec18Smcpowers 		rv = CKR_DATA_LEN_RANGE;
484f9fbec18Smcpowers 		goto clean_exit;
485f9fbec18Smcpowers 	}
486f9fbec18Smcpowers 
487f9fbec18Smcpowers 	/* structure assignment */
488f9fbec18Smcpowers 	ECkey.ecParams = ecc_ctx->ecparams;
489f9fbec18Smcpowers 
490c64d15a5Smcpowers 	value_len = EC_MAX_VALUE_LEN;
491c64d15a5Smcpowers 	rv = soft_get_private_value(key, CKA_VALUE, value, &value_len);
492f9fbec18Smcpowers 	if (rv != CKR_OK) {
493f9fbec18Smcpowers 		goto clean_exit;
494f9fbec18Smcpowers 	}
495f9fbec18Smcpowers 
496f9fbec18Smcpowers 	ECkey.privateValue.data = value;
497c64d15a5Smcpowers 	ECkey.privateValue.len = value_len;
498f9fbec18Smcpowers 
499f9fbec18Smcpowers 	signature_item.data = pSigned;
500f9fbec18Smcpowers 	signature_item.len = *pulSignedLen;
501f9fbec18Smcpowers 
502f9fbec18Smcpowers 	digest_item.data = pData;
503f9fbec18Smcpowers 	digest_item.len = ulDataLen;
504f9fbec18Smcpowers 
505f9fbec18Smcpowers 	if ((ss = ECDSA_SignDigest(&ECkey, &signature_item, &digest_item, 0))
506f9fbec18Smcpowers 	    != SECSuccess) {
507f9fbec18Smcpowers 		if (ss == SECBufferTooSmall)
508f9fbec18Smcpowers 			return (CKR_BUFFER_TOO_SMALL);
509f9fbec18Smcpowers 
510f9fbec18Smcpowers 		rv = CKR_FUNCTION_FAILED;
511f9fbec18Smcpowers 		goto clean_exit;
512f9fbec18Smcpowers 	}
513f9fbec18Smcpowers 
514f9fbec18Smcpowers 	if (rv == CKR_OK) {
515f9fbec18Smcpowers 		*pulSignedLen = signature_item.len;
516f9fbec18Smcpowers 		if (pSigned == NULL)
517f9fbec18Smcpowers 			return (rv);
518f9fbec18Smcpowers 	}
519f9fbec18Smcpowers 
520f9fbec18Smcpowers clean_exit:
521f9fbec18Smcpowers 	(void) pthread_mutex_lock(&session_p->session_mutex);
522f9fbec18Smcpowers 	soft_free_ecc_context(session_p->sign.context);
523f9fbec18Smcpowers 	session_p->sign.context = NULL;
524f9fbec18Smcpowers 	(void) pthread_mutex_unlock(&session_p->session_mutex);
525f9fbec18Smcpowers 	return (rv);
526f9fbec18Smcpowers }
527f9fbec18Smcpowers 
528f9fbec18Smcpowers CK_RV
soft_ecc_verify(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)529f9fbec18Smcpowers soft_ecc_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
530f9fbec18Smcpowers     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
531f9fbec18Smcpowers     CK_ULONG ulSignatureLen)
532f9fbec18Smcpowers {
533f9fbec18Smcpowers 	CK_RV rv = CKR_OK;
534f9fbec18Smcpowers 	soft_ecc_ctx_t *ecc_ctx = session_p->verify.context;
535f9fbec18Smcpowers 	soft_object_t *key = ecc_ctx->key;
536f9fbec18Smcpowers 	uchar_t point[EC_MAX_POINT_LEN];
537f9fbec18Smcpowers 	CK_ATTRIBUTE template;
538f9fbec18Smcpowers 	ECPublicKey ECkey;
539f9fbec18Smcpowers 	SECItem signature_item;
540f9fbec18Smcpowers 	SECItem digest_item;
541f9fbec18Smcpowers 
542f9fbec18Smcpowers 	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_EC)) {
543f9fbec18Smcpowers 		rv = CKR_KEY_TYPE_INCONSISTENT;
544f9fbec18Smcpowers 		goto clean_exit;
545f9fbec18Smcpowers 	}
546f9fbec18Smcpowers 
547f9fbec18Smcpowers 	if (ulSignatureLen > EC_MAX_SIG_LEN) {
548f9fbec18Smcpowers 		rv = CKR_SIGNATURE_LEN_RANGE;
549f9fbec18Smcpowers 		goto clean_exit;
550f9fbec18Smcpowers 	}
551f9fbec18Smcpowers 
552f9fbec18Smcpowers 	if (ulDataLen > EC_MAX_DIGEST_LEN) {
553f9fbec18Smcpowers 		rv = CKR_DATA_LEN_RANGE;
554f9fbec18Smcpowers 		goto clean_exit;
555f9fbec18Smcpowers 	}
556f9fbec18Smcpowers 
557f9fbec18Smcpowers 	/* structure assignment */
558f9fbec18Smcpowers 	ECkey.ecParams = ecc_ctx->ecparams;
559f9fbec18Smcpowers 
560f9fbec18Smcpowers 	template.type = CKA_EC_POINT;
561f9fbec18Smcpowers 	template.pValue = point;
562f9fbec18Smcpowers 	template.ulValueLen = sizeof (point);
563f9fbec18Smcpowers 	rv = soft_get_public_key_attribute(key, &template);
564f9fbec18Smcpowers 	if (rv != CKR_OK) {
565f9fbec18Smcpowers 		goto clean_exit;
566f9fbec18Smcpowers 	}
567f9fbec18Smcpowers 
568f9fbec18Smcpowers 	ECkey.publicValue.data = point;
569f9fbec18Smcpowers 	ECkey.publicValue.len = template.ulValueLen;
570f9fbec18Smcpowers 
571f9fbec18Smcpowers 	signature_item.data = pSignature;
572f9fbec18Smcpowers 	signature_item.len = ulSignatureLen;
573f9fbec18Smcpowers 
574f9fbec18Smcpowers 	digest_item.data = pData;
575f9fbec18Smcpowers 	digest_item.len = ulDataLen;
576f9fbec18Smcpowers 
577f9fbec18Smcpowers 	if (ECDSA_VerifyDigest(&ECkey, &signature_item, &digest_item, 0)
578f9fbec18Smcpowers 	    != SECSuccess) {
579f9fbec18Smcpowers 		rv = CKR_SIGNATURE_INVALID;
580f9fbec18Smcpowers 	} else {
581f9fbec18Smcpowers 		rv = CKR_OK;
582f9fbec18Smcpowers 	}
583f9fbec18Smcpowers 
584f9fbec18Smcpowers clean_exit:
585f9fbec18Smcpowers 	(void) pthread_mutex_lock(&session_p->session_mutex);
586f9fbec18Smcpowers 	soft_free_ecc_context(session_p->verify.context);
587f9fbec18Smcpowers 	session_p->verify.context = NULL;
588f9fbec18Smcpowers 	(void) pthread_mutex_unlock(&session_p->session_mutex);
589f9fbec18Smcpowers 	return (rv);
590f9fbec18Smcpowers }
591f9fbec18Smcpowers 
592f9fbec18Smcpowers 
593f9fbec18Smcpowers CK_RV
soft_ecc_digest_verify_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG ulSignedLen,boolean_t Final)594f9fbec18Smcpowers soft_ecc_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
595f9fbec18Smcpowers     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
596f9fbec18Smcpowers     CK_ULONG ulSignedLen, boolean_t Final)
597f9fbec18Smcpowers {
598f9fbec18Smcpowers 	CK_RV rv;
599f9fbec18Smcpowers 	CK_BYTE hash[SHA1_HASH_SIZE];
600f9fbec18Smcpowers 	CK_ULONG hash_len = SHA1_HASH_SIZE;
601f9fbec18Smcpowers 
602f9fbec18Smcpowers 	if (Final) {
603f9fbec18Smcpowers 		rv = soft_digest_final(session_p, hash, &hash_len);
604f9fbec18Smcpowers 	} else {
605f9fbec18Smcpowers 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
606f9fbec18Smcpowers 	}
607f9fbec18Smcpowers 
608f9fbec18Smcpowers 	if (rv != CKR_OK) {
609f9fbec18Smcpowers 		(void) pthread_mutex_lock(&session_p->session_mutex);
610f9fbec18Smcpowers 		soft_free_ecc_context(session_p->verify.context);
611f9fbec18Smcpowers 		session_p->verify.context = NULL;
612f9fbec18Smcpowers 		session_p->digest.flags = 0;
613f9fbec18Smcpowers 		(void) pthread_mutex_unlock(&session_p->session_mutex);
614f9fbec18Smcpowers 		return (rv);
615f9fbec18Smcpowers 	}
616f9fbec18Smcpowers 
617f9fbec18Smcpowers 	/*
618f9fbec18Smcpowers 	 * Now, we are ready to verify the data using signature.
619f9fbec18Smcpowers 	 * soft_ecc_verify() will free the verification key.
620f9fbec18Smcpowers 	 */
621f9fbec18Smcpowers 	rv = soft_ecc_verify(session_p, hash, hash_len,
622f9fbec18Smcpowers 	    pSigned, ulSignedLen);
623f9fbec18Smcpowers 
624f9fbec18Smcpowers clean_exit:
625f9fbec18Smcpowers 	(void) pthread_mutex_lock(&session_p->session_mutex);
626f9fbec18Smcpowers 	/* soft_digest_common() has freed the digest context */
627f9fbec18Smcpowers 	session_p->digest.flags = 0;
628f9fbec18Smcpowers 	(void) pthread_mutex_unlock(&session_p->session_mutex);
629f9fbec18Smcpowers 	return (rv);
630f9fbec18Smcpowers }
631