xref: /onnv-gate/usr/src/uts/common/crypto/io/ecc.c (revision 10732:498ac26a63d5)
15697Smcpowers /*
25697Smcpowers  * CDDL HEADER START
35697Smcpowers  *
45697Smcpowers  * The contents of this file are subject to the terms of the
55697Smcpowers  * Common Development and Distribution License (the "License").
65697Smcpowers  * You may not use this file except in compliance with the License.
75697Smcpowers  *
85697Smcpowers  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95697Smcpowers  * or http://www.opensolaris.org/os/licensing.
105697Smcpowers  * See the License for the specific language governing permissions
115697Smcpowers  * and limitations under the License.
125697Smcpowers  *
135697Smcpowers  * When distributing Covered Code, include this CDDL HEADER in each
145697Smcpowers  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155697Smcpowers  * If applicable, add the following below this CDDL HEADER, with the
165697Smcpowers  * fields enclosed by brackets "[]" replaced with your own identifying
175697Smcpowers  * information: Portions Copyright [yyyy] [name of copyright owner]
185697Smcpowers  *
195697Smcpowers  * CDDL HEADER END
205697Smcpowers  */
215697Smcpowers /*
2210500SHai-May.Chao@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235697Smcpowers  * Use is subject to license terms.
245697Smcpowers  */
255697Smcpowers 
265697Smcpowers #include <sys/types.h>
275697Smcpowers #include <sys/systm.h>
285697Smcpowers #include <sys/param.h>
295697Smcpowers #include <sys/modctl.h>
305697Smcpowers #include <sys/ddi.h>
315697Smcpowers #include <sys/crypto/spi.h>
327188Smcpowers #include <sys/crypto/impl.h>
3310500SHai-May.Chao@Sun.COM #include <sys/crypto/ioctladmin.h>
345697Smcpowers #include <sys/sysmacros.h>
355697Smcpowers #include <sys/strsun.h>
365697Smcpowers #include <sys/sha1.h>
375697Smcpowers #include <sys/random.h>
385697Smcpowers #include <sys/conf.h>
395697Smcpowers #include <sys/devops.h>
405697Smcpowers #include <sys/sunddi.h>
415697Smcpowers #include <sys/varargs.h>
425697Smcpowers #include <sys/kmem.h>
435697Smcpowers #include <sys/kstat.h>
445697Smcpowers 
4510500SHai-May.Chao@Sun.COM #include <des/des_impl.h>
4610500SHai-May.Chao@Sun.COM #include <ecc/ecc_impl.h>
475697Smcpowers 
485697Smcpowers #define	CKD_NULL		0x00000001
495697Smcpowers 
505697Smcpowers extern struct mod_ops mod_cryptoops;
515697Smcpowers 
525697Smcpowers /*
535697Smcpowers  * Module linkage information for the kernel.
545697Smcpowers  */
555697Smcpowers static struct modlcrypto modlcrypto = {
565697Smcpowers 	&mod_cryptoops,
575697Smcpowers 	"EC Kernel SW Provider"
585697Smcpowers };
595697Smcpowers 
605697Smcpowers static struct modlinkage modlinkage = {
615697Smcpowers 	MODREV_1,
625697Smcpowers 	(void *)&modlcrypto,
635697Smcpowers 	NULL
645697Smcpowers };
655697Smcpowers 
665697Smcpowers /*
675697Smcpowers  * CSPI information (entry points, provider info, etc.)
685697Smcpowers  */
695697Smcpowers typedef enum ecc_mech_type {
705697Smcpowers 	EC_KEY_PAIR_GEN_MECH_INFO_TYPE,	/* SUN_CKM_EC_KEY_PAIR_GEN */
715697Smcpowers 	ECDSA_MECH_INFO_TYPE,		/* SUN_CKM_ECDSA */
725697Smcpowers 	ECDSA_SHA1_MECH_INFO_TYPE,	/* SUN_CKM_ECDSA_SHA1 */
735697Smcpowers 	ECDH1_DERIVE_MECH_INFO_TYPE	/* SUN_CKM_ECDH1_DERIVE */
745697Smcpowers } ecc_mech_type_t;
755697Smcpowers 
765697Smcpowers /*
775697Smcpowers  * Context for ECDSA mechanism.
785697Smcpowers  */
795697Smcpowers typedef struct ecc_ctx {
805697Smcpowers 	ecc_mech_type_t	mech_type;
815697Smcpowers 	crypto_key_t *key;
825697Smcpowers 	size_t keychunk_size;
835697Smcpowers 	ECParams ecparams;
845697Smcpowers } ecc_ctx_t;
855697Smcpowers 
865697Smcpowers /*
875697Smcpowers  * Context for ECDSA_SHA1 mechanism.
885697Smcpowers  */
895697Smcpowers typedef struct digest_ecc_ctx {
905697Smcpowers 	ecc_mech_type_t	mech_type;
915697Smcpowers 	crypto_key_t *key;
925697Smcpowers 	size_t keychunk_size;
935697Smcpowers 	ECParams ecparams;
945697Smcpowers 	union {
955697Smcpowers 		SHA1_CTX sha1ctx;
965697Smcpowers 	} dctx_u;
975697Smcpowers } digest_ecc_ctx_t;
985697Smcpowers 
995697Smcpowers #define	sha1_ctx	dctx_u.sha1ctx
1005697Smcpowers 
1015697Smcpowers /*
1025697Smcpowers  * Mechanism info structure passed to KCF during registration.
1035697Smcpowers  */
1045697Smcpowers static crypto_mech_info_t ecc_mech_info_tab[] = {
1055697Smcpowers 	/* EC_KEY_PAIR_GEN */
1065697Smcpowers 	{SUN_CKM_EC_KEY_PAIR_GEN, EC_KEY_PAIR_GEN_MECH_INFO_TYPE,
1075697Smcpowers 	    CRYPTO_FG_GENERATE_KEY_PAIR, EC_MIN_KEY_LEN, EC_MAX_KEY_LEN,
1085697Smcpowers 	    CRYPTO_KEYSIZE_UNIT_IN_BITS},
1095697Smcpowers 	/* ECDH */
1105697Smcpowers 	{SUN_CKM_ECDH1_DERIVE, ECDH1_DERIVE_MECH_INFO_TYPE, CRYPTO_FG_DERIVE,
1115697Smcpowers 	    EC_MIN_KEY_LEN, EC_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BITS},
1125697Smcpowers 	/* ECDSA */
1135697Smcpowers 	{SUN_CKM_ECDSA, ECDSA_MECH_INFO_TYPE,
1145697Smcpowers 	    CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY |
1155697Smcpowers 	    CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC,
1165697Smcpowers 	    EC_MIN_KEY_LEN, EC_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BITS},
1175697Smcpowers 	/* ECDSA_SHA1 */
1185697Smcpowers 	{SUN_CKM_ECDSA_SHA1, ECDSA_SHA1_MECH_INFO_TYPE,
1195697Smcpowers 	    CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY |
1205697Smcpowers 	    CRYPTO_FG_SIGN_ATOMIC | CRYPTO_FG_VERIFY_ATOMIC,
1215697Smcpowers 	    EC_MIN_KEY_LEN, EC_MAX_KEY_LEN, CRYPTO_KEYSIZE_UNIT_IN_BITS}
1225697Smcpowers };
1235697Smcpowers 
1245697Smcpowers static void ecc_provider_status(crypto_provider_handle_t, uint_t *);
1255697Smcpowers 
1265697Smcpowers static crypto_control_ops_t ecc_control_ops = {
1275697Smcpowers 	ecc_provider_status
1285697Smcpowers };
1295697Smcpowers 
1305697Smcpowers static int ecc_sign_init(crypto_ctx_t *, crypto_mechanism_t *,
1315697Smcpowers     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1325697Smcpowers static int ecc_sign(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1335697Smcpowers     crypto_req_handle_t);
1345697Smcpowers static int ecc_sign_update(crypto_ctx_t *, crypto_data_t *,
1355697Smcpowers     crypto_req_handle_t);
1365697Smcpowers static int ecc_sign_final(crypto_ctx_t *, crypto_data_t *,
1375697Smcpowers     crypto_req_handle_t);
1385697Smcpowers static int ecc_sign_atomic(crypto_provider_handle_t, crypto_session_id_t,
1395697Smcpowers     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
1405697Smcpowers     crypto_spi_ctx_template_t, crypto_req_handle_t);
1415697Smcpowers 
1425697Smcpowers static crypto_sign_ops_t ecc_sign_ops = {
1435697Smcpowers 	ecc_sign_init,
1445697Smcpowers 	ecc_sign,
1455697Smcpowers 	ecc_sign_update,
1465697Smcpowers 	ecc_sign_final,
1475697Smcpowers 	ecc_sign_atomic,
1485697Smcpowers 	NULL,
1495697Smcpowers 	NULL,
1505697Smcpowers 	NULL
1515697Smcpowers };
1525697Smcpowers 
1535697Smcpowers static int ecc_verify_init(crypto_ctx_t *, crypto_mechanism_t *,
1545697Smcpowers     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1555697Smcpowers static int ecc_verify(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1565697Smcpowers     crypto_req_handle_t);
1575697Smcpowers static int ecc_verify_update(crypto_ctx_t *, crypto_data_t *,
1585697Smcpowers     crypto_req_handle_t);
1595697Smcpowers static int ecc_verify_final(crypto_ctx_t *, crypto_data_t *,
1605697Smcpowers     crypto_req_handle_t);
1615697Smcpowers static int ecc_verify_atomic(crypto_provider_handle_t, crypto_session_id_t,
1625697Smcpowers     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1635697Smcpowers     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1645697Smcpowers 
1655697Smcpowers static crypto_verify_ops_t ecc_verify_ops = {
1665697Smcpowers 	ecc_verify_init,
1675697Smcpowers 	ecc_verify,
1685697Smcpowers 	ecc_verify_update,
1695697Smcpowers 	ecc_verify_final,
1705697Smcpowers 	ecc_verify_atomic,
1715697Smcpowers 	NULL,
1725697Smcpowers 	NULL,
1735697Smcpowers 	NULL
1745697Smcpowers };
1755697Smcpowers 
1765697Smcpowers static int ecc_nostore_key_generate_pair(crypto_provider_handle_t,
1775697Smcpowers     crypto_session_id_t, crypto_mechanism_t *, crypto_object_attribute_t *,
1785697Smcpowers     uint_t, crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
1795697Smcpowers     uint_t, crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
1805697Smcpowers static int ecc_nostore_key_derive(crypto_provider_handle_t,
1815697Smcpowers     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
1825697Smcpowers     crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
1835697Smcpowers     uint_t, crypto_req_handle_t);
1845697Smcpowers 
1855697Smcpowers static crypto_nostore_key_ops_t ecc_nostore_key_ops = {
1865697Smcpowers 	NULL,
1875697Smcpowers 	ecc_nostore_key_generate_pair,
1885697Smcpowers 	ecc_nostore_key_derive
1895697Smcpowers };
1905697Smcpowers 
191*10732SAnthony.Scarpino@Sun.COM static void ecc_POST(int *);
192*10732SAnthony.Scarpino@Sun.COM 
193*10732SAnthony.Scarpino@Sun.COM static crypto_fips140_ops_t ecc_fips140_ops = {
194*10732SAnthony.Scarpino@Sun.COM 	ecc_POST
195*10732SAnthony.Scarpino@Sun.COM };
196*10732SAnthony.Scarpino@Sun.COM 
197*10732SAnthony.Scarpino@Sun.COM 
1985697Smcpowers static crypto_ops_t ecc_crypto_ops = {
1995697Smcpowers 	&ecc_control_ops,
2005697Smcpowers 	NULL,
2015697Smcpowers 	NULL,
2025697Smcpowers 	NULL,
2035697Smcpowers 	&ecc_sign_ops,
2045697Smcpowers 	&ecc_verify_ops,
2055697Smcpowers 	NULL,
2065697Smcpowers 	NULL,
2075697Smcpowers 	NULL,
2085697Smcpowers 	NULL,
2095697Smcpowers 	NULL,
2105697Smcpowers 	NULL,
2115697Smcpowers 	NULL,
2125697Smcpowers 	NULL,
2135697Smcpowers 	NULL,
214*10732SAnthony.Scarpino@Sun.COM 	&ecc_nostore_key_ops,
215*10732SAnthony.Scarpino@Sun.COM 	&ecc_fips140_ops
2165697Smcpowers };
2175697Smcpowers 
2185697Smcpowers static crypto_provider_info_t ecc_prov_info = {
219*10732SAnthony.Scarpino@Sun.COM 	CRYPTO_SPI_VERSION_4,
2205697Smcpowers 	"EC Software Provider",
2215697Smcpowers 	CRYPTO_SW_PROVIDER,
2225697Smcpowers 	{&modlinkage},
2235697Smcpowers 	NULL,
2245697Smcpowers 	&ecc_crypto_ops,
2255697Smcpowers 	sizeof (ecc_mech_info_tab)/sizeof (crypto_mech_info_t),
2265697Smcpowers 	ecc_mech_info_tab
2275697Smcpowers };
2285697Smcpowers 
2295697Smcpowers static crypto_kcf_provider_handle_t ecc_prov_handle = NULL;
2305697Smcpowers 
2315697Smcpowers static int ecc_sign_common(ecc_ctx_t *, crypto_data_t *, crypto_data_t *,
2325697Smcpowers     crypto_req_handle_t);
2335697Smcpowers static int ecc_verify_common(ecc_ctx_t *, crypto_data_t *, crypto_data_t *,
2345697Smcpowers     crypto_req_handle_t);
2355697Smcpowers static int find_attr(crypto_object_attribute_t *, uint_t, uint64_t);
2365697Smcpowers static int get_template_attr_ulong(crypto_object_attribute_t *,
2375697Smcpowers     uint_t, uint64_t, ulong_t *);
2385697Smcpowers static void ecc_free_context(crypto_ctx_t *);
2395697Smcpowers static void free_ecparams(ECParams *, boolean_t);
2405697Smcpowers static void free_ecprivkey(ECPrivateKey *);
2415697Smcpowers 
24210500SHai-May.Chao@Sun.COM static int fips_pairwise_check(ECPrivateKey *);
24310500SHai-May.Chao@Sun.COM extern int fips_ecdsa_post(void);
24410500SHai-May.Chao@Sun.COM 
24510500SHai-May.Chao@Sun.COM 
2465697Smcpowers int
2475697Smcpowers _init(void)
2485697Smcpowers {
2495697Smcpowers 	int ret;
2505697Smcpowers 
2515697Smcpowers 	/*
2525697Smcpowers 	 * Register with KCF. If the registration fails, return error.
2535697Smcpowers 	 */
2545697Smcpowers 	if ((ret = crypto_register_provider(&ecc_prov_info,
2555697Smcpowers 	    &ecc_prov_handle)) != CRYPTO_SUCCESS) {
2565697Smcpowers 		cmn_err(CE_WARN, "ecc _init: crypto_register_provider()"
2575697Smcpowers 		    "failed (0x%x)", ret);
2585697Smcpowers 		return (EACCES);
2595697Smcpowers 	}
2605697Smcpowers 
2615697Smcpowers 	if ((ret = mod_install(&modlinkage)) != 0) {
2625697Smcpowers 		int rv;
2635697Smcpowers 
2645697Smcpowers 		ASSERT(ecc_prov_handle != NULL);
2655697Smcpowers 		/* We should not return if the unregister returns busy. */
2665697Smcpowers 		while ((rv = crypto_unregister_provider(ecc_prov_handle))
2675697Smcpowers 		    == CRYPTO_BUSY) {
2685697Smcpowers 			cmn_err(CE_WARN, "ecc _init: "
2695697Smcpowers 			    "crypto_unregister_provider() "
2705697Smcpowers 			    "failed (0x%x). Retrying.", rv);
2715697Smcpowers 			/* wait 10 seconds and try again. */
2725697Smcpowers 			delay(10 * drv_usectohz(1000000));
2735697Smcpowers 		}
2745697Smcpowers 	}
2755697Smcpowers 
2765697Smcpowers 	return (ret);
2775697Smcpowers }
2785697Smcpowers 
2795697Smcpowers int
2805697Smcpowers _fini(void)
2815697Smcpowers {
2825697Smcpowers 	int ret;
2835697Smcpowers 
2845697Smcpowers 	/*
2855697Smcpowers 	 * Unregister from KCF if previous registration succeeded.
2865697Smcpowers 	 */
2875697Smcpowers 	if (ecc_prov_handle != NULL) {
2885697Smcpowers 		if ((ret = crypto_unregister_provider(ecc_prov_handle)) !=
2895697Smcpowers 		    CRYPTO_SUCCESS) {
2905697Smcpowers 			cmn_err(CE_WARN, "ecc _fini: "
2915697Smcpowers 			    "crypto_unregister_provider() "
2925697Smcpowers 			    "failed (0x%x)", ret);
2935697Smcpowers 			return (EBUSY);
2945697Smcpowers 		}
2955697Smcpowers 		ecc_prov_handle = NULL;
2965697Smcpowers 	}
2975697Smcpowers 
2985697Smcpowers 	return (mod_remove(&modlinkage));
2995697Smcpowers }
3005697Smcpowers 
3015697Smcpowers int
3025697Smcpowers _info(struct modinfo *modinfop)
3035697Smcpowers {
3045697Smcpowers 	return (mod_info(&modlinkage, modinfop));
3055697Smcpowers }
3065697Smcpowers 
3075697Smcpowers /* ARGSUSED */
3085697Smcpowers static void
3095697Smcpowers ecc_provider_status(crypto_provider_handle_t provider, uint_t *status)
3105697Smcpowers {
3115697Smcpowers 	*status = CRYPTO_PROVIDER_READY;
3125697Smcpowers }
3135697Smcpowers 
3145697Smcpowers /*
3155697Smcpowers  * Return the index of an attribute of specified type found in
3165697Smcpowers  * the specified array of attributes. If the attribute cannot
3175697Smcpowers  * found, return -1.
3185697Smcpowers  */
3195697Smcpowers static int
3205697Smcpowers find_attr(crypto_object_attribute_t *attr, uint_t nattr, uint64_t attr_type)
3215697Smcpowers {
3225697Smcpowers 	int i;
3235697Smcpowers 
3245697Smcpowers 	for (i = 0; i < nattr; i++)
3255697Smcpowers 		if (attr[i].oa_value != NULL && attr[i].oa_type == attr_type)
3265697Smcpowers 			return (i);
3275697Smcpowers 	return (-1);
3285697Smcpowers }
3295697Smcpowers 
3305697Smcpowers /*
3315697Smcpowers  * Common function used by the get_template_attr_*() family of
3325697Smcpowers  * functions. Returns the value of the specified attribute of specified
3335697Smcpowers  * length. Returns CRYPTO_SUCCESS on success, CRYPTO_ATTRIBUTE_VALUE_INVALID
3345697Smcpowers  * if the length of the attribute does not match the specified length,
3355697Smcpowers  * or CRYPTO_ARGUMENTS_BAD if the attribute cannot be found.
3365697Smcpowers  */
3375697Smcpowers static int
3385697Smcpowers get_template_attr_scalar_common(crypto_object_attribute_t *template,
3395697Smcpowers     uint_t nattr, uint64_t attr_type, void *value, size_t value_len)
3405697Smcpowers {
3415697Smcpowers 	size_t oa_value_len;
3425697Smcpowers 	size_t offset = 0;
3435697Smcpowers 	int attr_idx;
3445697Smcpowers 
3455697Smcpowers 	if ((attr_idx = find_attr(template, nattr, attr_type)) == -1)
3465697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
3475697Smcpowers 
3485697Smcpowers 	oa_value_len = template[attr_idx].oa_value_len;
3495697Smcpowers 	if (oa_value_len != value_len) {
3505697Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
3515697Smcpowers 	}
3525697Smcpowers 
3535697Smcpowers do_copy:
3545697Smcpowers 	bcopy(template[attr_idx].oa_value, (uchar_t *)value + offset,
3555697Smcpowers 	    oa_value_len);
3565697Smcpowers 
3575697Smcpowers 	return (CRYPTO_SUCCESS);
3585697Smcpowers }
3595697Smcpowers 
3605697Smcpowers /*
3615697Smcpowers  * Get the value of a ulong_t attribute from the specified template.
3625697Smcpowers  */
3635697Smcpowers static int
3645697Smcpowers get_template_attr_ulong(crypto_object_attribute_t *template,
3655697Smcpowers     uint_t nattr, uint64_t attr_type, ulong_t *attr_value)
3665697Smcpowers {
3675697Smcpowers 	return (get_template_attr_scalar_common(template, nattr,
3685697Smcpowers 	    attr_type, attr_value, sizeof (ulong_t)));
3695697Smcpowers }
3705697Smcpowers 
3715697Smcpowers /*
3725697Smcpowers  * Called from init routines to do basic sanity checks. Init routines,
3735697Smcpowers  * e.g. sign_init should fail rather than subsequent operations.
3745697Smcpowers  */
3755697Smcpowers static int
3765697Smcpowers check_mech_and_key(ecc_mech_type_t mech_type, crypto_key_t *key, ulong_t class)
3775697Smcpowers {
3785697Smcpowers 	int rv = CRYPTO_SUCCESS;
3795697Smcpowers 	uchar_t *foo;
3805697Smcpowers 	ssize_t point_len;
3815697Smcpowers 	ssize_t value_len;
3825697Smcpowers 
3835697Smcpowers 	if (mech_type != ECDSA_SHA1_MECH_INFO_TYPE &&
3845697Smcpowers 	    mech_type != ECDSA_MECH_INFO_TYPE)
3855697Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
3865697Smcpowers 
3875697Smcpowers 	if (key->ck_format != CRYPTO_KEY_ATTR_LIST) {
3885697Smcpowers 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
3895697Smcpowers 	}
3905697Smcpowers 
3915697Smcpowers 	switch (class) {
3925697Smcpowers 	case CKO_PUBLIC_KEY:
3937188Smcpowers 		if ((rv = crypto_get_key_attr(key, CKA_EC_POINT, &foo,
3947188Smcpowers 		    &point_len)) != CRYPTO_SUCCESS) {
3955697Smcpowers 			return (CRYPTO_TEMPLATE_INCOMPLETE);
3965697Smcpowers 		}
3975697Smcpowers 		if (point_len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) * 2 + 1 ||
3985697Smcpowers 		    point_len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN) * 2 + 1)
3995697Smcpowers 			return (CRYPTO_KEY_SIZE_RANGE);
4005697Smcpowers 		break;
4015697Smcpowers 
4025697Smcpowers 	case CKO_PRIVATE_KEY:
4037188Smcpowers 		if ((rv = crypto_get_key_attr(key, CKA_VALUE, &foo,
4047188Smcpowers 		    &value_len)) != CRYPTO_SUCCESS) {
4055697Smcpowers 			return (CRYPTO_TEMPLATE_INCOMPLETE);
4065697Smcpowers 		}
4075697Smcpowers 		if (value_len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) ||
4085697Smcpowers 		    value_len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN))
4095697Smcpowers 			return (CRYPTO_KEY_SIZE_RANGE);
4105697Smcpowers 		break;
4115697Smcpowers 
4125697Smcpowers 	default:
4135697Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
4145697Smcpowers 	}
4155697Smcpowers 
4165697Smcpowers 	return (rv);
4175697Smcpowers }
4185697Smcpowers 
4195697Smcpowers /*
4205697Smcpowers  * This function guarantees to return non-zero random numbers.
4215697Smcpowers  * This is needed as the /dev/urandom kernel interface,
4225697Smcpowers  * random_get_pseudo_bytes(), may return zeros.
4235697Smcpowers  */
4245697Smcpowers int
4255697Smcpowers ecc_knzero_random_generator(uint8_t *ran_out, size_t ran_len)
4265697Smcpowers {
4275697Smcpowers 	int rv;
4285697Smcpowers 	size_t ebc = 0; /* count of extra bytes in extrarand */
4295697Smcpowers 	size_t i = 0;
4305697Smcpowers 	uint8_t extrarand[32];
4315697Smcpowers 	size_t extrarand_len;
4325697Smcpowers 
433*10732SAnthony.Scarpino@Sun.COM 	if ((rv = random_get_pseudo_bytes_fips140(ran_out, ran_len)) != 0)
4345697Smcpowers 		return (rv);
4355697Smcpowers 
4365697Smcpowers 	/*
4375697Smcpowers 	 * Walk through the returned random numbers pointed by ran_out,
4385697Smcpowers 	 * and look for any random number which is zero.
4395697Smcpowers 	 * If we find zero, call random_get_pseudo_bytes() to generate
4405697Smcpowers 	 * another 32 random numbers pool. Replace any zeros in ran_out[]
4415697Smcpowers 	 * from the random number in pool.
4425697Smcpowers 	 */
4435697Smcpowers 	while (i < ran_len) {
4445697Smcpowers 		if (ran_out[i] != 0) {
4455697Smcpowers 			i++;
4465697Smcpowers 			continue;
4475697Smcpowers 		}
4485697Smcpowers 
4495697Smcpowers 		/*
4505697Smcpowers 		 * Note that it is 'while' so we are guaranteed a
4515697Smcpowers 		 * non-zero value on exit.
4525697Smcpowers 		 */
4535697Smcpowers 		if (ebc == 0) {
4545697Smcpowers 			/* refresh extrarand */
4555697Smcpowers 			extrarand_len = sizeof (extrarand);
456*10732SAnthony.Scarpino@Sun.COM 			if ((rv = random_get_pseudo_bytes_fips140(extrarand,
4575697Smcpowers 			    extrarand_len)) != 0) {
4585697Smcpowers 				return (rv);
4595697Smcpowers 			}
4605697Smcpowers 
4615697Smcpowers 			ebc = extrarand_len;
4625697Smcpowers 		}
4635697Smcpowers 		/* Replace zero with byte from extrarand. */
4645697Smcpowers 		-- ebc;
4655697Smcpowers 
4665697Smcpowers 		/*
4675697Smcpowers 		 * The new random byte zero/non-zero will be checked in
4685697Smcpowers 		 * the next pass through the loop.
4695697Smcpowers 		 */
4705697Smcpowers 		ran_out[i] = extrarand[ebc];
4715697Smcpowers 	}
4725697Smcpowers 
4735697Smcpowers 	return (CRYPTO_SUCCESS);
4745697Smcpowers }
4755697Smcpowers 
4765697Smcpowers static void
4775697Smcpowers ecc_free_context(crypto_ctx_t *ctx)
4785697Smcpowers {
4795697Smcpowers 	ecc_ctx_t *ctxp = ctx->cc_provider_private;
4805697Smcpowers 
4815697Smcpowers 	if (ctxp != NULL) {
4825697Smcpowers 		bzero(ctxp->key, ctxp->keychunk_size);
4835697Smcpowers 		kmem_free(ctxp->key, ctxp->keychunk_size);
4845697Smcpowers 
4855697Smcpowers 		free_ecparams(&ctxp->ecparams, B_FALSE);
4865697Smcpowers 
4875697Smcpowers 		if (ctxp->mech_type == ECDSA_MECH_INFO_TYPE)
4885697Smcpowers 			kmem_free(ctxp, sizeof (ecc_ctx_t));
4895697Smcpowers 		else
4905697Smcpowers 			kmem_free(ctxp, sizeof (digest_ecc_ctx_t));
4915697Smcpowers 
4925697Smcpowers 		ctx->cc_provider_private = NULL;
4935697Smcpowers 	}
4945697Smcpowers }
4955697Smcpowers 
4965697Smcpowers /* ARGSUSED */
4975697Smcpowers static int
4985697Smcpowers ecc_sign_verify_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
4995697Smcpowers     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
5005697Smcpowers     crypto_req_handle_t req)
5015697Smcpowers {
5025697Smcpowers 	int rv;
5035697Smcpowers 	int kmflag;
5045697Smcpowers 	ecc_ctx_t *ctxp;
5055697Smcpowers 	digest_ecc_ctx_t *dctxp;
5065697Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
5075697Smcpowers 	uchar_t *params;
5085697Smcpowers 	ssize_t params_len;
5095697Smcpowers 	ECParams  *ecparams;
5105697Smcpowers 	SECKEYECParams params_item;
5115697Smcpowers 
5127188Smcpowers 	if (crypto_get_key_attr(key, CKA_EC_PARAMS, (void *) &params,
5135697Smcpowers 	    &params_len)) {
5145697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
5155697Smcpowers 	}
5165697Smcpowers 
5175697Smcpowers 	/* ASN1 check */
5185697Smcpowers 	if (params[0] != 0x06 ||
5195697Smcpowers 	    params[1] != params_len - 2) {
5205697Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
5215697Smcpowers 	}
5225697Smcpowers 	params_item.data = params;
5235697Smcpowers 	params_item.len = (uint_t)params_len;
5245697Smcpowers 	kmflag = crypto_kmflag(req);
5255697Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
5265697Smcpowers 		/* bad curve OID */
5275697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
5285697Smcpowers 	}
5295697Smcpowers 
5305697Smcpowers 	/*
5315697Smcpowers 	 * Allocate an ECC context.
5325697Smcpowers 	 */
5335697Smcpowers 	switch (mech_type) {
5345697Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
5355697Smcpowers 		dctxp = kmem_zalloc(sizeof (digest_ecc_ctx_t), kmflag);
5365697Smcpowers 		ctxp = (ecc_ctx_t *)dctxp;
5375697Smcpowers 		break;
5385697Smcpowers 	default:
5395697Smcpowers 		ctxp = kmem_zalloc(sizeof (ecc_ctx_t), kmflag);
5405697Smcpowers 		break;
5415697Smcpowers 	}
5425697Smcpowers 
5435697Smcpowers 	if (ctxp == NULL) {
5445697Smcpowers 		free_ecparams(ecparams, B_TRUE);
5455697Smcpowers 		return (CRYPTO_HOST_MEMORY);
5465697Smcpowers 	}
5475697Smcpowers 
5487188Smcpowers 	if ((rv = crypto_copy_key_to_ctx(key, &ctxp->key, &ctxp->keychunk_size,
5497188Smcpowers 	    kmflag)) != CRYPTO_SUCCESS) {
5505697Smcpowers 		switch (mech_type) {
5515697Smcpowers 		case ECDSA_SHA1_MECH_INFO_TYPE:
5525697Smcpowers 			kmem_free(dctxp, sizeof (digest_ecc_ctx_t));
5535697Smcpowers 			break;
5545697Smcpowers 		default:
5555697Smcpowers 			kmem_free(ctxp, sizeof (ecc_ctx_t));
5565697Smcpowers 			break;
5575697Smcpowers 		}
5585697Smcpowers 		free_ecparams(ecparams, B_TRUE);
5595697Smcpowers 		return (rv);
5605697Smcpowers 	}
5615697Smcpowers 	ctxp->mech_type = mech_type;
5625697Smcpowers 	ctxp->ecparams = *ecparams;
5635697Smcpowers 	kmem_free(ecparams, sizeof (ECParams));
5645697Smcpowers 
5655697Smcpowers 	switch (mech_type) {
5665697Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
5675697Smcpowers 		SHA1Init(&(dctxp->sha1_ctx));
5685697Smcpowers 		break;
5695697Smcpowers 	}
5705697Smcpowers 
5715697Smcpowers 	ctx->cc_provider_private = ctxp;
5725697Smcpowers 
5735697Smcpowers 	return (CRYPTO_SUCCESS);
5745697Smcpowers }
5755697Smcpowers 
5765697Smcpowers /* ARGSUSED */
5775697Smcpowers static int
5785697Smcpowers ecc_sign_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
5795697Smcpowers     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
5805697Smcpowers     crypto_req_handle_t req)
5815697Smcpowers {
5825697Smcpowers 	int rv;
5835697Smcpowers 
5845697Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
5855697Smcpowers 
5865697Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
5875697Smcpowers 	    CKO_PRIVATE_KEY)) != CRYPTO_SUCCESS)
5885697Smcpowers 		return (rv);
5895697Smcpowers 
5905697Smcpowers 	rv = ecc_sign_verify_common_init(ctx, mechanism, key,
5915697Smcpowers 	    ctx_template, req);
5925697Smcpowers 
5935697Smcpowers 	return (rv);
5945697Smcpowers }
5955697Smcpowers 
5965697Smcpowers /* ARGSUSED */
5975697Smcpowers static int
5985697Smcpowers ecc_verify_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
5995697Smcpowers     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
6005697Smcpowers     crypto_req_handle_t req)
6015697Smcpowers {
6025697Smcpowers 	int rv;
6035697Smcpowers 
6045697Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
6055697Smcpowers 
6065697Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
6075697Smcpowers 	    CKO_PUBLIC_KEY)) != CRYPTO_SUCCESS)
6085697Smcpowers 		return (rv);
6095697Smcpowers 
6105697Smcpowers 	rv = ecc_sign_verify_common_init(ctx, mechanism, key,
6115697Smcpowers 	    ctx_template, req);
6125697Smcpowers 
6135697Smcpowers 	return (rv);
6145697Smcpowers }
6155697Smcpowers 
6165697Smcpowers #define	SHA1_DIGEST_SIZE 20
6175697Smcpowers 
6185697Smcpowers #define	INIT_RAW_CRYPTO_DATA(data, base, len, cd_len)	\
6195697Smcpowers 	(data).cd_format = CRYPTO_DATA_RAW;		\
6205697Smcpowers 	(data).cd_offset = 0;				\
6215697Smcpowers 	(data).cd_raw.iov_base = (char *)base;		\
6225697Smcpowers 	(data).cd_raw.iov_len = len;			\
6235697Smcpowers 	(data).cd_length = cd_len;
6245697Smcpowers 
6255697Smcpowers static int
6265697Smcpowers ecc_digest_svrfy_common(digest_ecc_ctx_t *ctxp, crypto_data_t *data,
6275697Smcpowers     crypto_data_t *signature, uchar_t flag, crypto_req_handle_t req)
6285697Smcpowers {
6295697Smcpowers 	int rv = CRYPTO_FAILED;
6305697Smcpowers 	uchar_t digest[SHA1_DIGEST_LENGTH];
6315697Smcpowers 	crypto_data_t der_cd;
6325697Smcpowers 	ecc_mech_type_t mech_type;
6335697Smcpowers 
6347188Smcpowers 	ASSERT(flag & CRYPTO_DO_SIGN || flag & CRYPTO_DO_VERIFY);
6357188Smcpowers 	ASSERT(data != NULL || (flag & CRYPTO_DO_FINAL));
6365697Smcpowers 
6375697Smcpowers 	mech_type = ctxp->mech_type;
6385697Smcpowers 	if (mech_type != ECDSA_SHA1_MECH_INFO_TYPE)
6395697Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
6405697Smcpowers 
6415697Smcpowers 	/* Don't digest if only returning length of signature. */
6425697Smcpowers 	if (signature->cd_length > 0) {
6435697Smcpowers 		if (mech_type == ECDSA_SHA1_MECH_INFO_TYPE) {
6447188Smcpowers 			rv = crypto_digest_data(data, &(ctxp->sha1_ctx),
6457188Smcpowers 			    digest, (void (*)())SHA1Update,
6467188Smcpowers 			    (void (*)())SHA1Final, flag | CRYPTO_DO_SHA1);
6475697Smcpowers 			if (rv != CRYPTO_SUCCESS)
6485697Smcpowers 				return (rv);
6495697Smcpowers 		}
6505697Smcpowers 	}
6515697Smcpowers 
6525697Smcpowers 	INIT_RAW_CRYPTO_DATA(der_cd, digest, SHA1_DIGEST_SIZE,
6535697Smcpowers 	    SHA1_DIGEST_SIZE);
6545697Smcpowers 
6557188Smcpowers 	if (flag & CRYPTO_DO_SIGN) {
6565697Smcpowers 		rv = ecc_sign_common((ecc_ctx_t *)ctxp, &der_cd, signature,
6575697Smcpowers 		    req);
6585697Smcpowers 	} else
6595697Smcpowers 		rv = ecc_verify_common((ecc_ctx_t *)ctxp, &der_cd, signature,
6605697Smcpowers 		    req);
6615697Smcpowers 
6625697Smcpowers 	return (rv);
6635697Smcpowers }
6645697Smcpowers 
6655697Smcpowers /*
6665697Smcpowers  * This is a single-part signing routine. It does not
6675697Smcpowers  * compute a hash before signing.
6685697Smcpowers  */
6695697Smcpowers static int
6705697Smcpowers ecc_sign_common(ecc_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
6715697Smcpowers     crypto_req_handle_t req)
6725697Smcpowers {
6735697Smcpowers 	int rv = CRYPTO_FAILED;
6745697Smcpowers 	SECStatus ss;
6755697Smcpowers 	uchar_t *param;
6765697Smcpowers 	uchar_t *private;
6775697Smcpowers 	ssize_t param_len;
6785697Smcpowers 	ssize_t private_len;
6795697Smcpowers 	uchar_t tmp_data[EC_MAX_DIGEST_LEN];
6805697Smcpowers 	uchar_t signed_data[EC_MAX_SIG_LEN];
6815697Smcpowers 	ECPrivateKey ECkey;
6825697Smcpowers 	SECItem signature_item;
6835697Smcpowers 	SECItem digest_item;
6845697Smcpowers 	crypto_key_t *key = ctx->key;
6855697Smcpowers 	int kmflag;
6865697Smcpowers 
6877188Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_EC_PARAMS, &param,
6885697Smcpowers 	    &param_len)) != CRYPTO_SUCCESS) {
6895697Smcpowers 		return (rv);
6905697Smcpowers 	}
6915697Smcpowers 
6925697Smcpowers 	if (data->cd_length > sizeof (tmp_data))
6935697Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
6945697Smcpowers 
6957188Smcpowers 	if ((rv = crypto_get_input_data(data, &digest_item.data, tmp_data))
6965697Smcpowers 	    != CRYPTO_SUCCESS) {
6975697Smcpowers 		return (rv);
6985697Smcpowers 	}
6995697Smcpowers 	digest_item.len = data->cd_length;
7005697Smcpowers 
7015697Smcpowers 	/* structure assignment */
7025697Smcpowers 	ECkey.ecParams = ctx->ecparams;
7035697Smcpowers 
7047188Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_VALUE, &private,
7055697Smcpowers 	    &private_len)) != CRYPTO_SUCCESS) {
7065697Smcpowers 		return (rv);
7075697Smcpowers 	}
7085697Smcpowers 	ECkey.privateValue.data = private;
7095697Smcpowers 	ECkey.privateValue.len = (uint_t)private_len;
7105697Smcpowers 
7115697Smcpowers 	signature_item.data = signed_data;
7125697Smcpowers 	signature_item.len = sizeof (signed_data);
7135697Smcpowers 
7145697Smcpowers 	kmflag = crypto_kmflag(req);
7155697Smcpowers 	if ((ss = ECDSA_SignDigest(&ECkey, &signature_item, &digest_item,
7165697Smcpowers 	    kmflag)) != SECSuccess) {
7175697Smcpowers 		if (ss == SECBufferTooSmall)
7185697Smcpowers 			return (CRYPTO_BUFFER_TOO_SMALL);
7195697Smcpowers 
7205697Smcpowers 		return (CRYPTO_FAILED);
7215697Smcpowers 	}
7225697Smcpowers 
7235697Smcpowers 	if (rv == CRYPTO_SUCCESS) {
7245697Smcpowers 		/* copy out the signature */
7257188Smcpowers 		if ((rv = crypto_put_output_data(signed_data,
7265697Smcpowers 		    signature, signature_item.len)) != CRYPTO_SUCCESS)
7275697Smcpowers 			return (rv);
7285697Smcpowers 
7295697Smcpowers 		signature->cd_length = signature_item.len;
7305697Smcpowers 	}
7315697Smcpowers 
7325697Smcpowers 	return (rv);
7335697Smcpowers }
7345697Smcpowers 
7355697Smcpowers /* ARGSUSED */
7365697Smcpowers static int
7375697Smcpowers ecc_sign(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
7385697Smcpowers     crypto_req_handle_t req)
7395697Smcpowers {
7405697Smcpowers 	int rv;
7415697Smcpowers 	ecc_ctx_t *ctxp;
7425697Smcpowers 
7435697Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
7445697Smcpowers 	ctxp = ctx->cc_provider_private;
7455697Smcpowers 
7465697Smcpowers 	switch (ctxp->mech_type) {
7475697Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
7485697Smcpowers 		rv = ecc_digest_svrfy_common((digest_ecc_ctx_t *)ctxp, data,
7497188Smcpowers 		    signature, CRYPTO_DO_SIGN | CRYPTO_DO_UPDATE |
7507188Smcpowers 		    CRYPTO_DO_FINAL, req);
7515697Smcpowers 		break;
7525697Smcpowers 	default:
7535697Smcpowers 		rv = ecc_sign_common(ctxp, data, signature, req);
7545697Smcpowers 		break;
7555697Smcpowers 	}
7565697Smcpowers 
7575697Smcpowers 	if (rv != CRYPTO_BUFFER_TOO_SMALL)
7585697Smcpowers 		ecc_free_context(ctx);
7595697Smcpowers 
7605697Smcpowers 	return (rv);
7615697Smcpowers }
7625697Smcpowers 
7635697Smcpowers /* ARGSUSED */
7645697Smcpowers static int
7655697Smcpowers ecc_sign_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
7665697Smcpowers {
7675697Smcpowers 	int rv;
7685697Smcpowers 	digest_ecc_ctx_t *ctxp;
7695697Smcpowers 	ecc_mech_type_t mech_type;
7705697Smcpowers 
7715697Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
7725697Smcpowers 	ctxp = ctx->cc_provider_private;
7735697Smcpowers 	mech_type = ctxp->mech_type;
7745697Smcpowers 
7755697Smcpowers 	if (mech_type == ECDSA_MECH_INFO_TYPE) {
7765697Smcpowers 		ecc_free_context(ctx);
7775697Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
7785697Smcpowers 	}
7795697Smcpowers 
7805697Smcpowers 	if (mech_type == ECDSA_SHA1_MECH_INFO_TYPE)
7817188Smcpowers 		rv = crypto_digest_data(data, &(ctxp->sha1_ctx), NULL,
7827188Smcpowers 		    (void (*)())SHA1Update, (void (*)())SHA1Final,
7837188Smcpowers 		    CRYPTO_DO_SHA1 | CRYPTO_DO_UPDATE);
7845697Smcpowers 
7855697Smcpowers 	if (rv != CRYPTO_SUCCESS)
7865697Smcpowers 		ecc_free_context(ctx);
7875697Smcpowers 
7885697Smcpowers 	return (rv);
7895697Smcpowers }
7905697Smcpowers 
7915697Smcpowers /* ARGSUSED */
7925697Smcpowers static int
7935697Smcpowers ecc_sign_final(crypto_ctx_t *ctx, crypto_data_t *signature,
7945697Smcpowers     crypto_req_handle_t req)
7955697Smcpowers {
7965697Smcpowers 	int rv;
7975697Smcpowers 	digest_ecc_ctx_t *ctxp;
7985697Smcpowers 
7995697Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
8005697Smcpowers 	ctxp = ctx->cc_provider_private;
8015697Smcpowers 
8027188Smcpowers 	rv = ecc_digest_svrfy_common(ctxp, NULL, signature, CRYPTO_DO_SIGN |
8037188Smcpowers 	    CRYPTO_DO_FINAL, req);
8045697Smcpowers 	if (rv != CRYPTO_BUFFER_TOO_SMALL)
8055697Smcpowers 		ecc_free_context(ctx);
8065697Smcpowers 
8075697Smcpowers 	return (rv);
8085697Smcpowers }
8095697Smcpowers 
8105697Smcpowers /* ARGSUSED */
8115697Smcpowers static int
8125697Smcpowers ecc_sign_atomic(crypto_provider_handle_t provider,
8135697Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
8145697Smcpowers     crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
8155697Smcpowers     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
8165697Smcpowers {
8175697Smcpowers 	int rv;
8185697Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
8195697Smcpowers 	uchar_t *params;
8205697Smcpowers 	ssize_t params_len;
8215697Smcpowers 	ECParams  *ecparams;
8225697Smcpowers 	SECKEYECParams params_item;
8235697Smcpowers 	int kmflag;
8245697Smcpowers 
8255697Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
8265697Smcpowers 	    CKO_PRIVATE_KEY)) != CRYPTO_SUCCESS)
8275697Smcpowers 		return (rv);
8285697Smcpowers 
8297188Smcpowers 	if (crypto_get_key_attr(key, CKA_EC_PARAMS, (void *) &params,
8305697Smcpowers 	    &params_len)) {
8315697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
8325697Smcpowers 	}
8335697Smcpowers 
8345697Smcpowers 	/* ASN1 check */
8355697Smcpowers 	if (params[0] != 0x06 ||
8365697Smcpowers 	    params[1] != params_len - 2) {
8375697Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
8385697Smcpowers 	}
8395697Smcpowers 	params_item.data = params;
8405697Smcpowers 	params_item.len = (uint_t)params_len;
8415697Smcpowers 	kmflag = crypto_kmflag(req);
8425697Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
8435697Smcpowers 		/* bad curve OID */
8445697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
8455697Smcpowers 	}
8465697Smcpowers 
8475697Smcpowers 	if (mechanism->cm_type == ECDSA_MECH_INFO_TYPE) {
8485697Smcpowers 		ecc_ctx_t ctx;
8495697Smcpowers 
8505697Smcpowers 		ctx.mech_type = mech_type;
8515697Smcpowers 		/* structure assignment */
8525697Smcpowers 		ctx.ecparams = *ecparams;
8535697Smcpowers 		ctx.key = key;
8545697Smcpowers 		rv = ecc_sign_common(&ctx, data, signature, req);
8555697Smcpowers 	} else {
8565697Smcpowers 		digest_ecc_ctx_t dctx;
8575697Smcpowers 
8585697Smcpowers 		dctx.mech_type = mech_type;
8595697Smcpowers 		/* structure assignment */
8605697Smcpowers 		dctx.ecparams = *ecparams;
8615697Smcpowers 		dctx.key = key;
8625697Smcpowers 		SHA1Init(&(dctx.sha1_ctx));
8635697Smcpowers 
8645697Smcpowers 		rv = ecc_digest_svrfy_common(&dctx, data, signature,
8657188Smcpowers 		    CRYPTO_DO_SIGN | CRYPTO_DO_UPDATE | CRYPTO_DO_FINAL, req);
8665697Smcpowers 	}
8675697Smcpowers 	free_ecparams(ecparams, B_TRUE);
8685697Smcpowers 
8695697Smcpowers 	return (rv);
8705697Smcpowers }
8715697Smcpowers 
8725697Smcpowers static int
8735697Smcpowers ecc_verify_common(ecc_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
8745697Smcpowers     crypto_req_handle_t req)
8755697Smcpowers {
8765697Smcpowers 	int rv = CRYPTO_FAILED;
8775697Smcpowers 	uchar_t *param;
8785697Smcpowers 	uchar_t *public;
8795697Smcpowers 	ssize_t param_len;
8805697Smcpowers 	ssize_t public_len;
8815697Smcpowers 	uchar_t tmp_data[EC_MAX_DIGEST_LEN];
8825697Smcpowers 	uchar_t signed_data[EC_MAX_SIG_LEN];
8835697Smcpowers 	ECPublicKey ECkey;
8845697Smcpowers 	SECItem signature_item;
8855697Smcpowers 	SECItem digest_item;
8865697Smcpowers 	crypto_key_t *key = ctx->key;
8875697Smcpowers 	int kmflag;
8885697Smcpowers 
8897188Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_EC_PARAMS, &param,
8905697Smcpowers 	    &param_len)) != CRYPTO_SUCCESS) {
8915697Smcpowers 		return (rv);
8925697Smcpowers 	}
8935697Smcpowers 
8945697Smcpowers 	if (signature->cd_length > sizeof (signed_data)) {
8955697Smcpowers 		return (CRYPTO_SIGNATURE_LEN_RANGE);
8965697Smcpowers 	}
8975697Smcpowers 
8987188Smcpowers 	if ((rv = crypto_get_input_data(signature, &signature_item.data,
8995697Smcpowers 	    signed_data)) != CRYPTO_SUCCESS) {
9005697Smcpowers 		return (rv);
9015697Smcpowers 	}
9025697Smcpowers 	signature_item.len = signature->cd_length;
9035697Smcpowers 
9045697Smcpowers 	if (data->cd_length > sizeof (tmp_data))
9055697Smcpowers 		return (CRYPTO_DATA_LEN_RANGE);
9065697Smcpowers 
9077188Smcpowers 	if ((rv = crypto_get_input_data(data, &digest_item.data, tmp_data))
9085697Smcpowers 	    != CRYPTO_SUCCESS) {
9095697Smcpowers 		return (rv);
9105697Smcpowers 	}
9115697Smcpowers 	digest_item.len = data->cd_length;
9125697Smcpowers 
9135697Smcpowers 	/* structure assignment */
9145697Smcpowers 	ECkey.ecParams = ctx->ecparams;
9155697Smcpowers 
9167188Smcpowers 	if ((rv = crypto_get_key_attr(key, CKA_EC_POINT, &public,
9175697Smcpowers 	    &public_len)) != CRYPTO_SUCCESS) {
9185697Smcpowers 		return (rv);
9195697Smcpowers 	}
9205697Smcpowers 	ECkey.publicValue.data = public;
9215697Smcpowers 	ECkey.publicValue.len = (uint_t)public_len;
9225697Smcpowers 
9235697Smcpowers 	kmflag = crypto_kmflag(req);
9245697Smcpowers 	if (ECDSA_VerifyDigest(&ECkey, &signature_item, &digest_item, kmflag)
9255697Smcpowers 	    != SECSuccess) {
9265697Smcpowers 		rv = CRYPTO_SIGNATURE_INVALID;
9275697Smcpowers 	} else {
9285697Smcpowers 		rv = CRYPTO_SUCCESS;
9295697Smcpowers 	}
9305697Smcpowers 
9315697Smcpowers 	return (rv);
9325697Smcpowers }
9335697Smcpowers 
9345697Smcpowers /* ARGSUSED */
9355697Smcpowers static int
9365697Smcpowers ecc_verify(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *signature,
9375697Smcpowers     crypto_req_handle_t req)
9385697Smcpowers {
9395697Smcpowers 	int rv;
9405697Smcpowers 	ecc_ctx_t *ctxp;
9415697Smcpowers 
9425697Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
9435697Smcpowers 	ctxp = ctx->cc_provider_private;
9445697Smcpowers 
9455697Smcpowers 	switch (ctxp->mech_type) {
9465697Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
9475697Smcpowers 		rv = ecc_digest_svrfy_common((digest_ecc_ctx_t *)ctxp, data,
9487188Smcpowers 		    signature, CRYPTO_DO_VERIFY | CRYPTO_DO_UPDATE |
9497188Smcpowers 		    CRYPTO_DO_FINAL, req);
9505697Smcpowers 		break;
9515697Smcpowers 	default:
9525697Smcpowers 		rv = ecc_verify_common(ctxp, data, signature, req);
9535697Smcpowers 		break;
9545697Smcpowers 	}
9555697Smcpowers 
9565697Smcpowers 	ecc_free_context(ctx);
9575697Smcpowers 	return (rv);
9585697Smcpowers }
9595697Smcpowers 
9605697Smcpowers /* ARGSUSED */
9615697Smcpowers static int
9625697Smcpowers ecc_verify_update(crypto_ctx_t *ctx, crypto_data_t *data,
9635697Smcpowers     crypto_req_handle_t req)
9645697Smcpowers {
9655697Smcpowers 	int rv;
9665697Smcpowers 	digest_ecc_ctx_t *ctxp;
9675697Smcpowers 
9685697Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
9695697Smcpowers 	ctxp = ctx->cc_provider_private;
9705697Smcpowers 
9715697Smcpowers 	switch (ctxp->mech_type) {
9725697Smcpowers 	case ECDSA_SHA1_MECH_INFO_TYPE:
9737188Smcpowers 		rv = crypto_digest_data(data, &(ctxp->sha1_ctx), NULL,
9747188Smcpowers 		    (void (*)())SHA1Update, (void (*)())SHA1Final,
9757188Smcpowers 		    CRYPTO_DO_SHA1 | CRYPTO_DO_UPDATE);
9765697Smcpowers 		break;
9775697Smcpowers 	default:
9785697Smcpowers 		rv = CRYPTO_MECHANISM_INVALID;
9795697Smcpowers 	}
9805697Smcpowers 
9815697Smcpowers 	if (rv != CRYPTO_SUCCESS)
9825697Smcpowers 		ecc_free_context(ctx);
9835697Smcpowers 
9845697Smcpowers 	return (rv);
9855697Smcpowers }
9865697Smcpowers 
9875697Smcpowers /* ARGSUSED */
9885697Smcpowers static int
9895697Smcpowers ecc_verify_final(crypto_ctx_t *ctx, crypto_data_t *signature,
9905697Smcpowers     crypto_req_handle_t req)
9915697Smcpowers {
9925697Smcpowers 	int rv;
9935697Smcpowers 	digest_ecc_ctx_t *ctxp;
9945697Smcpowers 
9955697Smcpowers 	ASSERT(ctx->cc_provider_private != NULL);
9965697Smcpowers 	ctxp = ctx->cc_provider_private;
9975697Smcpowers 
9985697Smcpowers 	rv = ecc_digest_svrfy_common(ctxp, NULL, signature,
9997188Smcpowers 	    CRYPTO_DO_VERIFY | CRYPTO_DO_FINAL, req);
10005697Smcpowers 
10015697Smcpowers 	ecc_free_context(ctx);
10025697Smcpowers 
10035697Smcpowers 	return (rv);
10045697Smcpowers }
10055697Smcpowers 
10065697Smcpowers 
10075697Smcpowers /* ARGSUSED */
10085697Smcpowers static int
10095697Smcpowers ecc_verify_atomic(crypto_provider_handle_t provider,
10105697Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
10115697Smcpowers     crypto_key_t *key, crypto_data_t *data, crypto_data_t *signature,
10125697Smcpowers     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
10135697Smcpowers {
10145697Smcpowers 	int rv;
10155697Smcpowers 	ecc_mech_type_t mech_type = mechanism->cm_type;
10165697Smcpowers 	uchar_t *params;
10175697Smcpowers 	ssize_t params_len;
10185697Smcpowers 	ECParams  *ecparams;
10195697Smcpowers 	SECKEYECParams params_item;
10205697Smcpowers 	int kmflag;
10215697Smcpowers 
10225697Smcpowers 	if ((rv = check_mech_and_key(mech_type, key,
10235697Smcpowers 	    CKO_PUBLIC_KEY)) != CRYPTO_SUCCESS)
10245697Smcpowers 		return (rv);
10255697Smcpowers 
10267188Smcpowers 	if (crypto_get_key_attr(key, CKA_EC_PARAMS, (void *) &params,
10275697Smcpowers 	    &params_len)) {
10285697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
10295697Smcpowers 	}
10305697Smcpowers 
10315697Smcpowers 	/* ASN1 check */
10325697Smcpowers 	if (params[0] != 0x06 ||
10335697Smcpowers 	    params[1] != params_len - 2) {
10345697Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
10355697Smcpowers 	}
10365697Smcpowers 	params_item.data = params;
10375697Smcpowers 	params_item.len = (uint_t)params_len;
10385697Smcpowers 	kmflag = crypto_kmflag(req);
10395697Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
10405697Smcpowers 		/* bad curve OID */
10415697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
10425697Smcpowers 	}
10435697Smcpowers 
10445697Smcpowers 	if (mechanism->cm_type == ECDSA_MECH_INFO_TYPE) {
10455697Smcpowers 		ecc_ctx_t ctx;
10465697Smcpowers 
10475697Smcpowers 		ctx.mech_type = mech_type;
10485697Smcpowers 		/* structure assignment */
10495697Smcpowers 		ctx.ecparams = *ecparams;
10505697Smcpowers 		ctx.key = key;
10515697Smcpowers 		rv = ecc_verify_common(&ctx, data, signature, req);
10525697Smcpowers 	} else {
10535697Smcpowers 		digest_ecc_ctx_t dctx;
10545697Smcpowers 
10555697Smcpowers 		dctx.mech_type = mech_type;
10565697Smcpowers 		/* structure assignment */
10575697Smcpowers 		dctx.ecparams = *ecparams;
10585697Smcpowers 		dctx.key = key;
10595697Smcpowers 		SHA1Init(&(dctx.sha1_ctx));
10605697Smcpowers 
10615697Smcpowers 		rv = ecc_digest_svrfy_common(&dctx, data, signature,
10627188Smcpowers 		    CRYPTO_DO_VERIFY | CRYPTO_DO_UPDATE | CRYPTO_DO_FINAL, req);
10635697Smcpowers 	}
10645697Smcpowers 	free_ecparams(ecparams, B_TRUE);
10655697Smcpowers 	return (rv);
10665697Smcpowers }
10675697Smcpowers 
10685697Smcpowers /* ARGSUSED */
10695697Smcpowers static int
10705697Smcpowers ecc_nostore_key_generate_pair(crypto_provider_handle_t provider,
10715697Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
10725697Smcpowers     crypto_object_attribute_t *pub_template, uint_t pub_attribute_count,
10735697Smcpowers     crypto_object_attribute_t *pri_template, uint_t pri_attribute_count,
10745697Smcpowers     crypto_object_attribute_t *pub_out_template, uint_t pub_out_attribute_count,
10755697Smcpowers     crypto_object_attribute_t *pri_out_template, uint_t pri_out_attribute_count,
10765697Smcpowers     crypto_req_handle_t req)
10775697Smcpowers {
10785697Smcpowers 	int rv = CRYPTO_SUCCESS;
10795697Smcpowers 	ECPrivateKey *privKey;	/* contains both public and private values */
10805697Smcpowers 	ECParams *ecparams;
10815697Smcpowers 	SECKEYECParams params_item;
10825697Smcpowers 	ulong_t pub_key_type = ~0UL, pub_class = ~0UL;
10835697Smcpowers 	ulong_t pri_key_type = ~0UL, pri_class = ~0UL;
10845697Smcpowers 	int params_idx, value_idx, point_idx;
10855697Smcpowers 	uchar_t *params = NULL;
10865697Smcpowers 	unsigned params_len;
10875697Smcpowers 	uchar_t *value = NULL;
10885697Smcpowers 	uchar_t *point = NULL;
10895697Smcpowers 	int valuelen;
10905697Smcpowers 	int pointlen;
10915697Smcpowers 	int xylen;
10925697Smcpowers 	int kmflag;
10935697Smcpowers 
10945697Smcpowers 	if (mechanism->cm_type != EC_KEY_PAIR_GEN_MECH_INFO_TYPE) {
10955697Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
10965697Smcpowers 	}
10975697Smcpowers 
10985697Smcpowers 	/* optional */
10995697Smcpowers 	(void) get_template_attr_ulong(pub_template,
11005697Smcpowers 	    pub_attribute_count, CKA_CLASS, &pub_class);
11015697Smcpowers 
11025697Smcpowers 	/* optional */
11035697Smcpowers 	(void) get_template_attr_ulong(pri_template,
11045697Smcpowers 	    pri_attribute_count, CKA_CLASS, &pri_class);
11055697Smcpowers 
11065697Smcpowers 	/* optional */
11075697Smcpowers 	(void) get_template_attr_ulong(pub_template,
11085697Smcpowers 	    pub_attribute_count, CKA_KEY_TYPE, &pub_key_type);
11095697Smcpowers 
11105697Smcpowers 	/* optional */
11115697Smcpowers 	(void) get_template_attr_ulong(pri_template,
11125697Smcpowers 	    pri_attribute_count, CKA_KEY_TYPE, &pri_key_type);
11135697Smcpowers 
11145697Smcpowers 	if (pub_class != ~0UL && pub_class != CKO_PUBLIC_KEY) {
11155697Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
11165697Smcpowers 	}
11175697Smcpowers 	pub_class = CKO_PUBLIC_KEY;
11185697Smcpowers 
11195697Smcpowers 	if (pri_class != ~0UL && pri_class != CKO_PRIVATE_KEY) {
11205697Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
11215697Smcpowers 	}
11225697Smcpowers 	pri_class = CKO_PRIVATE_KEY;
11235697Smcpowers 
11245697Smcpowers 	if (pub_key_type != ~0UL && pub_key_type != CKK_EC) {
11255697Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
11265697Smcpowers 	}
11275697Smcpowers 	pub_key_type = CKK_EC;
11285697Smcpowers 
11295697Smcpowers 	if (pri_key_type != ~0UL && pri_key_type != CKK_EC) {
11305697Smcpowers 		return (CRYPTO_TEMPLATE_INCONSISTENT);
11315697Smcpowers 	}
11325697Smcpowers 	pri_key_type = CKK_EC;
11335697Smcpowers 
11345697Smcpowers 	/* public output template must contain CKA_EC_POINT attribute */
11355697Smcpowers 	if ((point_idx = find_attr(pub_out_template, pub_out_attribute_count,
11365697Smcpowers 	    CKA_EC_POINT)) == -1) {
11375697Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
11385697Smcpowers 	}
11395697Smcpowers 
11405697Smcpowers 	/* private output template must contain CKA_VALUE attribute */
11415697Smcpowers 	if ((value_idx = find_attr(pri_out_template, pri_out_attribute_count,
11425697Smcpowers 	    CKA_VALUE)) == -1) {
11435697Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
11445697Smcpowers 	}
11455697Smcpowers 
11465697Smcpowers 	if ((params_idx = find_attr(pub_template, pub_attribute_count,
11475697Smcpowers 	    CKA_EC_PARAMS)) == -1) {
11485697Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
11495697Smcpowers 	}
11505697Smcpowers 
11515697Smcpowers 	params = (uchar_t *)pub_template[params_idx].oa_value;
11525697Smcpowers 	params_len = pub_template[params_idx].oa_value_len;
11535697Smcpowers 
11545697Smcpowers 	value = (uchar_t *)pri_out_template[value_idx].oa_value;
11555697Smcpowers 	valuelen = (int)pri_out_template[value_idx].oa_value_len;
11565697Smcpowers 	point = (uchar_t *)pub_out_template[point_idx].oa_value;
11575697Smcpowers 	pointlen = (int)pub_out_template[point_idx].oa_value_len;
11585697Smcpowers 
11595697Smcpowers 	/* ASN1 check */
11605697Smcpowers 	if (params[0] != 0x06 ||
11615697Smcpowers 	    params[1] != params_len - 2) {
11625697Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
11635697Smcpowers 	}
11645697Smcpowers 	params_item.data = params;
11655697Smcpowers 	params_item.len = params_len;
11665697Smcpowers 	kmflag = crypto_kmflag(req);
11675697Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
11685697Smcpowers 		/* bad curve OID */
11695697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
11705697Smcpowers 	}
11715697Smcpowers 
11725697Smcpowers 	if (EC_NewKey(ecparams, &privKey, kmflag) != SECSuccess) {
11735697Smcpowers 		free_ecparams(ecparams, B_TRUE);
11745697Smcpowers 		return (CRYPTO_FAILED);
11755697Smcpowers 	}
11765697Smcpowers 
11775697Smcpowers 	xylen = privKey->publicValue.len;
11785697Smcpowers 	/* ASSERT that xylen - 1 is divisible by 2 */
11795697Smcpowers 	if (xylen > pointlen) {
11805697Smcpowers 		rv = CRYPTO_BUFFER_TOO_SMALL;
11815697Smcpowers 		goto out;
11825697Smcpowers 	}
11835697Smcpowers 
11845697Smcpowers 	if (privKey->privateValue.len > valuelen) {
11855697Smcpowers 		rv = CRYPTO_BUFFER_TOO_SMALL;
11865697Smcpowers 		goto out;
11875697Smcpowers 	}
11885697Smcpowers 	bcopy(privKey->privateValue.data, value, privKey->privateValue.len);
11895697Smcpowers 	pri_out_template[value_idx].oa_value_len = privKey->privateValue.len;
11905697Smcpowers 
11915697Smcpowers 	bcopy(privKey->publicValue.data, point, xylen);
11925697Smcpowers 	pub_out_template[point_idx].oa_value_len = xylen;
11935697Smcpowers 
1194*10732SAnthony.Scarpino@Sun.COM 	if (kcf_get_fips140_mode() == FIPS140_MODE_ENABLED) {
119510500SHai-May.Chao@Sun.COM 		/* Pair-wise consistency test */
119610500SHai-May.Chao@Sun.COM 		if ((rv = fips_pairwise_check(privKey)) != CRYPTO_SUCCESS)
119710500SHai-May.Chao@Sun.COM 			cmn_err(CE_WARN, "ecc: fips_pairwise_check() "
119810500SHai-May.Chao@Sun.COM 			    "failed (0x%x).", rv);
119910500SHai-May.Chao@Sun.COM 	}
120010500SHai-May.Chao@Sun.COM 
12015697Smcpowers out:
12025697Smcpowers 	free_ecprivkey(privKey);
12035697Smcpowers 	free_ecparams(ecparams, B_TRUE);
12045697Smcpowers 	return (rv);
12055697Smcpowers }
12065697Smcpowers 
12075697Smcpowers /* ARGSUSED */
12085697Smcpowers static int
12095697Smcpowers ecc_nostore_key_derive(crypto_provider_handle_t provider,
12105697Smcpowers     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
12115697Smcpowers     crypto_key_t *base_key, crypto_object_attribute_t *in_attrs,
12125697Smcpowers     uint_t in_attr_count, crypto_object_attribute_t *out_attrs,
12135697Smcpowers     uint_t out_attr_count, crypto_req_handle_t req)
12145697Smcpowers {
12155697Smcpowers 	int rv = CRYPTO_SUCCESS;
12165697Smcpowers 	int params_idx, value_idx = -1, out_value_idx = -1;
12175697Smcpowers 	ulong_t key_type;
12185697Smcpowers 	ulong_t key_len;
12195697Smcpowers 	crypto_object_attribute_t *attrs;
12205697Smcpowers 	ECParams *ecparams;
12215697Smcpowers 	SECKEYECParams params_item;
12225697Smcpowers 	CK_ECDH1_DERIVE_PARAMS *mech_param;
12235697Smcpowers 	SECItem public_value_item, private_value_item, secret_item;
12245697Smcpowers 	int kmflag;
12255697Smcpowers 
12265697Smcpowers 	if (mechanism->cm_type != ECDH1_DERIVE_MECH_INFO_TYPE) {
12275697Smcpowers 		return (CRYPTO_MECHANISM_INVALID);
12285697Smcpowers 	}
12295697Smcpowers 
12305697Smcpowers 	ASSERT(IS_P2ALIGNED(mechanism->cm_param, sizeof (uint64_t)));
12315697Smcpowers 	/* LINTED: pointer alignment */
12325697Smcpowers 	mech_param = (CK_ECDH1_DERIVE_PARAMS *)mechanism->cm_param;
12335697Smcpowers 	if (mech_param->kdf != CKD_NULL) {
12345697Smcpowers 		return (CRYPTO_MECHANISM_PARAM_INVALID);
12355697Smcpowers 	}
12365697Smcpowers 
12375697Smcpowers 	if ((base_key->ck_format != CRYPTO_KEY_ATTR_LIST) ||
12385697Smcpowers 	    (base_key->ck_count == 0)) {
12395697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
12405697Smcpowers 	}
12415697Smcpowers 
12425697Smcpowers 	if ((rv = get_template_attr_ulong(in_attrs, in_attr_count,
12435697Smcpowers 	    CKA_KEY_TYPE, &key_type)) != CRYPTO_SUCCESS) {
12445697Smcpowers 		return (rv);
12455697Smcpowers 	}
12465697Smcpowers 
12475697Smcpowers 	switch (key_type) {
12485697Smcpowers 	case CKK_DES:
12495697Smcpowers 		key_len = DES_KEYSIZE;
12505697Smcpowers 		break;
12515697Smcpowers 	case CKK_DES2:
12525697Smcpowers 		key_len = DES2_KEYSIZE;
12535697Smcpowers 		break;
12545697Smcpowers 	case CKK_DES3:
12555697Smcpowers 		key_len = DES3_KEYSIZE;
12565697Smcpowers 		break;
12575697Smcpowers 	case CKK_RC4:
12585697Smcpowers 	case CKK_AES:
12595697Smcpowers 	case CKK_GENERIC_SECRET:
12605697Smcpowers 		if ((rv = get_template_attr_ulong(in_attrs, in_attr_count,
12615697Smcpowers 		    CKA_VALUE_LEN, &key_len)) != CRYPTO_SUCCESS) {
12625697Smcpowers 			return (rv);
12635697Smcpowers 		}
12645697Smcpowers 		break;
12655697Smcpowers 	default:
12665697Smcpowers 		key_len = 0;
12675697Smcpowers 	}
12685697Smcpowers 
12695697Smcpowers 	attrs = base_key->ck_attrs;
12705697Smcpowers 	if ((value_idx = find_attr(attrs, base_key->ck_count,
12715697Smcpowers 	    CKA_VALUE)) == -1) {
12725697Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
12735697Smcpowers 	}
12745697Smcpowers 
12755697Smcpowers 	if ((params_idx = find_attr(attrs, base_key->ck_count,
12765697Smcpowers 	    CKA_EC_PARAMS)) == -1) {
12775697Smcpowers 		return (CRYPTO_TEMPLATE_INCOMPLETE);
12785697Smcpowers 	}
12795697Smcpowers 
12805697Smcpowers 	private_value_item.data = (uchar_t *)attrs[value_idx].oa_value;
12815697Smcpowers 	private_value_item.len = attrs[value_idx].oa_value_len;
12825697Smcpowers 
12835697Smcpowers 	params_item.len = attrs[params_idx].oa_value_len;
12845697Smcpowers 	params_item.data = (uchar_t *)attrs[params_idx].oa_value;
12855697Smcpowers 
12865697Smcpowers 	/* ASN1 check */
12875697Smcpowers 	if (params_item.data[0] != 0x06 ||
12885697Smcpowers 	    params_item.data[1] != params_item.len - 2) {
12895697Smcpowers 		return (CRYPTO_ATTRIBUTE_VALUE_INVALID);
12905697Smcpowers 	}
12915697Smcpowers 	kmflag = crypto_kmflag(req);
12925697Smcpowers 	if (EC_DecodeParams(&params_item, &ecparams, kmflag) != SECSuccess) {
12935697Smcpowers 		/* bad curve OID */
12945697Smcpowers 		return (CRYPTO_ARGUMENTS_BAD);
12955697Smcpowers 	}
12965697Smcpowers 
12975697Smcpowers 	public_value_item.data = (uchar_t *)mech_param->pPublicData;
12985697Smcpowers 	public_value_item.len = mech_param->ulPublicDataLen;
12995697Smcpowers 
13005697Smcpowers 	if ((out_value_idx = find_attr(out_attrs, out_attr_count,
13015697Smcpowers 	    CKA_VALUE)) == -1) {
13025697Smcpowers 		rv = CRYPTO_TEMPLATE_INCOMPLETE;
13035697Smcpowers 		goto out;
13045697Smcpowers 	}
13055697Smcpowers 	secret_item.data = NULL;
13065697Smcpowers 	secret_item.len = 0;
13075697Smcpowers 
13085697Smcpowers 	if (ECDH_Derive(&public_value_item, ecparams, &private_value_item,
13095697Smcpowers 	    B_FALSE, &secret_item, kmflag) != SECSuccess) {
13105697Smcpowers 		free_ecparams(ecparams, B_TRUE);
13115697Smcpowers 		return (CRYPTO_FAILED);
13125697Smcpowers 	} else {
13135697Smcpowers 		rv = CRYPTO_SUCCESS;
13145697Smcpowers 	}
13155697Smcpowers 
13165697Smcpowers 	if (key_len == 0)
13175697Smcpowers 		key_len = secret_item.len;
13185697Smcpowers 
13195697Smcpowers 	if (key_len > secret_item.len) {
13205697Smcpowers 		rv = CRYPTO_ATTRIBUTE_VALUE_INVALID;
13215697Smcpowers 		goto out;
13225697Smcpowers 	}
13235697Smcpowers 	if (key_len > out_attrs[out_value_idx].oa_value_len) {
13245697Smcpowers 		rv = CRYPTO_BUFFER_TOO_SMALL;
13255697Smcpowers 		goto out;
13265697Smcpowers 	}
13275697Smcpowers 	bcopy(secret_item.data + secret_item.len - key_len,
13285697Smcpowers 	    (uchar_t *)out_attrs[out_value_idx].oa_value, key_len);
13295697Smcpowers 	out_attrs[out_value_idx].oa_value_len = key_len;
13305697Smcpowers out:
13315697Smcpowers 	free_ecparams(ecparams, B_TRUE);
13325697Smcpowers 	SECITEM_FreeItem(&secret_item, B_FALSE);
13335697Smcpowers 	return (rv);
13345697Smcpowers }
13355697Smcpowers 
13365697Smcpowers static void
13375697Smcpowers free_ecparams(ECParams *params, boolean_t freeit)
13385697Smcpowers {
13395697Smcpowers 	SECITEM_FreeItem(&params->fieldID.u.prime, B_FALSE);
13405697Smcpowers 	SECITEM_FreeItem(&params->curve.a, B_FALSE);
13415697Smcpowers 	SECITEM_FreeItem(&params->curve.b, B_FALSE);
13425697Smcpowers 	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
13435697Smcpowers 	SECITEM_FreeItem(&params->base, B_FALSE);
13445697Smcpowers 	SECITEM_FreeItem(&params->order, B_FALSE);
13455697Smcpowers 	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
13465697Smcpowers 	SECITEM_FreeItem(&params->curveOID, B_FALSE);
13475697Smcpowers 	if (freeit)
13485697Smcpowers 		kmem_free(params, sizeof (ECParams));
13495697Smcpowers }
13505697Smcpowers 
13515697Smcpowers static void
13525697Smcpowers free_ecprivkey(ECPrivateKey *key)
13535697Smcpowers {
13545697Smcpowers 	free_ecparams(&key->ecParams, B_FALSE);
13555697Smcpowers 	SECITEM_FreeItem(&key->publicValue, B_FALSE);
13565697Smcpowers 	bzero(key->privateValue.data, key->privateValue.len);
13575697Smcpowers 	SECITEM_FreeItem(&key->privateValue, B_FALSE);
13585697Smcpowers 	SECITEM_FreeItem(&key->version, B_FALSE);
13595697Smcpowers 	kmem_free(key, sizeof (ECPrivateKey));
13605697Smcpowers }
136110500SHai-May.Chao@Sun.COM 
136210500SHai-May.Chao@Sun.COM /*
136310500SHai-May.Chao@Sun.COM  * Pair-wise Consistency Test
136410500SHai-May.Chao@Sun.COM  */
136510500SHai-May.Chao@Sun.COM static int
136610500SHai-May.Chao@Sun.COM fips_pairwise_check(ECPrivateKey *ecdsa_private_key)
136710500SHai-May.Chao@Sun.COM {
136810500SHai-May.Chao@Sun.COM 
136910500SHai-May.Chao@Sun.COM 	SECItem signature_item;
137010500SHai-May.Chao@Sun.COM 	SECItem digest_item;
137110500SHai-May.Chao@Sun.COM 	uchar_t signed_data[EC_MAX_SIG_LEN];
137210500SHai-May.Chao@Sun.COM 	uchar_t sha1[SHA1_DIGEST_SIZE];
137310500SHai-May.Chao@Sun.COM 	ECPublicKey ecdsa_public_key;
137410500SHai-May.Chao@Sun.COM 	SHA1_CTX *sha1_context;
137510500SHai-May.Chao@Sun.COM 	int rv;
137610500SHai-May.Chao@Sun.COM 	static uint8_t msg[] = {
137710500SHai-May.Chao@Sun.COM 		"OpenSolarisCommunity"
137810500SHai-May.Chao@Sun.COM 	};
137910500SHai-May.Chao@Sun.COM 
138010500SHai-May.Chao@Sun.COM 	/* construct public key from private key. */
138110500SHai-May.Chao@Sun.COM 	if ((EC_CopyParams(ecdsa_private_key->ecParams.arena,
138210500SHai-May.Chao@Sun.COM 	    &ecdsa_public_key.ecParams, &ecdsa_private_key->ecParams))
138310500SHai-May.Chao@Sun.COM 	    != SECSuccess)
138410500SHai-May.Chao@Sun.COM 		return (CRYPTO_FAILED);
138510500SHai-May.Chao@Sun.COM 
138610500SHai-May.Chao@Sun.COM 	ecdsa_public_key.publicValue = ecdsa_private_key->publicValue;
138710500SHai-May.Chao@Sun.COM 
138810500SHai-May.Chao@Sun.COM 	if ((sha1_context = kmem_zalloc(sizeof (SHA1_CTX),
138910500SHai-May.Chao@Sun.COM 	    KM_SLEEP)) == NULL)
139010500SHai-May.Chao@Sun.COM 		return (CRYPTO_HOST_MEMORY);
139110500SHai-May.Chao@Sun.COM 
139210500SHai-May.Chao@Sun.COM 	SHA1Init(sha1_context);
139310500SHai-May.Chao@Sun.COM 	SHA1Update(sha1_context, msg, SHA1_DIGEST_SIZE);
139410500SHai-May.Chao@Sun.COM 	SHA1Final(sha1, sha1_context);
139510500SHai-May.Chao@Sun.COM 
139610500SHai-May.Chao@Sun.COM 	digest_item.data = sha1;
139710500SHai-May.Chao@Sun.COM 	digest_item.len = SHA1_DIGEST_SIZE;
139810500SHai-May.Chao@Sun.COM 	signature_item.data = signed_data;
139910500SHai-May.Chao@Sun.COM 	signature_item.len = sizeof (signed_data);
140010500SHai-May.Chao@Sun.COM 
140110500SHai-May.Chao@Sun.COM 	if ((ECDSA_SignDigest(ecdsa_private_key, &signature_item,
140210500SHai-May.Chao@Sun.COM 	    &digest_item, 0)) != SECSuccess) {
140310500SHai-May.Chao@Sun.COM 		rv = CRYPTO_FAILED;
140410500SHai-May.Chao@Sun.COM 		goto loser;
140510500SHai-May.Chao@Sun.COM 	}
140610500SHai-May.Chao@Sun.COM 
140710500SHai-May.Chao@Sun.COM 	if (ECDSA_VerifyDigest(&ecdsa_public_key, &signature_item,
140810500SHai-May.Chao@Sun.COM 	    &digest_item, 0) != SECSuccess) {
140910500SHai-May.Chao@Sun.COM 		rv = CRYPTO_SIGNATURE_INVALID;
141010500SHai-May.Chao@Sun.COM 	} else {
141110500SHai-May.Chao@Sun.COM 		rv = CRYPTO_SUCCESS;
141210500SHai-May.Chao@Sun.COM 	}
141310500SHai-May.Chao@Sun.COM 
141410500SHai-May.Chao@Sun.COM loser:
141510500SHai-May.Chao@Sun.COM 	kmem_free(sha1_context, sizeof (SHA1_CTX));
141610500SHai-May.Chao@Sun.COM 	return (rv);
141710500SHai-May.Chao@Sun.COM 
141810500SHai-May.Chao@Sun.COM }
141910500SHai-May.Chao@Sun.COM 
142010500SHai-May.Chao@Sun.COM 
142110500SHai-May.Chao@Sun.COM /*
142210500SHai-May.Chao@Sun.COM  * ECC Power-Up Self-Test
142310500SHai-May.Chao@Sun.COM  */
142410500SHai-May.Chao@Sun.COM void
142510500SHai-May.Chao@Sun.COM ecc_POST(int *rc)
142610500SHai-May.Chao@Sun.COM {
142710500SHai-May.Chao@Sun.COM 
142810500SHai-May.Chao@Sun.COM 	*rc = fips_ecdsa_post();
142910500SHai-May.Chao@Sun.COM 
143010500SHai-May.Chao@Sun.COM }
1431