xref: /illumos-gate/usr/src/uts/common/crypto/io/ecc.c (revision 3ec36537)
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 /*
22d3b2efc7SAnthony Scarpino  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23f9fbec18Smcpowers  * Use is subject to license terms.
24f9fbec18Smcpowers  */
256ea3c060SGarrett D'Amore /*
266ea3c060SGarrett D'Amore  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
276ea3c060SGarrett D'Amore  */
28f9fbec18Smcpowers 
29f9fbec18Smcpowers #include <sys/types.h>
30f9fbec18Smcpowers #include <sys/systm.h>
31f9fbec18Smcpowers #include <sys/param.h>
32f9fbec18Smcpowers #include <sys/modctl.h>
33f9fbec18Smcpowers #include <sys/ddi.h>
34f9fbec18Smcpowers #include <sys/crypto/spi.h>
3523c57df7Smcpowers #include <sys/crypto/impl.h>
36b5a2d845SHai-May Chao #include <sys/crypto/ioctladmin.h>
37f9fbec18Smcpowers #include <sys/sysmacros.h>
38f9fbec18Smcpowers #include <sys/strsun.h>
39f9fbec18Smcpowers #include <sys/sha1.h>
40f9fbec18Smcpowers #include <sys/random.h>
41f9fbec18Smcpowers #include <sys/conf.h>
42f9fbec18Smcpowers #include <sys/devops.h>
43f9fbec18Smcpowers #include <sys/sunddi.h>
44f9fbec18Smcpowers #include <sys/varargs.h>
45f9fbec18Smcpowers #include <sys/kmem.h>
46f9fbec18Smcpowers #include <sys/kstat.h>
47f9fbec18Smcpowers 
48b5a2d845SHai-May Chao #include <des/des_impl.h>
49b5a2d845SHai-May Chao #include <ecc/ecc_impl.h>
50f9fbec18Smcpowers 
51f9fbec18Smcpowers #define	CKD_NULL		0x00000001
52f9fbec18Smcpowers 
53f9fbec18Smcpowers extern struct mod_ops mod_cryptoops;
54f9fbec18Smcpowers 
55f9fbec18Smcpowers /*
56f9fbec18Smcpowers  * Module linkage information for the kernel.
57f9fbec18Smcpowers  */
58f9fbec18Smcpowers static struct modlcrypto modlcrypto = {
59f9fbec18Smcpowers 	&mod_cryptoops,
60f9fbec18Smcpowers 	"EC Kernel SW Provider"
61f9fbec18Smcpowers };
62f9fbec18Smcpowers 
63f9fbec18Smcpowers static struct modlinkage modlinkage = {
64f9fbec18Smcpowers 	MODREV_1,
65f9fbec18Smcpowers 	(void *)&modlcrypto,
66f9fbec18Smcpowers 	NULL
67f9fbec18Smcpowers };
68f9fbec18Smcpowers 
69f9fbec18Smcpowers /*
70f9fbec18Smcpowers  * CSPI information (entry points, provider info, etc.)
71f9fbec18Smcpowers  */
72f9fbec18Smcpowers typedef enum ecc_mech_type {
73f9fbec18Smcpowers 	EC_KEY_PAIR_GEN_MECH_INFO_TYPE,	/* SUN_CKM_EC_KEY_PAIR_GEN */
74f9fbec18Smcpowers 	ECDSA_MECH_INFO_TYPE,		/* SUN_CKM_ECDSA */
75f9fbec18Smcpowers 	ECDSA_SHA1_MECH_INFO_TYPE,	/* SUN_CKM_ECDSA_SHA1 */
76f9fbec18Smcpowers 	ECDH1_DERIVE_MECH_INFO_TYPE	/* SUN_CKM_ECDH1_DERIVE */
77f9fbec18Smcpowers } ecc_mech_type_t;
78f9fbec18Smcpowers 
79f9fbec18Smcpowers /*
80f9fbec18Smcpowers  * Context for ECDSA mechanism.
81f9fbec18Smcpowers  */
82f9fbec18Smcpowers typedef struct ecc_ctx {
83f9fbec18Smcpowers 	ecc_mech_type_t	mech_type;
84f9fbec18Smcpowers 	crypto_key_t *key;
85f9fbec18Smcpowers 	size_t keychunk_size;
86f9fbec18Smcpowers 	ECParams ecparams;
87f9fbec18Smcpowers } ecc_ctx_t;
88f9fbec18Smcpowers 
89f9fbec18Smcpowers /*
90f9fbec18Smcpowers  * Context for ECDSA_SHA1 mechanism.
91f9fbec18Smcpowers  */
92f9fbec18Smcpowers typedef struct digest_ecc_ctx {
93f9fbec18Smcpowers 	ecc_mech_type_t	mech_type;
94f9fbec18Smcpowers 	crypto_key_t *key;
95f9fbec18Smcpowers 	size_t keychunk_size;
96f9fbec18Smcpowers 	ECParams ecparams;
97f9fbec18Smcpowers 	union {
98f9fbec18Smcpowers 		SHA1_CTX sha1ctx;
99f9fbec18Smcpowers 	} dctx_u;
100f9fbec18Smcpowers } digest_ecc_ctx_t;
101f9fbec18Smcpowers 
102f9fbec18Smcpowers #define	sha1_ctx	dctx_u.sha1ctx
103f9fbec18Smcpowers 
104f9fbec18Smcpowers /*
105f9fbec18Smcpowers  * Mechanism info structure passed to KCF during registration.
106f9fbec18Smcpowers  */
107f9fbec18Smcpowers static crypto_mech_info_t ecc_mech_info_tab[] = {
108f9fbec18Smcpowers 	/* EC_KEY_PAIR_GEN */
109f9fbec18Smcpowers 	{SUN_CKM_EC_KEY_PAIR_GEN, EC_KEY_PAIR_GEN_MECH_INFO_TYPE,
110f9fbec18Smcpowers 	    CRYPTO_FG_GENERATE_KEY_PAIR, EC_MIN_KEY_LEN, EC_MAX_KEY_LEN,
111f9fbec18Smcpowers 	    CRYPTO_KEYSIZE_UNIT_IN_BITS},
112f9fbec18Smcpowers 	/* ECDH */
113f9fbec18Smcpowers 	{SUN_CKM_ECDH1_DERIVE, ECDH1_DERIVE_MECH_INFO_TYPE, CRYPTO_FG_DERIVE,
114f9fbec18Smcpowers 	    EC_MIN_KEY_LEN, EC_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BITS},
115f9fbec18Smcpowers 	/* ECDSA */
116f9fbec18Smcpowers 	{SUN_CKM_ECDSA, ECDSA_MECH_INFO_TYPE,
117f9fbec18Smcpowers 	    CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY |
118f9fbec18Smcpowers 	    CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC,
119f9fbec18Smcpowers 	    EC_MIN_KEY_LEN, EC_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BITS},
120f9fbec18Smcpowers 	/* ECDSA_SHA1 */
121f9fbec18Smcpowers 	{SUN_CKM_ECDSA_SHA1, ECDSA_SHA1_MECH_INFO_TYPE,
122f9fbec18Smcpowers 	    CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY |
123f9fbec18Smcpowers 	    CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC,
124f9fbec18Smcpowers 	    EC_MIN_KEY_LEN, EC_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BITS}
125f9fbec18Smcpowers };
126f9fbec18Smcpowers 
127f9fbec18Smcpowers static void ecc_provider_status(crypto_provider_handle_t, uint_t *);
128f9fbec18Smcpowers 
129f9fbec18Smcpowers static crypto_control_ops_t ecc_control_ops = {
130f9fbec18Smcpowers 	ecc_provider_status
131f9fbec18Smcpowers };
132f9fbec18Smcpowers 
133f9fbec18Smcpowers static int ecc_sign_init(crypto_ctx_t *, crypto_mechanism_t *,
134f9fbec18Smcpowers     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
135f9fbec18Smcpowers static int ecc_sign(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
136f9fbec18Smcpowers     crypto_req_handle_t);
137f9fbec18Smcpowers static int ecc_sign_update(crypto_ctx_t *, crypto_data_t *,
138f9fbec18Smcpowers     crypto_req_handle_t);
139f9fbec18Smcpowers static int ecc_sign_final(crypto_ctx_t *, crypto_data_t *,
140f9fbec18Smcpowers     crypto_req_handle_t);
141f9fbec18Smcpowers static int ecc_sign_atomic(crypto_provider_handle_t, crypto_session_id_t,
142f9fbec18Smcpowers     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
143f9fbec18Smcpowers     crypto_spi_ctx_template_t, crypto_req_handle_t);
144f9fbec18Smcpowers 
145f9fbec18Smcpowers static crypto_sign_ops_t ecc_sign_ops = {
146f9fbec18Smcpowers 	ecc_sign_init,
147f9fbec18Smcpowers 	ecc_sign,
148f9fbec18Smcpowers 	ecc_sign_update,
149f9fbec18Smcpowers 	ecc_sign_final,
150f9fbec18Smcpowers 	ecc_sign_atomic,
151f9fbec18Smcpowers 	NULL,
152f9fbec18Smcpowers 	NULL,
153f9fbec18Smcpowers 	NULL
154f9fbec18Smcpowers };
155f9fbec18Smcpowers 
156f9fbec18Smcpowers static int ecc_verify_init(crypto_ctx_t *, crypto_mechanism_t *,
157f9fbec18Smcpowers     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
158f9fbec18Smcpowers static int ecc_verify(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
159f9fbec18Smcpowers     crypto_req_handle_t);
160f9fbec18Smcpowers static int ecc_verify_update(crypto_ctx_t *, crypto_data_t *,
161f9fbec18Smcpowers     crypto_req_handle_t);
162f9fbec18Smcpowers static int ecc_verify_final(crypto_ctx_t *, crypto_data_t *,
163f9fbec18Smcpowers     crypto_req_handle_t);
164f9fbec18Smcpowers static int ecc_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
165f9fbec18Smcpowers     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
166f9fbec18Smcpowers     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
167f9fbec18Smcpowers 
168f9fbec18Smcpowers static crypto_verify_ops_t ecc_verify_ops = {
169f9fbec18Smcpowers 	ecc_verify_init,
170f9fbec18Smcpowers 	ecc_verify,
171f9fbec18Smcpowers 	ecc_verify_update,
172f9fbec18Smcpowers 	ecc_verify_final,
173f9fbec18Smcpowers 	ecc_verify_atomic,
174f9fbec18Smcpowers 	NULL,
175f9fbec18Smcpowers 	NULL,
176f9fbec18Smcpowers 	NULL
177f9fbec18Smcpowers };
178f9fbec18Smcpowers 
179f9fbec18Smcpowers static int ecc_nostore_key_generate_pair(crypto_provider_handle_t,
180f9fbec18Smcpowers     crypto_session_id_t, crypto_mechanism_t *, crypto_object_attribute_t *,
181f9fbec18Smcpowers     uint_t, crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
182f9fbec18Smcpowers     uint_t, crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
183f9fbec18Smcpowers static int ecc_nostore_key_derive(crypto_provider_handle_t,
184f9fbec18Smcpowers     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
185f9fbec18Smcpowers     crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
186f9fbec18Smcpowers     uint_t, crypto_req_handle_t);
187f9fbec18Smcpowers 
188f9fbec18Smcpowers static crypto_nostore_key_ops_t ecc_nostore_key_ops = {
189f9fbec18Smcpowers 	NULL,
190f9fbec18Smcpowers 	ecc_nostore_key_generate_pair,
191f9fbec18Smcpowers 	ecc_nostore_key_derive
192f9fbec18Smcpowers };
193f9fbec18Smcpowers 
194f9fbec18Smcpowers static crypto_ops_t ecc_crypto_ops = {
195f9fbec18Smcpowers 	&ecc_control_ops,
196f9fbec18Smcpowers 	NULL,
197f9fbec18Smcpowers 	NULL,
198f9fbec18Smcpowers 	NULL,
199f9fbec18Smcpowers 	&ecc_sign_ops,
200f9fbec18Smcpowers 	&ecc_verify_ops,
201f9fbec18Smcpowers 	NULL,
202f9fbec18Smcpowers 	NULL,
203f9fbec18Smcpowers 	NULL,
204f9fbec18Smcpowers 	NULL,
205f9fbec18Smcpowers 	NULL,
206f9fbec18Smcpowers 	NULL,
207f9fbec18Smcpowers 	NULL,
208f9fbec18Smcpowers 	NULL,
209f9fbec18Smcpowers 	NULL,
21073556491SAnthony Scarpino 	&ecc_nostore_key_ops,
2116ea3c060SGarrett D'Amore 	NULL,
212f9fbec18Smcpowers };
213f9fbec18Smcpowers 
214f9fbec18Smcpowers static crypto_provider_info_t ecc_prov_info = {
21573556491SAnthony Scarpino 	CRYPTO_SPI_VERSION_4,
216f9fbec18Smcpowers 	"EC Software Provider",
217f9fbec18Smcpowers 	CRYPTO_SW_PROVIDER,
218f9fbec18Smcpowers 	{&modlinkage},
219f9fbec18Smcpowers 	NULL,
220f9fbec18Smcpowers 	&ecc_crypto_ops,
221f9fbec18Smcpowers 	sizeof (ecc_mech_info_tab)/sizeof (crypto_mech_info_t),
222f9fbec18Smcpowers 	ecc_mech_info_tab
223f9fbec18Smcpowers };
224f9fbec18Smcpowers 
225*3ec36537SToomas Soome static crypto_kcf_provider_handle_t ecc_prov_handle = 0;
226f9fbec18Smcpowers 
227f9fbec18Smcpowers static int ecc_sign_common(ecc_ctx_t *, crypto_data_t *, crypto_data_t *,
228f9fbec18Smcpowers     crypto_req_handle_t);
229f9fbec18Smcpowers static int ecc_verify_common(ecc_ctx_t *, crypto_data_t *, crypto_data_t *,
230f9fbec18Smcpowers     crypto_req_handle_t);
231f9fbec18Smcpowers static int find_attr(crypto_object_attribute_t *, uint_t, uint64_t);
232f9fbec18Smcpowers static int get_template_attr_ulong(crypto_object_attribute_t *,
233f9fbec18Smcpowers     uint_t, uint64_t, ulong_t *);
234f9fbec18Smcpowers static void ecc_free_context(crypto_ctx_t *);
235f9fbec18Smcpowers static void free_ecparams(ECParams *, boolean_t);
236f9fbec18Smcpowers static void free_ecprivkey(ECPrivateKey *);
237f9fbec18Smcpowers 
238f9fbec18Smcpowers int
_init(void)239f9fbec18Smcpowers _init(void)
240f9fbec18Smcpowers {
241f9fbec18Smcpowers 	int ret;
242f9fbec18Smcpowers 
243d3b2efc7SAnthony Scarpino 	if ((ret = mod_install(&modlinkage)) != 0)
244d3b2efc7SAnthony Scarpino 		return (ret);
245f9fbec18Smcpowers 
246d3b2efc7SAnthony Scarpino 	/* Register with KCF.  If the registration fails, remove the module. */
247d3b2efc7SAnthony Scarpino 	if (crypto_register_provider(&ecc_prov_info, &ecc_prov_handle)) {
248d3b2efc7SAnthony Scarpino 		(void) mod_remove(&modlinkage);
249d3b2efc7SAnthony Scarpino 		return (EACCES);
250f9fbec18Smcpowers 	}
251f9fbec18Smcpowers 
252d3b2efc7SAnthony Scarpino 	return (0);
253f9fbec18Smcpowers }
254f9fbec18Smcpowers 
255f9fbec18Smcpowers int
_fini(void)256f9fbec18Smcpowers _fini(void)
257f9fbec18Smcpowers {
258d3b2efc7SAnthony Scarpino 	/* Unregister from KCF if module is registered */
259*3ec36537SToomas Soome 	if (ecc_prov_handle != 0) {
260d3b2efc7SAnthony Scarpino 		if (crypto_unregister_provider(ecc_prov_handle))
261f9fbec18Smcpowers 			return (EBUSY);
262d3b2efc7SAnthony Scarpino 
263*3ec36537SToomas Soome 		ecc_prov_handle = 0;
264f9fbec18Smcpowers 	}
265f9fbec18Smcpowers 
266f9fbec18Smcpowers 	return (mod_remove(&modlinkage));
267f9fbec18Smcpowers }
268f9fbec18Smcpowers 
269f9fbec18Smcpowers int
_info(struct modinfo * modinfop)270f9fbec18Smcpowers _info(struct modinfo *modinfop)
271f9fbec18Smcpowers {
272f9fbec18Smcpowers 	return (mod_info(&modlinkage, modinfop));
273f9fbec18Smcpowers }
274f9fbec18Smcpowers 
275f9fbec18Smcpowers /* ARGSUSED */
276f9fbec18Smcpowers static void
ecc_provider_status(crypto_provider_handle_t provider,uint_t * status)277f9fbec18Smcpowers ecc_provider_status(crypto_provider_handle_t provider, uint_t *status)
278f9fbec18Smcpowers {
279f9fbec18Smcpowers 	*status = CRYPTO_PROVIDER_READY;
280f9fbec18Smcpowers }
281f9fbec18Smcpowers 
282f9fbec18Smcpowers /*
283f9fbec18Smcpowers  * Return the index of an attribute of specified type found in
284f9fbec18Smcpowers  * the specified array of attributes. If the attribute cannot
285f9fbec18Smcpowers  * found, return -1.
286f9fbec18Smcpowers  */
287f9fbec18Smcpowers static int
find_attr(crypto_object_attribute_t * attr,uint_t nattr,uint64_t attr_type)288f9fbec18Smcpowers find_attr(crypto_object_attribute_t *attr, uint_t nattr, uint64_t attr_type)
289f9fbec18Smcpowers {
290f9fbec18Smcpowers 	int i;
291f9fbec18Smcpowers 
292f9fbec18Smcpowers 	for (i = 0; i < nattr; i++)
293f9fbec18Smcpowers 		if (attr[i].oa_value != NULL && attr[i].oa_type == attr_type)
294f9fbec18Smcpowers 			return (i);
295f9fbec18Smcpowers 	return (-1);
296f9fbec18Smcpowers }
297f9fbec18Smcpowers 
298f9fbec18Smcpowers /*
299f9fbec18Smcpowers  * Common function used by the get_template_attr_*() family of
300f9fbec18Smcpowers  * functions. Returns the value of the specified attribute of specified
301f9fbec18Smcpowers  * length. Returns CRYPTO_SUCCESS on success, CRYPTO_ATTRIBUTE_VALUE_INVALID
302f9fbec18Smcpowers  * if the length of the attribute does not match the specified length,
303f9fbec18Smcpowers  * or CRYPTO_ARGUMENTS_BAD if the attribute cannot be found.
304f9fbec18Smcpowers  */
305f9fbec18Smcpowers static int
get_template_attr_scalar_common(crypto_object_attribute_t * template,uint_t nattr,uint64_t attr_type,void * value,size_t value_len)306f9fbec18Smcpowers get_template_attr_scalar_common(crypto_object_attribute_t *template,
307f9fbec18Smcpowers     uint_t nattr, uint64_t attr_type, void *value, size_t value_len)
308f9fbec18Smcpowers {
309f9fbec18Smcpowers 	size_t oa_value_len;
310f9fbec18Smcpowers 	size_t offset = 0;
311f9fbec18Smcpowers 	int attr_idx;
312f9fbec18Smcpowers 
313f9fbec18Smcpowers 	if ((attr_idx = find_attr(template, nattr, attr_type)) == -1)
314f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
315f9fbec18Smcpowers 
316f9fbec18Smcpowers 	oa_value_len = template[attr_idx].oa_value_len;
317f9fbec18Smcpowers 	if (oa_value_len != value_len) {
318f9fbec18Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
319f9fbec18Smcpowers 	}
320f9fbec18Smcpowers 
321f9fbec18Smcpowers do_copy:
322f9fbec18Smcpowers 	bcopy(template[attr_idx].oa_value, (uchar_t *)value + offset,
323f9fbec18Smcpowers 	    oa_value_len);
324f9fbec18Smcpowers 
325f9fbec18Smcpowers 	return (CRYPTO_SUCCESS);
326f9fbec18Smcpowers }
327f9fbec18Smcpowers 
328f9fbec18Smcpowers /*
329f9fbec18Smcpowers  * Get the value of a ulong_t attribute from the specified template.
330f9fbec18Smcpowers  */
331f9fbec18Smcpowers static int
get_template_attr_ulong(crypto_object_attribute_t * template,uint_t nattr,uint64_t attr_type,ulong_t * attr_value)332f9fbec18Smcpowers get_template_attr_ulong(crypto_object_attribute_t *template,
333f9fbec18Smcpowers     uint_t nattr, uint64_t attr_type, ulong_t *attr_value)
334f9fbec18Smcpowers {
335f9fbec18Smcpowers 	return (get_template_attr_scalar_common(template, nattr,
336f9fbec18Smcpowers 	    attr_type, attr_value, sizeof (ulong_t)));
337f9fbec18Smcpowers }
338f9fbec18Smcpowers 
339f9fbec18Smcpowers /*
340f9fbec18Smcpowers  * Called from init routines to do basic sanity checks. Init routines,
341f9fbec18Smcpowers  * e.g. sign_init should fail rather than subsequent operations.
342f9fbec18Smcpowers  */
343f9fbec18Smcpowers static int
check_mech_and_key(ecc_mech_type_t mech_type,crypto_key_t * key,ulong_t class)344f9fbec18Smcpowers check_mech_and_key(ecc_mech_type_t mech_type, crypto_key_t *key, ulong_t class)
345f9fbec18Smcpowers {
346f9fbec18Smcpowers 	int rv = CRYPTO_SUCCESS;
347f9fbec18Smcpowers 	uchar_t *foo;
348f9fbec18Smcpowers 	ssize_t point_len;
349f9fbec18Smcpowers 	ssize_t value_len;
350f9fbec18Smcpowers 
351f9fbec18Smcpowers 	if (mech_type != ECDSA_SHA1_MECH_INFO_TYPE &&
352f9fbec18Smcpowers 	    mech_type != ECDSA_MECH_INFO_TYPE)
353f9fbec18Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
354f9fbec18Smcpowers 
355f9fbec18Smcpowers 	if (key->ck_format != CRYPTO_KEY_ATTR_LIST) {
356f9fbec18Smcpowers 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
357f9fbec18Smcpowers 	}
358f9fbec18Smcpowers 
359f9fbec18Smcpowers 	switch (class) {
360f9fbec18Smcpowers 	case CKO_PUBLIC_KEY:
36123c57df7Smcpowers 		if ((rv = crypto_get_key_attr(key, CKA_EC_POINT, &foo,
36223c57df7Smcpowers 		    &point_len)) != CRYPTO_SUCCESS) {
363f9fbec18Smcpowers 			return (CRYPTO_TEMPLATE_INCOMPLETE);
364f9fbec18Smcpowers 		}
365f9fbec18Smcpowers 		if (point_len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) * 2 + 1 ||
366f9fbec18Smcpowers 		    point_len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN) * 2 + 1)
367f9fbec18Smcpowers 			return (CRYPTO_KEY_SIZE_RANGE);
368f9fbec18Smcpowers 		break;
369f9fbec18Smcpowers 
370f9fbec18Smcpowers 	case CKO_PRIVATE_KEY:
37123c57df7Smcpowers 		if ((rv = crypto_get_key_attr(key, CKA_VALUE, &foo,
37223c57df7Smcpowers 		    &value_len)) != CRYPTO_SUCCESS) {
373f9fbec18Smcpowers 			return (CRYPTO_TEMPLATE_INCOMPLETE);
374f9fbec18Smcpowers 		}
375f9fbec18Smcpowers 		if (value_len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) ||
376f9fbec18Smcpowers 		    value_len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN))
377f9fbec18Smcpowers 			return (CRYPTO_KEY_SIZE_RANGE);
378f9fbec18Smcpowers 		break;
379f9fbec18Smcpowers 
380f9fbec18Smcpowers 	default:
381f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
382f9fbec18Smcpowers 	}
383f9fbec18Smcpowers 
384f9fbec18Smcpowers 	return (rv);
385f9fbec18Smcpowers }
386f9fbec18Smcpowers 
387f9fbec18Smcpowers /*
388f9fbec18Smcpowers  * This function guarantees to return non-zero random numbers.
389f9fbec18Smcpowers  * This is needed as the /dev/urandom kernel interface,
390f9fbec18Smcpowers  * random_get_pseudo_bytes(), may return zeros.
391f9fbec18Smcpowers  */
392f9fbec18Smcpowers int
ecc_knzero_random_generator(uint8_t * ran_out,size_t ran_len)393f9fbec18Smcpowers ecc_knzero_random_generator(uint8_t *ran_out, size_t ran_len)
394f9fbec18Smcpowers {
395f9fbec18Smcpowers 	int rv;
396f9fbec18Smcpowers 	size_t ebc = 0; /* count of extra bytes in extrarand */
397f9fbec18Smcpowers 	size_t i = 0;
398f9fbec18Smcpowers 	uint8_t extrarand[32];
399f9fbec18Smcpowers 	size_t extrarand_len;
400f9fbec18Smcpowers 
4016ea3c060SGarrett D'Amore 	if ((rv = random_get_pseudo_bytes(ran_out, ran_len)) != 0)
402f9fbec18Smcpowers 		return (rv);
403f9fbec18Smcpowers 
404f9fbec18Smcpowers 	/*
405f9fbec18Smcpowers 	 * Walk through the returned random numbers pointed by ran_out,
406f9fbec18Smcpowers 	 * and look for any random number which is zero.
407f9fbec18Smcpowers 	 * If we find zero, call random_get_pseudo_bytes() to generate
408f9fbec18Smcpowers 	 * another 32 random numbers pool. Replace any zeros in ran_out[]
409f9fbec18Smcpowers 	 * from the random number in pool.
410f9fbec18Smcpowers 	 */
411f9fbec18Smcpowers 	while (i < ran_len) {
412f9fbec18Smcpowers 		if (ran_out[i] != 0) {
413f9fbec18Smcpowers 			i++;
414f9fbec18Smcpowers 			continue;
415f9fbec18Smcpowers 		}
416f9fbec18Smcpowers 
417f9fbec18Smcpowers 		/*
418f9fbec18Smcpowers 		 * Note that it is 'while' so we are guaranteed a
419f9fbec18Smcpowers 		 * non-zero value on exit.
420f9fbec18Smcpowers 		 */
421f9fbec18Smcpowers 		if (ebc == 0) {
422f9fbec18Smcpowers 			/* refresh extrarand */
423f9fbec18Smcpowers 			extrarand_len = sizeof (extrarand);
4246ea3c060SGarrett D'Amore 			if ((rv = random_get_pseudo_bytes(extrarand,
425f9fbec18Smcpowers 			    extrarand_len)) != 0) {
426f9fbec18Smcpowers 				return (rv);
427f9fbec18Smcpowers 			}
428f9fbec18Smcpowers 
429f9fbec18Smcpowers 			ebc = extrarand_len;
430f9fbec18Smcpowers 		}
431f9fbec18Smcpowers 		/* Replace zero with byte from extrarand. */
432f9fbec18Smcpowers 		-- ebc;
433f9fbec18Smcpowers 
434f9fbec18Smcpowers 		/*
435f9fbec18Smcpowers 		 * The new random byte zero/non-zero will be checked in
436f9fbec18Smcpowers 		 * the next pass through the loop.
437f9fbec18Smcpowers 		 */
438f9fbec18Smcpowers 		ran_out[i] = extrarand[ebc];
439f9fbec18Smcpowers 	}
440f9fbec18Smcpowers 
441f9fbec18Smcpowers 	return (CRYPTO_SUCCESS);
442f9fbec18Smcpowers }
443f9fbec18Smcpowers 
444f9fbec18Smcpowers static void
ecc_free_context(crypto_ctx_t * ctx)445f9fbec18Smcpowers ecc_free_context(crypto_ctx_t *ctx)
446f9fbec18Smcpowers {
447f9fbec18Smcpowers 	ecc_ctx_t *ctxp = ctx->cc_provider_private;
448f9fbec18Smcpowers 
449f9fbec18Smcpowers 	if (ctxp != NULL) {
450f9fbec18Smcpowers 		bzero(ctxp->key, ctxp->keychunk_size);
451f9fbec18Smcpowers 		kmem_free(ctxp->key, ctxp->keychunk_size);
452f9fbec18Smcpowers 
453f9fbec18Smcpowers 		free_ecparams(&ctxp->ecparams, B_FALSE);
454f9fbec18Smcpowers 
455f9fbec18Smcpowers 		if (ctxp->mech_type == ECDSA_MECH_INFO_TYPE)
456f9fbec18Smcpowers 			kmem_free(ctxp, sizeof (ecc_ctx_t));
457f9fbec18Smcpowers 		else
458f9fbec18Smcpowers 			kmem_free(ctxp, sizeof (digest_ecc_ctx_t));
459f9fbec18Smcpowers 
460f9fbec18Smcpowers 		ctx->cc_provider_private = NULL;
461f9fbec18Smcpowers 	}
462f9fbec18Smcpowers }
463f9fbec18Smcpowers 
464f9fbec18Smcpowers /* ARGSUSED */
465f9fbec18Smcpowers static int
ecc_sign_verify_common_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)466f9fbec18Smcpowers ecc_sign_verify_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
467f9fbec18Smcpowers     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
468f9fbec18Smcpowers     crypto_req_handle_t req)
469f9fbec18Smcpowers {
470f9fbec18Smcpowers 	int rv;
471f9fbec18Smcpowers 	int kmflag;
472f9fbec18Smcpowers 	ecc_ctx_t *ctxp;
473f9fbec18Smcpowers 	digest_ecc_ctx_t *dctxp;
474f9fbec18Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
475f9fbec18Smcpowers 	uchar_t *params;
476f9fbec18Smcpowers 	ssize_t params_len;
477f9fbec18Smcpowers 	ECParams  *ecparams;
478f9fbec18Smcpowers 	SECKEYECParams params_item;
479f9fbec18Smcpowers 
48023c57df7Smcpowers 	if (crypto_get_key_attr(key, CKA_EC_PARAMS, (void *) &params,
481f9fbec18Smcpowers 	    &params_len)) {
482f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
483f9fbec18Smcpowers 	}
484f9fbec18Smcpowers 
485f9fbec18Smcpowers 	/* ASN1 check */
486f9fbec18Smcpowers 	if (params[0] != 0x06 ||
487f9fbec18Smcpowers 	    params[1] != params_len - 2) {
488f9fbec18Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
489f9fbec18Smcpowers 	}
490f9fbec18Smcpowers 	params_item.data = params;
491f9fbec18Smcpowers 	params_item.len = (uint_t)params_len;
492f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
493f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
494f9fbec18Smcpowers 		/* bad curve OID */
495f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
496f9fbec18Smcpowers 	}
497f9fbec18Smcpowers 
498f9fbec18Smcpowers 	/*
499f9fbec18Smcpowers 	 * Allocate an ECC context.
500f9fbec18Smcpowers 	 */
501f9fbec18Smcpowers 	switch (mech_type) {
502f9fbec18Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
503f9fbec18Smcpowers 		dctxp = kmem_zalloc(sizeof (digest_ecc_ctx_t), kmflag);
504f9fbec18Smcpowers 		ctxp = (ecc_ctx_t *)dctxp;
505f9fbec18Smcpowers 		break;
506f9fbec18Smcpowers 	default:
507f9fbec18Smcpowers 		ctxp = kmem_zalloc(sizeof (ecc_ctx_t), kmflag);
508f9fbec18Smcpowers 		break;
509f9fbec18Smcpowers 	}
510f9fbec18Smcpowers 
511f9fbec18Smcpowers 	if (ctxp == NULL) {
512f9fbec18Smcpowers 		free_ecparams(ecparams, B_TRUE);
513f9fbec18Smcpowers 		return (CRYPTO_HOST_MEMORY);
514f9fbec18Smcpowers 	}
515f9fbec18Smcpowers 
51623c57df7Smcpowers 	if ((rv = crypto_copy_key_to_ctx(key, &ctxp->key, &ctxp->keychunk_size,
51723c57df7Smcpowers 	    kmflag)) != CRYPTO_SUCCESS) {
518f9fbec18Smcpowers 		switch (mech_type) {
519f9fbec18Smcpowers 		case ECDSA_SHA1_MECH_INFO_TYPE:
520f9fbec18Smcpowers 			kmem_free(dctxp, sizeof (digest_ecc_ctx_t));
521f9fbec18Smcpowers 			break;
522f9fbec18Smcpowers 		default:
523f9fbec18Smcpowers 			kmem_free(ctxp, sizeof (ecc_ctx_t));
524f9fbec18Smcpowers 			break;
525f9fbec18Smcpowers 		}
526f9fbec18Smcpowers 		free_ecparams(ecparams, B_TRUE);
527f9fbec18Smcpowers 		return (rv);
528f9fbec18Smcpowers 	}
529f9fbec18Smcpowers 	ctxp->mech_type = mech_type;
530f9fbec18Smcpowers 	ctxp->ecparams = *ecparams;
531f9fbec18Smcpowers 	kmem_free(ecparams, sizeof (ECParams));
532f9fbec18Smcpowers 
533f9fbec18Smcpowers 	switch (mech_type) {
534f9fbec18Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
535f9fbec18Smcpowers 		SHA1Init(&(dctxp->sha1_ctx));
536f9fbec18Smcpowers 		break;
537f9fbec18Smcpowers 	}
538f9fbec18Smcpowers 
539f9fbec18Smcpowers 	ctx->cc_provider_private = ctxp;
540f9fbec18Smcpowers 
541f9fbec18Smcpowers 	return (CRYPTO_SUCCESS);
542f9fbec18Smcpowers }
543f9fbec18Smcpowers 
544f9fbec18Smcpowers /* ARGSUSED */
545f9fbec18Smcpowers static int
ecc_sign_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)546f9fbec18Smcpowers ecc_sign_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
547f9fbec18Smcpowers     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
548f9fbec18Smcpowers     crypto_req_handle_t req)
549f9fbec18Smcpowers {
550f9fbec18Smcpowers 	int rv;
551f9fbec18Smcpowers 
552f9fbec18Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
553f9fbec18Smcpowers 
554f9fbec18Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
555f9fbec18Smcpowers 	    CKO_PRIVATE_KEY)) != CRYPTO_SUCCESS)
556f9fbec18Smcpowers 		return (rv);
557f9fbec18Smcpowers 
558f9fbec18Smcpowers 	rv = ecc_sign_verify_common_init(ctx, mechanism, key,
559f9fbec18Smcpowers 	    ctx_template, req);
560f9fbec18Smcpowers 
561f9fbec18Smcpowers 	return (rv);
562f9fbec18Smcpowers }
563f9fbec18Smcpowers 
564f9fbec18Smcpowers /* ARGSUSED */
565f9fbec18Smcpowers static int
ecc_verify_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)566f9fbec18Smcpowers ecc_verify_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
567f9fbec18Smcpowers     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
568f9fbec18Smcpowers     crypto_req_handle_t req)
569f9fbec18Smcpowers {
570f9fbec18Smcpowers 	int rv;
571f9fbec18Smcpowers 
572f9fbec18Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
573f9fbec18Smcpowers 
574f9fbec18Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
575f9fbec18Smcpowers 	    CKO_PUBLIC_KEY)) != CRYPTO_SUCCESS)
576f9fbec18Smcpowers 		return (rv);
577f9fbec18Smcpowers 
578f9fbec18Smcpowers 	rv = ecc_sign_verify_common_init(ctx, mechanism, key,
579f9fbec18Smcpowers 	    ctx_template, req);
580f9fbec18Smcpowers 
581f9fbec18Smcpowers 	return (rv);
582f9fbec18Smcpowers }
583f9fbec18Smcpowers 
584f9fbec18Smcpowers #define	SHA1_DIGEST_SIZE 20
585f9fbec18Smcpowers 
586f9fbec18Smcpowers #define	INIT_RAW_CRYPTO_DATA(data, base, len, cd_len)	\
587f9fbec18Smcpowers 	(data).cd_format = CRYPTO_DATA_RAW;		\
588f9fbec18Smcpowers 	(data).cd_offset = 0;				\
589f9fbec18Smcpowers 	(data).cd_raw.iov_base = (char *)base;		\
590f9fbec18Smcpowers 	(data).cd_raw.iov_len = len;			\
591f9fbec18Smcpowers 	(data).cd_length = cd_len;
592f9fbec18Smcpowers 
593f9fbec18Smcpowers static int
ecc_digest_svrfy_common(digest_ecc_ctx_t * ctxp,crypto_data_t * data,crypto_data_t * signature,uchar_t flag,crypto_req_handle_t req)594f9fbec18Smcpowers ecc_digest_svrfy_common(digest_ecc_ctx_t *ctxp, crypto_data_t *data,
595f9fbec18Smcpowers     crypto_data_t *signature, uchar_t flag, crypto_req_handle_t req)
596f9fbec18Smcpowers {
597f9fbec18Smcpowers 	int rv = CRYPTO_FAILED;
598f9fbec18Smcpowers 	uchar_t digest[SHA1_DIGEST_LENGTH];
599f9fbec18Smcpowers 	crypto_data_t der_cd;
600f9fbec18Smcpowers 	ecc_mech_type_t mech_type;
601f9fbec18Smcpowers 
60223c57df7Smcpowers 	ASSERT(flag & CRYPTO_DO_SIGN || flag & CRYPTO_DO_VERIFY);
60323c57df7Smcpowers 	ASSERT(data != NULL || (flag & CRYPTO_DO_FINAL));
604f9fbec18Smcpowers 
605f9fbec18Smcpowers 	mech_type = ctxp->mech_type;
606f9fbec18Smcpowers 	if (mech_type != ECDSA_SHA1_MECH_INFO_TYPE)
607f9fbec18Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
608f9fbec18Smcpowers 
609f9fbec18Smcpowers 	/* Don't digest if only returning length of signature. */
610f9fbec18Smcpowers 	if (signature->cd_length > 0) {
611f9fbec18Smcpowers 		if (mech_type == ECDSA_SHA1_MECH_INFO_TYPE) {
61223c57df7Smcpowers 			rv = crypto_digest_data(data, &(ctxp->sha1_ctx),
61323c57df7Smcpowers 			    digest, (void (*)())SHA1Update,
61423c57df7Smcpowers 			    (void (*)())SHA1Final, flag | CRYPTO_DO_SHA1);
615f9fbec18Smcpowers 			if (rv != CRYPTO_SUCCESS)
616f9fbec18Smcpowers 				return (rv);
617f9fbec18Smcpowers 		}
618f9fbec18Smcpowers 	}
619f9fbec18Smcpowers 
620f9fbec18Smcpowers 	INIT_RAW_CRYPTO_DATA(der_cd, digest, SHA1_DIGEST_SIZE,
621f9fbec18Smcpowers 	    SHA1_DIGEST_SIZE);
622f9fbec18Smcpowers 
62323c57df7Smcpowers 	if (flag & CRYPTO_DO_SIGN) {
624f9fbec18Smcpowers 		rv = ecc_sign_common((ecc_ctx_t *)ctxp, &der_cd, signature,
625f9fbec18Smcpowers 		    req);
626f9fbec18Smcpowers 	} else
627f9fbec18Smcpowers 		rv = ecc_verify_common((ecc_ctx_t *)ctxp, &der_cd, signature,
628f9fbec18Smcpowers 		    req);
629f9fbec18Smcpowers 
630f9fbec18Smcpowers 	return (rv);
631f9fbec18Smcpowers }
632f9fbec18Smcpowers 
633f9fbec18Smcpowers /*
634f9fbec18Smcpowers  * This is a single-part signing routine. It does not
635f9fbec18Smcpowers  * compute a hash before signing.
636f9fbec18Smcpowers  */
637f9fbec18Smcpowers static int
ecc_sign_common(ecc_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)638f9fbec18Smcpowers ecc_sign_common(ecc_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
639f9fbec18Smcpowers     crypto_req_handle_t req)
640f9fbec18Smcpowers {
641f9fbec18Smcpowers 	int rv = CRYPTO_FAILED;
642f9fbec18Smcpowers 	SECStatus ss;
643f9fbec18Smcpowers 	uchar_t *param;
644f9fbec18Smcpowers 	uchar_t *private;
645f9fbec18Smcpowers 	ssize_t param_len;
646f9fbec18Smcpowers 	ssize_t private_len;
647f9fbec18Smcpowers 	uchar_t tmp_data[EC_MAX_DIGEST_LEN];
648f9fbec18Smcpowers 	uchar_t signed_data[EC_MAX_SIG_LEN];
649f9fbec18Smcpowers 	ECPrivateKey ECkey;
650f9fbec18Smcpowers 	SECItem signature_item;
651f9fbec18Smcpowers 	SECItem digest_item;
652f9fbec18Smcpowers 	crypto_key_t *key = ctx->key;
653f9fbec18Smcpowers 	int kmflag;
654f9fbec18Smcpowers 
65523c57df7Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_EC_PARAMS, &param,
656f9fbec18Smcpowers 	    &param_len)) != CRYPTO_SUCCESS) {
657f9fbec18Smcpowers 		return (rv);
658f9fbec18Smcpowers 	}
659f9fbec18Smcpowers 
660f9fbec18Smcpowers 	if (data->cd_length > sizeof (tmp_data))
661f9fbec18Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
662f9fbec18Smcpowers 
66323c57df7Smcpowers 	if ((rv = crypto_get_input_data(data, &digest_item.data, tmp_data))
664f9fbec18Smcpowers 	    != CRYPTO_SUCCESS) {
665f9fbec18Smcpowers 		return (rv);
666f9fbec18Smcpowers 	}
667f9fbec18Smcpowers 	digest_item.len = data->cd_length;
668f9fbec18Smcpowers 
669f9fbec18Smcpowers 	/* structure assignment */
670f9fbec18Smcpowers 	ECkey.ecParams = ctx->ecparams;
671f9fbec18Smcpowers 
67223c57df7Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_VALUE, &private,
673f9fbec18Smcpowers 	    &private_len)) != CRYPTO_SUCCESS) {
674f9fbec18Smcpowers 		return (rv);
675f9fbec18Smcpowers 	}
676f9fbec18Smcpowers 	ECkey.privateValue.data = private;
677f9fbec18Smcpowers 	ECkey.privateValue.len = (uint_t)private_len;
678f9fbec18Smcpowers 
679f9fbec18Smcpowers 	signature_item.data = signed_data;
680f9fbec18Smcpowers 	signature_item.len = sizeof (signed_data);
681f9fbec18Smcpowers 
682f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
683f9fbec18Smcpowers 	if ((ss = ECDSA_SignDigest(&ECkey, &signature_item, &digest_item,
684f9fbec18Smcpowers 	    kmflag)) != SECSuccess) {
685f9fbec18Smcpowers 		if (ss == SECBufferTooSmall)
686f9fbec18Smcpowers 			return (CRYPTO_BUFFER_TOO_SMALL);
687f9fbec18Smcpowers 
688f9fbec18Smcpowers 		return (CRYPTO_FAILED);
689f9fbec18Smcpowers 	}
690f9fbec18Smcpowers 
691f9fbec18Smcpowers 	if (rv == CRYPTO_SUCCESS) {
692f9fbec18Smcpowers 		/* copy out the signature */
69323c57df7Smcpowers 		if ((rv = crypto_put_output_data(signed_data,
694f9fbec18Smcpowers 		    signature, signature_item.len)) != CRYPTO_SUCCESS)
695f9fbec18Smcpowers 			return (rv);
696f9fbec18Smcpowers 
697f9fbec18Smcpowers 		signature->cd_length = signature_item.len;
698f9fbec18Smcpowers 	}
699f9fbec18Smcpowers 
700f9fbec18Smcpowers 	return (rv);
701f9fbec18Smcpowers }
702f9fbec18Smcpowers 
703f9fbec18Smcpowers /* ARGSUSED */
704f9fbec18Smcpowers static int
ecc_sign(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)705f9fbec18Smcpowers ecc_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
706f9fbec18Smcpowers     crypto_req_handle_t req)
707f9fbec18Smcpowers {
708f9fbec18Smcpowers 	int rv;
709f9fbec18Smcpowers 	ecc_ctx_t *ctxp;
710f9fbec18Smcpowers 
711f9fbec18Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
712f9fbec18Smcpowers 	ctxp = ctx->cc_provider_private;
713f9fbec18Smcpowers 
714f9fbec18Smcpowers 	switch (ctxp->mech_type) {
715f9fbec18Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
716f9fbec18Smcpowers 		rv = ecc_digest_svrfy_common((digest_ecc_ctx_t *)ctxp, data,
71723c57df7Smcpowers 		    signature, CRYPTO_DO_SIGN | CRYPTO_DO_UPDATE |
71823c57df7Smcpowers 		    CRYPTO_DO_FINAL, req);
719f9fbec18Smcpowers 		break;
720f9fbec18Smcpowers 	default:
721f9fbec18Smcpowers 		rv = ecc_sign_common(ctxp, data, signature, req);
722f9fbec18Smcpowers 		break;
723f9fbec18Smcpowers 	}
724f9fbec18Smcpowers 
725f9fbec18Smcpowers 	if (rv != CRYPTO_BUFFER_TOO_SMALL)
726f9fbec18Smcpowers 		ecc_free_context(ctx);
727f9fbec18Smcpowers 
728f9fbec18Smcpowers 	return (rv);
729f9fbec18Smcpowers }
730f9fbec18Smcpowers 
731f9fbec18Smcpowers /* ARGSUSED */
732f9fbec18Smcpowers static int
ecc_sign_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)733f9fbec18Smcpowers ecc_sign_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
734f9fbec18Smcpowers {
735f9fbec18Smcpowers 	int rv;
736f9fbec18Smcpowers 	digest_ecc_ctx_t *ctxp;
737f9fbec18Smcpowers 	ecc_mech_type_t mech_type;
738f9fbec18Smcpowers 
739f9fbec18Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
740f9fbec18Smcpowers 	ctxp = ctx->cc_provider_private;
741f9fbec18Smcpowers 	mech_type = ctxp->mech_type;
742f9fbec18Smcpowers 
743f9fbec18Smcpowers 	if (mech_type == ECDSA_MECH_INFO_TYPE) {
744f9fbec18Smcpowers 		ecc_free_context(ctx);
745f9fbec18Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
746f9fbec18Smcpowers 	}
747f9fbec18Smcpowers 
748f9fbec18Smcpowers 	if (mech_type == ECDSA_SHA1_MECH_INFO_TYPE)
74923c57df7Smcpowers 		rv = crypto_digest_data(data, &(ctxp->sha1_ctx), NULL,
75023c57df7Smcpowers 		    (void (*)())SHA1Update, (void (*)())SHA1Final,
75123c57df7Smcpowers 		    CRYPTO_DO_SHA1 | CRYPTO_DO_UPDATE);
752f9fbec18Smcpowers 
753f9fbec18Smcpowers 	if (rv != CRYPTO_SUCCESS)
754f9fbec18Smcpowers 		ecc_free_context(ctx);
755f9fbec18Smcpowers 
756f9fbec18Smcpowers 	return (rv);
757f9fbec18Smcpowers }
758f9fbec18Smcpowers 
759f9fbec18Smcpowers /* ARGSUSED */
760f9fbec18Smcpowers static int
ecc_sign_final(crypto_ctx_t * ctx,crypto_data_t * signature,crypto_req_handle_t req)761f9fbec18Smcpowers ecc_sign_final(crypto_ctx_t *ctx, crypto_data_t *signature,
762f9fbec18Smcpowers     crypto_req_handle_t req)
763f9fbec18Smcpowers {
764f9fbec18Smcpowers 	int rv;
765f9fbec18Smcpowers 	digest_ecc_ctx_t *ctxp;
766f9fbec18Smcpowers 
767f9fbec18Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
768f9fbec18Smcpowers 	ctxp = ctx->cc_provider_private;
769f9fbec18Smcpowers 
77023c57df7Smcpowers 	rv = ecc_digest_svrfy_common(ctxp, NULL, signature, CRYPTO_DO_SIGN |
77123c57df7Smcpowers 	    CRYPTO_DO_FINAL, req);
772f9fbec18Smcpowers 	if (rv != CRYPTO_BUFFER_TOO_SMALL)
773f9fbec18Smcpowers 		ecc_free_context(ctx);
774f9fbec18Smcpowers 
775f9fbec18Smcpowers 	return (rv);
776f9fbec18Smcpowers }
777f9fbec18Smcpowers 
778f9fbec18Smcpowers /* ARGSUSED */
779f9fbec18Smcpowers static int
ecc_sign_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * signature,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)780f9fbec18Smcpowers ecc_sign_atomic(crypto_provider_handle_t provider,
781f9fbec18Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
782f9fbec18Smcpowers     crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
783f9fbec18Smcpowers     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
784f9fbec18Smcpowers {
785f9fbec18Smcpowers 	int rv;
786f9fbec18Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
787f9fbec18Smcpowers 	uchar_t *params;
788f9fbec18Smcpowers 	ssize_t params_len;
789f9fbec18Smcpowers 	ECParams  *ecparams;
790f9fbec18Smcpowers 	SECKEYECParams params_item;
791f9fbec18Smcpowers 	int kmflag;
792f9fbec18Smcpowers 
793f9fbec18Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
794f9fbec18Smcpowers 	    CKO_PRIVATE_KEY)) != CRYPTO_SUCCESS)
795f9fbec18Smcpowers 		return (rv);
796f9fbec18Smcpowers 
79723c57df7Smcpowers 	if (crypto_get_key_attr(key, CKA_EC_PARAMS, (void *) &params,
798f9fbec18Smcpowers 	    &params_len)) {
799f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
800f9fbec18Smcpowers 	}
801f9fbec18Smcpowers 
802f9fbec18Smcpowers 	/* ASN1 check */
803f9fbec18Smcpowers 	if (params[0] != 0x06 ||
804f9fbec18Smcpowers 	    params[1] != params_len - 2) {
805f9fbec18Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
806f9fbec18Smcpowers 	}
807f9fbec18Smcpowers 	params_item.data = params;
808f9fbec18Smcpowers 	params_item.len = (uint_t)params_len;
809f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
810f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
811f9fbec18Smcpowers 		/* bad curve OID */
812f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
813f9fbec18Smcpowers 	}
814f9fbec18Smcpowers 
815f9fbec18Smcpowers 	if (mechanism->cm_type == ECDSA_MECH_INFO_TYPE) {
816f9fbec18Smcpowers 		ecc_ctx_t ctx;
817f9fbec18Smcpowers 
818f9fbec18Smcpowers 		ctx.mech_type = mech_type;
819f9fbec18Smcpowers 		/* structure assignment */
820f9fbec18Smcpowers 		ctx.ecparams = *ecparams;
821f9fbec18Smcpowers 		ctx.key = key;
822f9fbec18Smcpowers 		rv = ecc_sign_common(&ctx, data, signature, req);
823f9fbec18Smcpowers 	} else {
824f9fbec18Smcpowers 		digest_ecc_ctx_t dctx;
825f9fbec18Smcpowers 
826f9fbec18Smcpowers 		dctx.mech_type = mech_type;
827f9fbec18Smcpowers 		/* structure assignment */
828f9fbec18Smcpowers 		dctx.ecparams = *ecparams;
829f9fbec18Smcpowers 		dctx.key = key;
830f9fbec18Smcpowers 		SHA1Init(&(dctx.sha1_ctx));
831f9fbec18Smcpowers 
832f9fbec18Smcpowers 		rv = ecc_digest_svrfy_common(&dctx, data, signature,
83323c57df7Smcpowers 		    CRYPTO_DO_SIGN | CRYPTO_DO_UPDATE | CRYPTO_DO_FINAL, req);
834f9fbec18Smcpowers 	}
835f9fbec18Smcpowers 	free_ecparams(ecparams, B_TRUE);
836f9fbec18Smcpowers 
837f9fbec18Smcpowers 	return (rv);
838f9fbec18Smcpowers }
839f9fbec18Smcpowers 
840f9fbec18Smcpowers static int
ecc_verify_common(ecc_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)841f9fbec18Smcpowers ecc_verify_common(ecc_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
842f9fbec18Smcpowers     crypto_req_handle_t req)
843f9fbec18Smcpowers {
844f9fbec18Smcpowers 	int rv = CRYPTO_FAILED;
845f9fbec18Smcpowers 	uchar_t *param;
846f9fbec18Smcpowers 	uchar_t *public;
847f9fbec18Smcpowers 	ssize_t param_len;
848f9fbec18Smcpowers 	ssize_t public_len;
849f9fbec18Smcpowers 	uchar_t tmp_data[EC_MAX_DIGEST_LEN];
850f9fbec18Smcpowers 	uchar_t signed_data[EC_MAX_SIG_LEN];
851f9fbec18Smcpowers 	ECPublicKey ECkey;
852f9fbec18Smcpowers 	SECItem signature_item;
853f9fbec18Smcpowers 	SECItem digest_item;
854f9fbec18Smcpowers 	crypto_key_t *key = ctx->key;
855f9fbec18Smcpowers 	int kmflag;
856f9fbec18Smcpowers 
85723c57df7Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_EC_PARAMS, &param,
858f9fbec18Smcpowers 	    &param_len)) != CRYPTO_SUCCESS) {
859f9fbec18Smcpowers 		return (rv);
860f9fbec18Smcpowers 	}
861f9fbec18Smcpowers 
862f9fbec18Smcpowers 	if (signature->cd_length > sizeof (signed_data)) {
863f9fbec18Smcpowers 		return (CRYPTO_SIGNATURE_LEN_RANGE);
864f9fbec18Smcpowers 	}
865f9fbec18Smcpowers 
86623c57df7Smcpowers 	if ((rv = crypto_get_input_data(signature, &signature_item.data,
867f9fbec18Smcpowers 	    signed_data)) != CRYPTO_SUCCESS) {
868f9fbec18Smcpowers 		return (rv);
869f9fbec18Smcpowers 	}
870f9fbec18Smcpowers 	signature_item.len = signature->cd_length;
871f9fbec18Smcpowers 
872f9fbec18Smcpowers 	if (data->cd_length > sizeof (tmp_data))
873f9fbec18Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
874f9fbec18Smcpowers 
87523c57df7Smcpowers 	if ((rv = crypto_get_input_data(data, &digest_item.data, tmp_data))
876f9fbec18Smcpowers 	    != CRYPTO_SUCCESS) {
877f9fbec18Smcpowers 		return (rv);
878f9fbec18Smcpowers 	}
879f9fbec18Smcpowers 	digest_item.len = data->cd_length;
880f9fbec18Smcpowers 
881f9fbec18Smcpowers 	/* structure assignment */
882f9fbec18Smcpowers 	ECkey.ecParams = ctx->ecparams;
883f9fbec18Smcpowers 
88423c57df7Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_EC_POINT, &public,
885f9fbec18Smcpowers 	    &public_len)) != CRYPTO_SUCCESS) {
886f9fbec18Smcpowers 		return (rv);
887f9fbec18Smcpowers 	}
888f9fbec18Smcpowers 	ECkey.publicValue.data = public;
889f9fbec18Smcpowers 	ECkey.publicValue.len = (uint_t)public_len;
890f9fbec18Smcpowers 
891f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
892f9fbec18Smcpowers 	if (ECDSA_VerifyDigest(&ECkey, &signature_item, &digest_item, kmflag)
893f9fbec18Smcpowers 	    != SECSuccess) {
894f9fbec18Smcpowers 		rv = CRYPTO_SIGNATURE_INVALID;
895f9fbec18Smcpowers 	} else {
896f9fbec18Smcpowers 		rv = CRYPTO_SUCCESS;
897f9fbec18Smcpowers 	}
898f9fbec18Smcpowers 
899f9fbec18Smcpowers 	return (rv);
900f9fbec18Smcpowers }
901f9fbec18Smcpowers 
902f9fbec18Smcpowers /* ARGSUSED */
903f9fbec18Smcpowers static int
ecc_verify(crypto_ctx_t * ctx,crypto_data_t * data,crypto_data_t * signature,crypto_req_handle_t req)904f9fbec18Smcpowers ecc_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
905f9fbec18Smcpowers     crypto_req_handle_t req)
906f9fbec18Smcpowers {
907f9fbec18Smcpowers 	int rv;
908f9fbec18Smcpowers 	ecc_ctx_t *ctxp;
909f9fbec18Smcpowers 
910f9fbec18Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
911f9fbec18Smcpowers 	ctxp = ctx->cc_provider_private;
912f9fbec18Smcpowers 
913f9fbec18Smcpowers 	switch (ctxp->mech_type) {
914f9fbec18Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
915f9fbec18Smcpowers 		rv = ecc_digest_svrfy_common((digest_ecc_ctx_t *)ctxp, data,
91623c57df7Smcpowers 		    signature, CRYPTO_DO_VERIFY | CRYPTO_DO_UPDATE |
91723c57df7Smcpowers 		    CRYPTO_DO_FINAL, req);
918f9fbec18Smcpowers 		break;
919f9fbec18Smcpowers 	default:
920f9fbec18Smcpowers 		rv = ecc_verify_common(ctxp, data, signature, req);
921f9fbec18Smcpowers 		break;
922f9fbec18Smcpowers 	}
923f9fbec18Smcpowers 
924f9fbec18Smcpowers 	ecc_free_context(ctx);
925f9fbec18Smcpowers 	return (rv);
926f9fbec18Smcpowers }
927f9fbec18Smcpowers 
928f9fbec18Smcpowers /* ARGSUSED */
929f9fbec18Smcpowers static int
ecc_verify_update(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)930f9fbec18Smcpowers ecc_verify_update(crypto_ctx_t *ctx, crypto_data_t *data,
931f9fbec18Smcpowers     crypto_req_handle_t req)
932f9fbec18Smcpowers {
933f9fbec18Smcpowers 	int rv;
934f9fbec18Smcpowers 	digest_ecc_ctx_t *ctxp;
935f9fbec18Smcpowers 
936f9fbec18Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
937f9fbec18Smcpowers 	ctxp = ctx->cc_provider_private;
938f9fbec18Smcpowers 
939f9fbec18Smcpowers 	switch (ctxp->mech_type) {
940f9fbec18Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
94123c57df7Smcpowers 		rv = crypto_digest_data(data, &(ctxp->sha1_ctx), NULL,
94223c57df7Smcpowers 		    (void (*)())SHA1Update, (void (*)())SHA1Final,
94323c57df7Smcpowers 		    CRYPTO_DO_SHA1 | CRYPTO_DO_UPDATE);
944f9fbec18Smcpowers 		break;
945f9fbec18Smcpowers 	default:
946f9fbec18Smcpowers 		rv = CRYPTO_MECHANISM_INVALID;
947f9fbec18Smcpowers 	}
948f9fbec18Smcpowers 
949f9fbec18Smcpowers 	if (rv != CRYPTO_SUCCESS)
950f9fbec18Smcpowers 		ecc_free_context(ctx);
951f9fbec18Smcpowers 
952f9fbec18Smcpowers 	return (rv);
953f9fbec18Smcpowers }
954f9fbec18Smcpowers 
955f9fbec18Smcpowers /* ARGSUSED */
956f9fbec18Smcpowers static int
ecc_verify_final(crypto_ctx_t * ctx,crypto_data_t * signature,crypto_req_handle_t req)957f9fbec18Smcpowers ecc_verify_final(crypto_ctx_t *ctx, crypto_data_t *signature,
958f9fbec18Smcpowers     crypto_req_handle_t req)
959f9fbec18Smcpowers {
960f9fbec18Smcpowers 	int rv;
961f9fbec18Smcpowers 	digest_ecc_ctx_t *ctxp;
962f9fbec18Smcpowers 
963f9fbec18Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
964f9fbec18Smcpowers 	ctxp = ctx->cc_provider_private;
965f9fbec18Smcpowers 
966f9fbec18Smcpowers 	rv = ecc_digest_svrfy_common(ctxp, NULL, signature,
96723c57df7Smcpowers 	    CRYPTO_DO_VERIFY | CRYPTO_DO_FINAL, req);
968f9fbec18Smcpowers 
969f9fbec18Smcpowers 	ecc_free_context(ctx);
970f9fbec18Smcpowers 
971f9fbec18Smcpowers 	return (rv);
972f9fbec18Smcpowers }
973f9fbec18Smcpowers 
974f9fbec18Smcpowers 
975f9fbec18Smcpowers /* ARGSUSED */
976f9fbec18Smcpowers static int
ecc_verify_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * data,crypto_data_t * signature,crypto_spi_ctx_template_t ctx_template,crypto_req_handle_t req)977f9fbec18Smcpowers ecc_verify_atomic(crypto_provider_handle_t provider,
978f9fbec18Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
979f9fbec18Smcpowers     crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
980f9fbec18Smcpowers     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
981f9fbec18Smcpowers {
982f9fbec18Smcpowers 	int rv;
983f9fbec18Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
984f9fbec18Smcpowers 	uchar_t *params;
985f9fbec18Smcpowers 	ssize_t params_len;
986f9fbec18Smcpowers 	ECParams  *ecparams;
987f9fbec18Smcpowers 	SECKEYECParams params_item;
988f9fbec18Smcpowers 	int kmflag;
989f9fbec18Smcpowers 
990f9fbec18Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
991f9fbec18Smcpowers 	    CKO_PUBLIC_KEY)) != CRYPTO_SUCCESS)
992f9fbec18Smcpowers 		return (rv);
993f9fbec18Smcpowers 
99423c57df7Smcpowers 	if (crypto_get_key_attr(key, CKA_EC_PARAMS, (void *) &params,
995f9fbec18Smcpowers 	    &params_len)) {
996f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
997f9fbec18Smcpowers 	}
998f9fbec18Smcpowers 
999f9fbec18Smcpowers 	/* ASN1 check */
1000f9fbec18Smcpowers 	if (params[0] != 0x06 ||
1001f9fbec18Smcpowers 	    params[1] != params_len - 2) {
1002f9fbec18Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
1003f9fbec18Smcpowers 	}
1004f9fbec18Smcpowers 	params_item.data = params;
1005f9fbec18Smcpowers 	params_item.len = (uint_t)params_len;
1006f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
1007f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
1008f9fbec18Smcpowers 		/* bad curve OID */
1009f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
1010f9fbec18Smcpowers 	}
1011f9fbec18Smcpowers 
1012f9fbec18Smcpowers 	if (mechanism->cm_type == ECDSA_MECH_INFO_TYPE) {
1013f9fbec18Smcpowers 		ecc_ctx_t ctx;
1014f9fbec18Smcpowers 
1015f9fbec18Smcpowers 		ctx.mech_type = mech_type;
1016f9fbec18Smcpowers 		/* structure assignment */
1017f9fbec18Smcpowers 		ctx.ecparams = *ecparams;
1018f9fbec18Smcpowers 		ctx.key = key;
1019f9fbec18Smcpowers 		rv = ecc_verify_common(&ctx, data, signature, req);
1020f9fbec18Smcpowers 	} else {
1021f9fbec18Smcpowers 		digest_ecc_ctx_t dctx;
1022f9fbec18Smcpowers 
1023f9fbec18Smcpowers 		dctx.mech_type = mech_type;
1024f9fbec18Smcpowers 		/* structure assignment */
1025f9fbec18Smcpowers 		dctx.ecparams = *ecparams;
1026f9fbec18Smcpowers 		dctx.key = key;
1027f9fbec18Smcpowers 		SHA1Init(&(dctx.sha1_ctx));
1028f9fbec18Smcpowers 
1029f9fbec18Smcpowers 		rv = ecc_digest_svrfy_common(&dctx, data, signature,
103023c57df7Smcpowers 		    CRYPTO_DO_VERIFY | CRYPTO_DO_UPDATE | CRYPTO_DO_FINAL, req);
1031f9fbec18Smcpowers 	}
1032f9fbec18Smcpowers 	free_ecparams(ecparams, B_TRUE);
1033f9fbec18Smcpowers 	return (rv);
1034f9fbec18Smcpowers }
1035f9fbec18Smcpowers 
1036f9fbec18Smcpowers /* ARGSUSED */
1037f9fbec18Smcpowers static int
ecc_nostore_key_generate_pair(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_object_attribute_t * pub_template,uint_t pub_attribute_count,crypto_object_attribute_t * pri_template,uint_t pri_attribute_count,crypto_object_attribute_t * pub_out_template,uint_t pub_out_attribute_count,crypto_object_attribute_t * pri_out_template,uint_t pri_out_attribute_count,crypto_req_handle_t req)1038f9fbec18Smcpowers ecc_nostore_key_generate_pair(crypto_provider_handle_t provider,
1039f9fbec18Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1040f9fbec18Smcpowers     crypto_object_attribute_t *pub_template, uint_t pub_attribute_count,
1041f9fbec18Smcpowers     crypto_object_attribute_t *pri_template, uint_t pri_attribute_count,
1042f9fbec18Smcpowers     crypto_object_attribute_t *pub_out_template, uint_t pub_out_attribute_count,
1043f9fbec18Smcpowers     crypto_object_attribute_t *pri_out_template, uint_t pri_out_attribute_count,
1044f9fbec18Smcpowers     crypto_req_handle_t req)
1045f9fbec18Smcpowers {
1046f9fbec18Smcpowers 	int rv = CRYPTO_SUCCESS;
1047f9fbec18Smcpowers 	ECPrivateKey *privKey;	/* contains both public and private values */
1048f9fbec18Smcpowers 	ECParams *ecparams;
1049f9fbec18Smcpowers 	SECKEYECParams params_item;
1050f9fbec18Smcpowers 	ulong_t pub_key_type = ~0UL, pub_class = ~0UL;
1051f9fbec18Smcpowers 	ulong_t pri_key_type = ~0UL, pri_class = ~0UL;
1052f9fbec18Smcpowers 	int params_idx, value_idx, point_idx;
1053f9fbec18Smcpowers 	uchar_t *params = NULL;
1054f9fbec18Smcpowers 	unsigned params_len;
1055f9fbec18Smcpowers 	uchar_t *value = NULL;
1056f9fbec18Smcpowers 	uchar_t *point = NULL;
1057f9fbec18Smcpowers 	int valuelen;
1058f9fbec18Smcpowers 	int pointlen;
1059f9fbec18Smcpowers 	int xylen;
1060f9fbec18Smcpowers 	int kmflag;
1061f9fbec18Smcpowers 
1062f9fbec18Smcpowers 	if (mechanism->cm_type != EC_KEY_PAIR_GEN_MECH_INFO_TYPE) {
1063f9fbec18Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
1064f9fbec18Smcpowers 	}
1065f9fbec18Smcpowers 
1066f9fbec18Smcpowers 	/* optional */
1067f9fbec18Smcpowers 	(void) get_template_attr_ulong(pub_template,
1068f9fbec18Smcpowers 	    pub_attribute_count, CKA_CLASS, &pub_class);
1069f9fbec18Smcpowers 
1070f9fbec18Smcpowers 	/* optional */
1071f9fbec18Smcpowers 	(void) get_template_attr_ulong(pri_template,
1072f9fbec18Smcpowers 	    pri_attribute_count, CKA_CLASS, &pri_class);
1073f9fbec18Smcpowers 
1074f9fbec18Smcpowers 	/* optional */
1075f9fbec18Smcpowers 	(void) get_template_attr_ulong(pub_template,
1076f9fbec18Smcpowers 	    pub_attribute_count, CKA_KEY_TYPE, &pub_key_type);
1077f9fbec18Smcpowers 
1078f9fbec18Smcpowers 	/* optional */
1079f9fbec18Smcpowers 	(void) get_template_attr_ulong(pri_template,
1080f9fbec18Smcpowers 	    pri_attribute_count, CKA_KEY_TYPE, &pri_key_type);
1081f9fbec18Smcpowers 
1082f9fbec18Smcpowers 	if (pub_class != ~0UL && pub_class != CKO_PUBLIC_KEY) {
1083f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
1084f9fbec18Smcpowers 	}
1085f9fbec18Smcpowers 	pub_class = CKO_PUBLIC_KEY;
1086f9fbec18Smcpowers 
1087f9fbec18Smcpowers 	if (pri_class != ~0UL && pri_class != CKO_PRIVATE_KEY) {
1088f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
1089f9fbec18Smcpowers 	}
1090f9fbec18Smcpowers 	pri_class = CKO_PRIVATE_KEY;
1091f9fbec18Smcpowers 
1092f9fbec18Smcpowers 	if (pub_key_type != ~0UL && pub_key_type != CKK_EC) {
1093f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
1094f9fbec18Smcpowers 	}
1095f9fbec18Smcpowers 	pub_key_type = CKK_EC;
1096f9fbec18Smcpowers 
1097f9fbec18Smcpowers 	if (pri_key_type != ~0UL && pri_key_type != CKK_EC) {
1098f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
1099f9fbec18Smcpowers 	}
1100f9fbec18Smcpowers 	pri_key_type = CKK_EC;
1101f9fbec18Smcpowers 
1102f9fbec18Smcpowers 	/* public output template must contain CKA_EC_POINT attribute */
1103f9fbec18Smcpowers 	if ((point_idx = find_attr(pub_out_template, pub_out_attribute_count,
1104f9fbec18Smcpowers 	    CKA_EC_POINT)) == -1) {
1105f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
1106f9fbec18Smcpowers 	}
1107f9fbec18Smcpowers 
1108f9fbec18Smcpowers 	/* private output template must contain CKA_VALUE attribute */
1109f9fbec18Smcpowers 	if ((value_idx = find_attr(pri_out_template, pri_out_attribute_count,
1110f9fbec18Smcpowers 	    CKA_VALUE)) == -1) {
1111f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
1112f9fbec18Smcpowers 	}
1113f9fbec18Smcpowers 
1114f9fbec18Smcpowers 	if ((params_idx = find_attr(pub_template, pub_attribute_count,
1115f9fbec18Smcpowers 	    CKA_EC_PARAMS)) == -1) {
1116f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
1117f9fbec18Smcpowers 	}
1118f9fbec18Smcpowers 
1119f9fbec18Smcpowers 	params = (uchar_t *)pub_template[params_idx].oa_value;
1120f9fbec18Smcpowers 	params_len = pub_template[params_idx].oa_value_len;
1121f9fbec18Smcpowers 
1122f9fbec18Smcpowers 	value = (uchar_t *)pri_out_template[value_idx].oa_value;
1123f9fbec18Smcpowers 	valuelen = (int)pri_out_template[value_idx].oa_value_len;
1124f9fbec18Smcpowers 	point = (uchar_t *)pub_out_template[point_idx].oa_value;
1125f9fbec18Smcpowers 	pointlen = (int)pub_out_template[point_idx].oa_value_len;
1126f9fbec18Smcpowers 
1127f9fbec18Smcpowers 	/* ASN1 check */
1128f9fbec18Smcpowers 	if (params[0] != 0x06 ||
1129f9fbec18Smcpowers 	    params[1] != params_len - 2) {
1130f9fbec18Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
1131f9fbec18Smcpowers 	}
1132f9fbec18Smcpowers 	params_item.data = params;
1133f9fbec18Smcpowers 	params_item.len = params_len;
1134f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
1135f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
1136f9fbec18Smcpowers 		/* bad curve OID */
1137f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
1138f9fbec18Smcpowers 	}
1139f9fbec18Smcpowers 
1140f9fbec18Smcpowers 	if (EC_NewKey(ecparams, &privKey, kmflag) != SECSuccess) {
1141f9fbec18Smcpowers 		free_ecparams(ecparams, B_TRUE);
1142f9fbec18Smcpowers 		return (CRYPTO_FAILED);
1143f9fbec18Smcpowers 	}
1144f9fbec18Smcpowers 
1145f9fbec18Smcpowers 	xylen = privKey->publicValue.len;
1146f9fbec18Smcpowers 	/* ASSERT that xylen - 1 is divisible by 2 */
1147f9fbec18Smcpowers 	if (xylen > pointlen) {
1148f9fbec18Smcpowers 		rv = CRYPTO_BUFFER_TOO_SMALL;
1149f9fbec18Smcpowers 		goto out;
1150f9fbec18Smcpowers 	}
1151f9fbec18Smcpowers 
1152f9fbec18Smcpowers 	if (privKey->privateValue.len > valuelen) {
1153f9fbec18Smcpowers 		rv = CRYPTO_BUFFER_TOO_SMALL;
1154f9fbec18Smcpowers 		goto out;
1155f9fbec18Smcpowers 	}
1156f9fbec18Smcpowers 	bcopy(privKey->privateValue.data, value, privKey->privateValue.len);
1157f9fbec18Smcpowers 	pri_out_template[value_idx].oa_value_len = privKey->privateValue.len;
1158f9fbec18Smcpowers 
1159f9fbec18Smcpowers 	bcopy(privKey->publicValue.data, point, xylen);
1160f9fbec18Smcpowers 	pub_out_template[point_idx].oa_value_len = xylen;
1161f9fbec18Smcpowers 
1162f9fbec18Smcpowers out:
1163f9fbec18Smcpowers 	free_ecprivkey(privKey);
1164f9fbec18Smcpowers 	free_ecparams(ecparams, B_TRUE);
1165f9fbec18Smcpowers 	return (rv);
1166f9fbec18Smcpowers }
1167f9fbec18Smcpowers 
1168f9fbec18Smcpowers /* ARGSUSED */
1169f9fbec18Smcpowers static int
ecc_nostore_key_derive(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * base_key,crypto_object_attribute_t * in_attrs,uint_t in_attr_count,crypto_object_attribute_t * out_attrs,uint_t out_attr_count,crypto_req_handle_t req)1170f9fbec18Smcpowers ecc_nostore_key_derive(crypto_provider_handle_t provider,
1171f9fbec18Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
1172f9fbec18Smcpowers     crypto_key_t *base_key, crypto_object_attribute_t *in_attrs,
1173f9fbec18Smcpowers     uint_t in_attr_count, crypto_object_attribute_t *out_attrs,
1174f9fbec18Smcpowers     uint_t out_attr_count, crypto_req_handle_t req)
1175f9fbec18Smcpowers {
1176f9fbec18Smcpowers 	int rv = CRYPTO_SUCCESS;
1177f9fbec18Smcpowers 	int params_idx, value_idx = -1, out_value_idx = -1;
1178f9fbec18Smcpowers 	ulong_t key_type;
1179f9fbec18Smcpowers 	ulong_t key_len;
1180f9fbec18Smcpowers 	crypto_object_attribute_t *attrs;
1181f9fbec18Smcpowers 	ECParams *ecparams;
1182f9fbec18Smcpowers 	SECKEYECParams params_item;
1183f9fbec18Smcpowers 	CK_ECDH1_DERIVE_PARAMS *mech_param;
1184f9fbec18Smcpowers 	SECItem public_value_item, private_value_item, secret_item;
1185f9fbec18Smcpowers 	int kmflag;
1186f9fbec18Smcpowers 
1187f9fbec18Smcpowers 	if (mechanism->cm_type != ECDH1_DERIVE_MECH_INFO_TYPE) {
1188f9fbec18Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
1189f9fbec18Smcpowers 	}
1190f9fbec18Smcpowers 
1191f9fbec18Smcpowers 	ASSERT(IS_P2ALIGNED(mechanism->cm_param, sizeof (uint64_t)));
1192f9fbec18Smcpowers 	/* LINTED: pointer alignment */
1193f9fbec18Smcpowers 	mech_param = (CK_ECDH1_DERIVE_PARAMS *)mechanism->cm_param;
1194f9fbec18Smcpowers 	if (mech_param->kdf != CKD_NULL) {
1195f9fbec18Smcpowers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
1196f9fbec18Smcpowers 	}
1197f9fbec18Smcpowers 
1198f9fbec18Smcpowers 	if ((base_key->ck_format != CRYPTO_KEY_ATTR_LIST) ||
1199f9fbec18Smcpowers 	    (base_key->ck_count == 0)) {
1200f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
1201f9fbec18Smcpowers 	}
1202f9fbec18Smcpowers 
1203f9fbec18Smcpowers 	if ((rv = get_template_attr_ulong(in_attrs, in_attr_count,
1204f9fbec18Smcpowers 	    CKA_KEY_TYPE, &key_type)) != CRYPTO_SUCCESS) {
1205f9fbec18Smcpowers 		return (rv);
1206f9fbec18Smcpowers 	}
1207f9fbec18Smcpowers 
1208f9fbec18Smcpowers 	switch (key_type) {
1209f9fbec18Smcpowers 	case CKK_DES:
1210f9fbec18Smcpowers 		key_len = DES_KEYSIZE;
1211f9fbec18Smcpowers 		break;
1212f9fbec18Smcpowers 	case CKK_DES2:
1213f9fbec18Smcpowers 		key_len = DES2_KEYSIZE;
1214f9fbec18Smcpowers 		break;
1215f9fbec18Smcpowers 	case CKK_DES3:
1216f9fbec18Smcpowers 		key_len = DES3_KEYSIZE;
1217f9fbec18Smcpowers 		break;
1218f9fbec18Smcpowers 	case CKK_RC4:
1219f9fbec18Smcpowers 	case CKK_AES:
1220f9fbec18Smcpowers 	case CKK_GENERIC_SECRET:
1221f9fbec18Smcpowers 		if ((rv = get_template_attr_ulong(in_attrs, in_attr_count,
1222f9fbec18Smcpowers 		    CKA_VALUE_LEN, &key_len)) != CRYPTO_SUCCESS) {
1223f9fbec18Smcpowers 			return (rv);
1224f9fbec18Smcpowers 		}
1225f9fbec18Smcpowers 		break;
1226f9fbec18Smcpowers 	default:
1227f9fbec18Smcpowers 		key_len = 0;
1228f9fbec18Smcpowers 	}
1229f9fbec18Smcpowers 
1230f9fbec18Smcpowers 	attrs = base_key->ck_attrs;
1231f9fbec18Smcpowers 	if ((value_idx = find_attr(attrs, base_key->ck_count,
1232f9fbec18Smcpowers 	    CKA_VALUE)) == -1) {
1233f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
1234f9fbec18Smcpowers 	}
1235f9fbec18Smcpowers 
1236f9fbec18Smcpowers 	if ((params_idx = find_attr(attrs, base_key->ck_count,
1237f9fbec18Smcpowers 	    CKA_EC_PARAMS)) == -1) {
1238f9fbec18Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
1239f9fbec18Smcpowers 	}
1240f9fbec18Smcpowers 
1241f9fbec18Smcpowers 	private_value_item.data = (uchar_t *)attrs[value_idx].oa_value;
1242f9fbec18Smcpowers 	private_value_item.len = attrs[value_idx].oa_value_len;
1243f9fbec18Smcpowers 
1244f9fbec18Smcpowers 	params_item.len = attrs[params_idx].oa_value_len;
1245f9fbec18Smcpowers 	params_item.data = (uchar_t *)attrs[params_idx].oa_value;
1246f9fbec18Smcpowers 
1247f9fbec18Smcpowers 	/* ASN1 check */
1248f9fbec18Smcpowers 	if (params_item.data[0] != 0x06 ||
1249f9fbec18Smcpowers 	    params_item.data[1] != params_item.len - 2) {
1250f9fbec18Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
1251f9fbec18Smcpowers 	}
1252f9fbec18Smcpowers 	kmflag = crypto_kmflag(req);
1253f9fbec18Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
1254f9fbec18Smcpowers 		/* bad curve OID */
1255f9fbec18Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
1256f9fbec18Smcpowers 	}
1257f9fbec18Smcpowers 
1258f9fbec18Smcpowers 	public_value_item.data = (uchar_t *)mech_param->pPublicData;
1259f9fbec18Smcpowers 	public_value_item.len = mech_param->ulPublicDataLen;
1260f9fbec18Smcpowers 
1261f9fbec18Smcpowers 	if ((out_value_idx = find_attr(out_attrs, out_attr_count,
1262f9fbec18Smcpowers 	    CKA_VALUE)) == -1) {
1263f9fbec18Smcpowers 		rv = CRYPTO_TEMPLATE_INCOMPLETE;
1264f9fbec18Smcpowers 		goto out;
1265f9fbec18Smcpowers 	}
1266f9fbec18Smcpowers 	secret_item.data = NULL;
1267f9fbec18Smcpowers 	secret_item.len = 0;
1268f9fbec18Smcpowers 
1269f9fbec18Smcpowers 	if (ECDH_Derive(&public_value_item, ecparams, &private_value_item,
1270f9fbec18Smcpowers 	    B_FALSE, &secret_item, kmflag) != SECSuccess) {
1271f9fbec18Smcpowers 		free_ecparams(ecparams, B_TRUE);
1272f9fbec18Smcpowers 		return (CRYPTO_FAILED);
1273f9fbec18Smcpowers 	} else {
1274f9fbec18Smcpowers 		rv = CRYPTO_SUCCESS;
1275f9fbec18Smcpowers 	}
1276f9fbec18Smcpowers 
1277f9fbec18Smcpowers 	if (key_len == 0)
1278f9fbec18Smcpowers 		key_len = secret_item.len;
1279f9fbec18Smcpowers 
1280f9fbec18Smcpowers 	if (key_len > secret_item.len) {
1281f9fbec18Smcpowers 		rv = CRYPTO_ATTRIBUTE_VALUE_INVALID;
1282f9fbec18Smcpowers 		goto out;
1283f9fbec18Smcpowers 	}
1284f9fbec18Smcpowers 	if (key_len > out_attrs[out_value_idx].oa_value_len) {
1285f9fbec18Smcpowers 		rv = CRYPTO_BUFFER_TOO_SMALL;
1286f9fbec18Smcpowers 		goto out;
1287f9fbec18Smcpowers 	}
1288f9fbec18Smcpowers 	bcopy(secret_item.data + secret_item.len - key_len,
1289f9fbec18Smcpowers 	    (uchar_t *)out_attrs[out_value_idx].oa_value, key_len);
1290f9fbec18Smcpowers 	out_attrs[out_value_idx].oa_value_len = key_len;
1291f9fbec18Smcpowers out:
1292f9fbec18Smcpowers 	free_ecparams(ecparams, B_TRUE);
1293f9fbec18Smcpowers 	SECITEM_FreeItem(&secret_item, B_FALSE);
1294f9fbec18Smcpowers 	return (rv);
1295f9fbec18Smcpowers }
1296f9fbec18Smcpowers 
1297f9fbec18Smcpowers static void
free_ecparams(ECParams * params,boolean_t freeit)1298f9fbec18Smcpowers free_ecparams(ECParams *params, boolean_t freeit)
1299f9fbec18Smcpowers {
1300f9fbec18Smcpowers 	SECITEM_FreeItem(&params->fieldID.u.prime, B_FALSE);
1301f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curve.a, B_FALSE);
1302f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curve.b, B_FALSE);
1303f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
1304f9fbec18Smcpowers 	SECITEM_FreeItem(&params->base, B_FALSE);
1305f9fbec18Smcpowers 	SECITEM_FreeItem(&params->order, B_FALSE);
1306f9fbec18Smcpowers 	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
1307f9fbec18Smcpowers 	SECITEM_FreeItem(&params->curveOID, B_FALSE);
1308f9fbec18Smcpowers 	if (freeit)
1309f9fbec18Smcpowers 		kmem_free(params, sizeof (ECParams));
1310f9fbec18Smcpowers }
1311f9fbec18Smcpowers 
1312f9fbec18Smcpowers static void
free_ecprivkey(ECPrivateKey * key)1313f9fbec18Smcpowers free_ecprivkey(ECPrivateKey *key)
1314f9fbec18Smcpowers {
1315f9fbec18Smcpowers 	free_ecparams(&key->ecParams, B_FALSE);
1316f9fbec18Smcpowers 	SECITEM_FreeItem(&key->publicValue, B_FALSE);
1317f9fbec18Smcpowers 	bzero(key->privateValue.data, key->privateValue.len);
1318f9fbec18Smcpowers 	SECITEM_FreeItem(&key->privateValue, B_FALSE);
1319f9fbec18Smcpowers 	SECITEM_FreeItem(&key->version, B_FALSE);
1320f9fbec18Smcpowers 	kmem_free(key, sizeof (ECPrivateKey));
1321f9fbec18Smcpowers }
1322