xref: /optee_os/core/drivers/crypto/versal/ecc.c (revision e2ec831cb07ed0099535c7c140cb6338aa62816a)
149b0febcSJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
249b0febcSJorge Ramirez-Ortiz /*
349b0febcSJorge Ramirez-Ortiz  * Copyright (C) Foundries Ltd. 2022.
449b0febcSJorge Ramirez-Ortiz  * Author: Jorge Ramirez <jorge@foundries.io>
549b0febcSJorge Ramirez-Ortiz  */
649b0febcSJorge Ramirez-Ortiz 
749b0febcSJorge Ramirez-Ortiz #include <drvcrypt.h>
849b0febcSJorge Ramirez-Ortiz #include <drvcrypt_acipher.h>
949b0febcSJorge Ramirez-Ortiz #include <crypto/crypto_impl.h>
1049b0febcSJorge Ramirez-Ortiz #include <initcall.h>
1149b0febcSJorge Ramirez-Ortiz #include <ipi.h>
1249b0febcSJorge Ramirez-Ortiz #include <kernel/panic.h>
1349b0febcSJorge Ramirez-Ortiz #include <mm/core_memprot.h>
1449b0febcSJorge Ramirez-Ortiz #include <string.h>
1549b0febcSJorge Ramirez-Ortiz #include <tee/cache.h>
1649b0febcSJorge Ramirez-Ortiz #include <tee/tee_cryp_utl.h>
1749b0febcSJorge Ramirez-Ortiz #include <util.h>
1849b0febcSJorge Ramirez-Ortiz 
1949b0febcSJorge Ramirez-Ortiz /* AMD/Xilinx Versal's Known Answer Tests */
2049b0febcSJorge Ramirez-Ortiz #define XSECURE_ECDSA_KAT_NIST_P384	0
2149b0febcSJorge Ramirez-Ortiz #define XSECURE_ECDSA_KAT_NIST_P521	2
2249b0febcSJorge Ramirez-Ortiz 
2349b0febcSJorge Ramirez-Ortiz /* Software based ECDSA operations */
241220a68bSJorge Ramirez-Ortiz static const struct crypto_ecc_keypair_ops *pair_ops;
2549b0febcSJorge Ramirez-Ortiz static const struct crypto_ecc_public_ops *pub_ops;
2649b0febcSJorge Ramirez-Ortiz 
2749b0febcSJorge Ramirez-Ortiz enum versal_ecc_err {
2849b0febcSJorge Ramirez-Ortiz 	KAT_KEY_NOTVALID_ERROR = 0xC0,
2949b0febcSJorge Ramirez-Ortiz 	KAT_FAILED_ERROR,
3049b0febcSJorge Ramirez-Ortiz 	NON_SUPPORTED_CURVE,
3149b0febcSJorge Ramirez-Ortiz 	KEY_ZERO,
3249b0febcSJorge Ramirez-Ortiz 	KEY_WRONG_ORDER,
3349b0febcSJorge Ramirez-Ortiz 	KEY_NOT_ON_CURVE,
3449b0febcSJorge Ramirez-Ortiz 	BAD_SIGN,
3549b0febcSJorge Ramirez-Ortiz 	GEN_SIGN_INCORRECT_HASH_LEN,
3649b0febcSJorge Ramirez-Ortiz 	VER_SIGN_INCORRECT_HASH_LEN,
3749b0febcSJorge Ramirez-Ortiz 	GEN_SIGN_BAD_RAND_NUM,
3849b0febcSJorge Ramirez-Ortiz 	GEN_KEY_ERR,
3949b0febcSJorge Ramirez-Ortiz 	INVALID_PARAM,
4049b0febcSJorge Ramirez-Ortiz 	VER_SIGN_R_ZERO,
4149b0febcSJorge Ramirez-Ortiz 	VER_SIGN_S_ZERO,
4249b0febcSJorge Ramirez-Ortiz 	VER_SIGN_R_ORDER_ERROR,
4349b0febcSJorge Ramirez-Ortiz 	VER_SIGN_S_ORDER_ERROR,
4449b0febcSJorge Ramirez-Ortiz 	KAT_INVLD_CRV_ERROR,
4549b0febcSJorge Ramirez-Ortiz };
4649b0febcSJorge Ramirez-Ortiz 
4749b0febcSJorge Ramirez-Ortiz #define VERSAL_ECC_ERROR(m) { .error = (m), .name = TO_STR(m) }
4849b0febcSJorge Ramirez-Ortiz 
versal_ecc_error(uint8_t err)4949b0febcSJorge Ramirez-Ortiz static const char *versal_ecc_error(uint8_t err)
5049b0febcSJorge Ramirez-Ortiz {
5149b0febcSJorge Ramirez-Ortiz 	struct {
5249b0febcSJorge Ramirez-Ortiz 		enum versal_ecc_err error;
5349b0febcSJorge Ramirez-Ortiz 		const char *name;
5449b0febcSJorge Ramirez-Ortiz 	} elist[] = {
5549b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(KAT_KEY_NOTVALID_ERROR),
5649b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(KAT_FAILED_ERROR),
5749b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(NON_SUPPORTED_CURVE),
5849b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(KEY_ZERO),
5949b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(KEY_WRONG_ORDER),
6049b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(KEY_NOT_ON_CURVE),
6149b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(BAD_SIGN),
6249b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(GEN_SIGN_INCORRECT_HASH_LEN),
6349b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(VER_SIGN_INCORRECT_HASH_LEN),
6449b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(GEN_SIGN_BAD_RAND_NUM),
6549b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(GEN_KEY_ERR),
6649b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(INVALID_PARAM),
6749b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(VER_SIGN_R_ZERO),
6849b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(VER_SIGN_S_ZERO),
6949b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(VER_SIGN_R_ORDER_ERROR),
7049b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(VER_SIGN_S_ORDER_ERROR),
7149b0febcSJorge Ramirez-Ortiz 		VERSAL_ECC_ERROR(KAT_INVLD_CRV_ERROR),
7249b0febcSJorge Ramirez-Ortiz 	};
7349b0febcSJorge Ramirez-Ortiz 
7449b0febcSJorge Ramirez-Ortiz 	if (err <= KAT_INVLD_CRV_ERROR && err >= KAT_KEY_NOTVALID_ERROR) {
7549b0febcSJorge Ramirez-Ortiz 		if (elist[err - KAT_KEY_NOTVALID_ERROR].name)
7649b0febcSJorge Ramirez-Ortiz 			return elist[err - KAT_KEY_NOTVALID_ERROR].name;
7749b0febcSJorge Ramirez-Ortiz 
7849b0febcSJorge Ramirez-Ortiz 		return "Invalid";
7949b0febcSJorge Ramirez-Ortiz 	}
8049b0febcSJorge Ramirez-Ortiz 
8149b0febcSJorge Ramirez-Ortiz 	return "Unknown";
8249b0febcSJorge Ramirez-Ortiz }
8349b0febcSJorge Ramirez-Ortiz 
ecc_get_key_size(uint32_t curve,size_t * bytes,size_t * bits)8449b0febcSJorge Ramirez-Ortiz static TEE_Result ecc_get_key_size(uint32_t curve, size_t *bytes, size_t *bits)
8549b0febcSJorge Ramirez-Ortiz {
8649b0febcSJorge Ramirez-Ortiz 	switch (curve) {
8749b0febcSJorge Ramirez-Ortiz 	case TEE_ECC_CURVE_NIST_P384:
8849b0febcSJorge Ramirez-Ortiz 		*bits = 384;
8949b0febcSJorge Ramirez-Ortiz 		*bytes = 48;
9049b0febcSJorge Ramirez-Ortiz 		break;
9149b0febcSJorge Ramirez-Ortiz 	case TEE_ECC_CURVE_NIST_P521:
9249b0febcSJorge Ramirez-Ortiz 		*bits = 521;
9349b0febcSJorge Ramirez-Ortiz 		*bytes = 66;
9449b0febcSJorge Ramirez-Ortiz 		break;
9549b0febcSJorge Ramirez-Ortiz 	default:
9649b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_NOT_SUPPORTED;
9749b0febcSJorge Ramirez-Ortiz 	}
9849b0febcSJorge Ramirez-Ortiz 
9949b0febcSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
10049b0febcSJorge Ramirez-Ortiz }
10149b0febcSJorge Ramirez-Ortiz 
memcpy_swp(uint8_t * to,const uint8_t * from,size_t len)102e8bbd0e0SJorge Ramirez-Ortiz static void memcpy_swp(uint8_t *to, const uint8_t *from, size_t len)
103e8bbd0e0SJorge Ramirez-Ortiz {
104e8bbd0e0SJorge Ramirez-Ortiz 	size_t i = 0;
105e8bbd0e0SJorge Ramirez-Ortiz 
106e8bbd0e0SJorge Ramirez-Ortiz 	for (i = 0; i < len; i++)
107e8bbd0e0SJorge Ramirez-Ortiz 		to[i] = from[len - 1 - i];
108e8bbd0e0SJorge Ramirez-Ortiz }
109e8bbd0e0SJorge Ramirez-Ortiz 
crypto_bignum_bn2bin_eswap(uint32_t curve,struct bignum * from,uint8_t * to)11049b0febcSJorge Ramirez-Ortiz static void crypto_bignum_bn2bin_eswap(uint32_t curve,
11149b0febcSJorge Ramirez-Ortiz 				       struct bignum *from, uint8_t *to)
11249b0febcSJorge Ramirez-Ortiz {
11349b0febcSJorge Ramirez-Ortiz 	uint8_t pad[66] = { 0 };
11449b0febcSJorge Ramirez-Ortiz 	size_t len = crypto_bignum_num_bytes(from);
11549b0febcSJorge Ramirez-Ortiz 	size_t bytes = 0;
11649b0febcSJorge Ramirez-Ortiz 	size_t bits = 0;
11749b0febcSJorge Ramirez-Ortiz 
11849b0febcSJorge Ramirez-Ortiz 	if (ecc_get_key_size(curve, &bytes, &bits))
11949b0febcSJorge Ramirez-Ortiz 		panic();
12049b0febcSJorge Ramirez-Ortiz 
12149b0febcSJorge Ramirez-Ortiz 	crypto_bignum_bn2bin(from, pad + bytes - len);
122e8bbd0e0SJorge Ramirez-Ortiz 	memcpy_swp(to, pad, bytes);
12349b0febcSJorge Ramirez-Ortiz }
12449b0febcSJorge Ramirez-Ortiz 
ecc_prepare_msg(uint32_t algo,const uint8_t * msg,size_t msg_len,struct versal_mbox_mem * p)12549b0febcSJorge Ramirez-Ortiz static TEE_Result ecc_prepare_msg(uint32_t algo, const uint8_t *msg,
12649b0febcSJorge Ramirez-Ortiz 				  size_t msg_len, struct versal_mbox_mem *p)
12749b0febcSJorge Ramirez-Ortiz {
128e8bbd0e0SJorge Ramirez-Ortiz 	uint8_t swp[TEE_SHA512_HASH_SIZE + 2] = { 0 };
12949b0febcSJorge Ramirez-Ortiz 	size_t len = 0;
13049b0febcSJorge Ramirez-Ortiz 
131e8bbd0e0SJorge Ramirez-Ortiz 	if (msg_len > TEE_SHA512_HASH_SIZE + 2)
132e8bbd0e0SJorge Ramirez-Ortiz 		return TEE_ERROR_BAD_PARAMETERS;
133e8bbd0e0SJorge Ramirez-Ortiz 
1349cf576a9SJerome Forissier 	if (algo == TEE_ALG_ECDSA_SHA384)
13549b0febcSJorge Ramirez-Ortiz 		len = TEE_SHA384_HASH_SIZE;
1369cf576a9SJerome Forissier 	else if (algo == TEE_ALG_ECDSA_SHA512)
13749b0febcSJorge Ramirez-Ortiz 		len = TEE_SHA512_HASH_SIZE + 2;
138e8bbd0e0SJorge Ramirez-Ortiz 	else
139e8bbd0e0SJorge Ramirez-Ortiz 		return TEE_ERROR_NOT_SUPPORTED;
14049b0febcSJorge Ramirez-Ortiz 
141e8bbd0e0SJorge Ramirez-Ortiz 	/* Swap the hash/message and pad if necessary */
142e8bbd0e0SJorge Ramirez-Ortiz 	memcpy_swp(swp, msg, msg_len);
143e8bbd0e0SJorge Ramirez-Ortiz 	return versal_mbox_alloc(len, swp, p);
14449b0febcSJorge Ramirez-Ortiz }
14549b0febcSJorge Ramirez-Ortiz 
verify(uint32_t algo,struct ecc_public_key * key,const uint8_t * msg,size_t msg_len,const uint8_t * sig,size_t sig_len)14649b0febcSJorge Ramirez-Ortiz static TEE_Result verify(uint32_t algo, struct ecc_public_key *key,
14749b0febcSJorge Ramirez-Ortiz 			 const uint8_t *msg, size_t msg_len,
14849b0febcSJorge Ramirez-Ortiz 			 const uint8_t *sig, size_t sig_len)
14949b0febcSJorge Ramirez-Ortiz {
15049b0febcSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
15149b0febcSJorge Ramirez-Ortiz 	struct versal_ecc_verify_param *cmd = NULL;
15249b0febcSJorge Ramirez-Ortiz 	struct versal_cmd_args arg = { };
15349b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem x = { };
15449b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem s = { };
15549b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem p = { };
15649b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem cmd_buf = { };
15749b0febcSJorge Ramirez-Ortiz 	uint32_t err = 0;
15849b0febcSJorge Ramirez-Ortiz 	size_t bytes = 0;
15949b0febcSJorge Ramirez-Ortiz 	size_t bits = 0;
16049b0febcSJorge Ramirez-Ortiz 
161e8bbd0e0SJorge Ramirez-Ortiz 	if (sig_len % 2)
162e8bbd0e0SJorge Ramirez-Ortiz 		return TEE_ERROR_SIGNATURE_INVALID;
163e8bbd0e0SJorge Ramirez-Ortiz 
16449b0febcSJorge Ramirez-Ortiz 	ret = ecc_get_key_size(key->curve, &bytes, &bits);
16549b0febcSJorge Ramirez-Ortiz 	if (ret != TEE_SUCCESS) {
16649b0febcSJorge Ramirez-Ortiz 		if (ret != TEE_ERROR_NOT_SUPPORTED)
16749b0febcSJorge Ramirez-Ortiz 			return ret;
16849b0febcSJorge Ramirez-Ortiz 
16949b0febcSJorge Ramirez-Ortiz 		/* Fallback to software */
17049b0febcSJorge Ramirez-Ortiz 		return pub_ops->verify(algo, key, msg, msg_len, sig, sig_len);
17149b0febcSJorge Ramirez-Ortiz 	}
17249b0febcSJorge Ramirez-Ortiz 
17349b0febcSJorge Ramirez-Ortiz 	ret = ecc_prepare_msg(algo, msg, msg_len, &p);
17449b0febcSJorge Ramirez-Ortiz 	if (ret)
17549b0febcSJorge Ramirez-Ortiz 		return ret;
17649b0febcSJorge Ramirez-Ortiz 
17749b0febcSJorge Ramirez-Ortiz 	versal_mbox_alloc(bytes * 2, NULL, &x);
17849b0febcSJorge Ramirez-Ortiz 	crypto_bignum_bn2bin_eswap(key->curve, key->x, x.buf);
17949b0febcSJorge Ramirez-Ortiz 	crypto_bignum_bn2bin_eswap(key->curve, key->y,
18049b0febcSJorge Ramirez-Ortiz 				   (uint8_t *)x.buf + bytes);
18149b0febcSJorge Ramirez-Ortiz 	/* Validate the public key for the curve */
18249b0febcSJorge Ramirez-Ortiz 	arg.data[0] = key->curve;
18349b0febcSJorge Ramirez-Ortiz 	arg.dlen = 1;
18449b0febcSJorge Ramirez-Ortiz 	arg.ibuf[0].mem = x;
18549b0febcSJorge Ramirez-Ortiz 	if (versal_crypto_request(VERSAL_ELLIPTIC_VALIDATE_PUBLIC_KEY,
18649b0febcSJorge Ramirez-Ortiz 				  &arg, &err)) {
18749b0febcSJorge Ramirez-Ortiz 		EMSG("Versal ECC: %s", versal_ecc_error(err));
18849b0febcSJorge Ramirez-Ortiz 		ret = TEE_ERROR_GENERIC;
18949b0febcSJorge Ramirez-Ortiz 		goto out;
19049b0febcSJorge Ramirez-Ortiz 	}
19149b0febcSJorge Ramirez-Ortiz 	memset(&arg, 0, sizeof(arg));
19249b0febcSJorge Ramirez-Ortiz 
193e8bbd0e0SJorge Ramirez-Ortiz 	versal_mbox_alloc(sig_len, NULL, &s);
194e8bbd0e0SJorge Ramirez-Ortiz 	/* Swap the {R,S} components */
195e8bbd0e0SJorge Ramirez-Ortiz 	memcpy_swp(s.buf, sig, sig_len / 2);
196e8bbd0e0SJorge Ramirez-Ortiz 	memcpy_swp((uint8_t *)s.buf + sig_len / 2, sig + sig_len / 2,
197e8bbd0e0SJorge Ramirez-Ortiz 		   sig_len / 2);
19849b0febcSJorge Ramirez-Ortiz 	versal_mbox_alloc(sizeof(*cmd), NULL, &cmd_buf);
19949b0febcSJorge Ramirez-Ortiz 
20049b0febcSJorge Ramirez-Ortiz 	cmd = cmd_buf.buf;
20149b0febcSJorge Ramirez-Ortiz 	cmd->signature_addr = virt_to_phys(s.buf);
20249b0febcSJorge Ramirez-Ortiz 	cmd->pub_key_addr = virt_to_phys(x.buf);
20349b0febcSJorge Ramirez-Ortiz 	cmd->hash_addr = virt_to_phys(p.buf);
20449b0febcSJorge Ramirez-Ortiz 	cmd->hash_len = p.len;
20549b0febcSJorge Ramirez-Ortiz 	cmd->curve = key->curve;
20649b0febcSJorge Ramirez-Ortiz 
20749b0febcSJorge Ramirez-Ortiz 	arg.ibuf[0].mem = cmd_buf;
20849b0febcSJorge Ramirez-Ortiz 	arg.ibuf[1].mem = p;
20949b0febcSJorge Ramirez-Ortiz 	arg.ibuf[1].only_cache = true;
21049b0febcSJorge Ramirez-Ortiz 	arg.ibuf[2].mem = x;
21149b0febcSJorge Ramirez-Ortiz 	arg.ibuf[3].mem = s;
21249b0febcSJorge Ramirez-Ortiz 
21349b0febcSJorge Ramirez-Ortiz 	if (versal_crypto_request(VERSAL_ELLIPTIC_VERIFY_SIGN, &arg, &err)) {
21449b0febcSJorge Ramirez-Ortiz 		EMSG("Versal ECC: %s", versal_ecc_error(err));
21549b0febcSJorge Ramirez-Ortiz 		ret = TEE_ERROR_GENERIC;
21649b0febcSJorge Ramirez-Ortiz 	}
21749b0febcSJorge Ramirez-Ortiz out:
21849b0febcSJorge Ramirez-Ortiz 	free(p.buf);
21949b0febcSJorge Ramirez-Ortiz 	free(x.buf);
22049b0febcSJorge Ramirez-Ortiz 	free(s.buf);
22149b0febcSJorge Ramirez-Ortiz 	free(cmd);
22249b0febcSJorge Ramirez-Ortiz 
22349b0febcSJorge Ramirez-Ortiz 	return ret;
22449b0febcSJorge Ramirez-Ortiz }
22549b0febcSJorge Ramirez-Ortiz 
sign(uint32_t algo,struct ecc_keypair * key,const uint8_t * msg,size_t msg_len,uint8_t * sig,size_t * sig_len)22649b0febcSJorge Ramirez-Ortiz static TEE_Result sign(uint32_t algo, struct ecc_keypair *key,
22749b0febcSJorge Ramirez-Ortiz 		       const uint8_t *msg, size_t msg_len,
22849b0febcSJorge Ramirez-Ortiz 		       uint8_t *sig, size_t *sig_len)
22949b0febcSJorge Ramirez-Ortiz {
23049b0febcSJorge Ramirez-Ortiz 	struct versal_ecc_sign_param *cmd = NULL;
23149b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem cmd_buf = { };
23249b0febcSJorge Ramirez-Ortiz 	struct ecc_keypair ephemeral = { };
23349b0febcSJorge Ramirez-Ortiz 	struct versal_cmd_args arg = { };
23449b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem p = { };
23549b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem k = { };
23649b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem d = { };
23749b0febcSJorge Ramirez-Ortiz 	struct versal_mbox_mem s = { };
23849b0febcSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
23949b0febcSJorge Ramirez-Ortiz 	uint32_t err = 0;
24049b0febcSJorge Ramirez-Ortiz 	size_t bytes = 0;
24149b0febcSJorge Ramirez-Ortiz 	size_t bits = 0;
24249b0febcSJorge Ramirez-Ortiz 
24349b0febcSJorge Ramirez-Ortiz 	ret = ecc_get_key_size(key->curve, &bytes, &bits);
24449b0febcSJorge Ramirez-Ortiz 	if (ret != TEE_SUCCESS) {
24549b0febcSJorge Ramirez-Ortiz 		if (ret != TEE_ERROR_NOT_SUPPORTED)
24649b0febcSJorge Ramirez-Ortiz 			return ret;
24749b0febcSJorge Ramirez-Ortiz 
24849b0febcSJorge Ramirez-Ortiz 		/* Fallback to software */
2491220a68bSJorge Ramirez-Ortiz 		return pair_ops->sign(algo, key, msg, msg_len, sig, sig_len);
25049b0febcSJorge Ramirez-Ortiz 	}
25149b0febcSJorge Ramirez-Ortiz 
25249b0febcSJorge Ramirez-Ortiz 	/* Hash and update the length */
25349b0febcSJorge Ramirez-Ortiz 	ret = ecc_prepare_msg(algo, msg, msg_len, &p);
25449b0febcSJorge Ramirez-Ortiz 	if (ret)
25549b0febcSJorge Ramirez-Ortiz 		return ret;
25649b0febcSJorge Ramirez-Ortiz 
25749b0febcSJorge Ramirez-Ortiz 	/* Ephemeral private key */
25849b0febcSJorge Ramirez-Ortiz 	ret = drvcrypt_asym_alloc_ecc_keypair(&ephemeral,
25949b0febcSJorge Ramirez-Ortiz 					      TEE_TYPE_ECDSA_KEYPAIR, bits);
26049b0febcSJorge Ramirez-Ortiz 	if (ret) {
26149b0febcSJorge Ramirez-Ortiz 		EMSG("Versal, can't allocate the ephemeral key");
26249b0febcSJorge Ramirez-Ortiz 		return ret;
26349b0febcSJorge Ramirez-Ortiz 	}
26449b0febcSJorge Ramirez-Ortiz 
26549b0febcSJorge Ramirez-Ortiz 	ephemeral.curve = key->curve;
26649b0febcSJorge Ramirez-Ortiz 	ret = crypto_acipher_gen_ecc_key(&ephemeral, bits);
26749b0febcSJorge Ramirez-Ortiz 	if (ret) {
26849b0febcSJorge Ramirez-Ortiz 		EMSG("Versal, can't generate the ephemeral key");
26949b0febcSJorge Ramirez-Ortiz 		return ret;
27049b0febcSJorge Ramirez-Ortiz 	}
27149b0febcSJorge Ramirez-Ortiz 
27249b0febcSJorge Ramirez-Ortiz 	versal_mbox_alloc(bytes, NULL, &k);
27349b0febcSJorge Ramirez-Ortiz 	crypto_bignum_bn2bin_eswap(key->curve, ephemeral.d, k.buf);
274*e2ec831cSJihwan Park 	crypto_bignum_free(&ephemeral.d);
275*e2ec831cSJihwan Park 	crypto_bignum_free(&ephemeral.x);
276*e2ec831cSJihwan Park 	crypto_bignum_free(&ephemeral.y);
27749b0febcSJorge Ramirez-Ortiz 
27849b0febcSJorge Ramirez-Ortiz 	/* Private key*/
27949b0febcSJorge Ramirez-Ortiz 	versal_mbox_alloc(bytes, NULL, &d);
28049b0febcSJorge Ramirez-Ortiz 	crypto_bignum_bn2bin_eswap(key->curve, key->d, d.buf);
28149b0febcSJorge Ramirez-Ortiz 
28249b0febcSJorge Ramirez-Ortiz 	/* Signature */
28349b0febcSJorge Ramirez-Ortiz 	versal_mbox_alloc(*sig_len, NULL, &s);
28449b0febcSJorge Ramirez-Ortiz 
28549b0febcSJorge Ramirez-Ortiz 	/* IPI command */
28649b0febcSJorge Ramirez-Ortiz 	versal_mbox_alloc(sizeof(*cmd), NULL, &cmd_buf);
28749b0febcSJorge Ramirez-Ortiz 
28849b0febcSJorge Ramirez-Ortiz 	cmd = cmd_buf.buf;
28949b0febcSJorge Ramirez-Ortiz 	cmd->priv_key_addr = virt_to_phys(d.buf);
29049b0febcSJorge Ramirez-Ortiz 	cmd->epriv_key_addr = virt_to_phys(k.buf);
29149b0febcSJorge Ramirez-Ortiz 	cmd->hash_addr = virt_to_phys(p.buf);
29249b0febcSJorge Ramirez-Ortiz 	cmd->hash_len = p.len;
29349b0febcSJorge Ramirez-Ortiz 	cmd->curve = key->curve;
29449b0febcSJorge Ramirez-Ortiz 
29549b0febcSJorge Ramirez-Ortiz 	arg.ibuf[0].mem = cmd_buf;
29649b0febcSJorge Ramirez-Ortiz 	arg.ibuf[1].mem = s;
29749b0febcSJorge Ramirez-Ortiz 	arg.ibuf[2].mem = k;
29849b0febcSJorge Ramirez-Ortiz 	arg.ibuf[3].mem = d;
29949b0febcSJorge Ramirez-Ortiz 	arg.ibuf[4].mem = p;
30049b0febcSJorge Ramirez-Ortiz 
30149b0febcSJorge Ramirez-Ortiz 	if (versal_crypto_request(VERSAL_ELLIPTIC_GENERATE_SIGN, &arg, &err)) {
30249b0febcSJorge Ramirez-Ortiz 		EMSG("Versal ECC: %s", versal_ecc_error(err));
30349b0febcSJorge Ramirez-Ortiz 		ret = TEE_ERROR_GENERIC;
30449b0febcSJorge Ramirez-Ortiz 		goto out;
30549b0febcSJorge Ramirez-Ortiz 	}
30649b0febcSJorge Ramirez-Ortiz 
30749b0febcSJorge Ramirez-Ortiz 	*sig_len = 2 * bytes;
308e8bbd0e0SJorge Ramirez-Ortiz 
309e8bbd0e0SJorge Ramirez-Ortiz 	/* Swap the {R,S} components */
310e8bbd0e0SJorge Ramirez-Ortiz 	memcpy_swp(sig, s.buf, *sig_len / 2);
311e8bbd0e0SJorge Ramirez-Ortiz 	memcpy_swp(sig + *sig_len / 2, (uint8_t *)s.buf + *sig_len / 2,
312e8bbd0e0SJorge Ramirez-Ortiz 		   *sig_len / 2);
31349b0febcSJorge Ramirez-Ortiz out:
31449b0febcSJorge Ramirez-Ortiz 	free(cmd);
31549b0febcSJorge Ramirez-Ortiz 	free(k.buf);
31649b0febcSJorge Ramirez-Ortiz 	free(p.buf);
31749b0febcSJorge Ramirez-Ortiz 	free(s.buf);
31849b0febcSJorge Ramirez-Ortiz 	free(d.buf);
31949b0febcSJorge Ramirez-Ortiz 
32049b0febcSJorge Ramirez-Ortiz 	return ret;
32149b0febcSJorge Ramirez-Ortiz }
32249b0febcSJorge Ramirez-Ortiz 
shared_secret(struct ecc_keypair * private_key,struct ecc_public_key * public_key,void * secret,size_t * secret_len)32349b0febcSJorge Ramirez-Ortiz static TEE_Result shared_secret(struct ecc_keypair *private_key,
32449b0febcSJorge Ramirez-Ortiz 				struct ecc_public_key *public_key,
32549b0febcSJorge Ramirez-Ortiz 				void *secret, size_t *secret_len)
32649b0febcSJorge Ramirez-Ortiz {
3271220a68bSJorge Ramirez-Ortiz 	return pair_ops->shared_secret(private_key, public_key,
32849b0febcSJorge Ramirez-Ortiz 					  secret, secret_len);
32949b0febcSJorge Ramirez-Ortiz }
33049b0febcSJorge Ramirez-Ortiz 
do_shared_secret(struct drvcrypt_secret_data * sdata)33149b0febcSJorge Ramirez-Ortiz static TEE_Result do_shared_secret(struct drvcrypt_secret_data *sdata)
33249b0febcSJorge Ramirez-Ortiz {
33349b0febcSJorge Ramirez-Ortiz 	return shared_secret(sdata->key_priv,
33449b0febcSJorge Ramirez-Ortiz 			     sdata->key_pub,
33549b0febcSJorge Ramirez-Ortiz 			     sdata->secret.data,
33649b0febcSJorge Ramirez-Ortiz 			     &sdata->secret.length);
33749b0febcSJorge Ramirez-Ortiz }
33849b0febcSJorge Ramirez-Ortiz 
do_sign(struct drvcrypt_sign_data * sdata)33949b0febcSJorge Ramirez-Ortiz static TEE_Result do_sign(struct drvcrypt_sign_data *sdata)
34049b0febcSJorge Ramirez-Ortiz {
34149b0febcSJorge Ramirez-Ortiz 	return sign(sdata->algo,
34249b0febcSJorge Ramirez-Ortiz 		    sdata->key,
34349b0febcSJorge Ramirez-Ortiz 		    sdata->message.data,
34449b0febcSJorge Ramirez-Ortiz 		    sdata->message.length,
34549b0febcSJorge Ramirez-Ortiz 		    sdata->signature.data,
34649b0febcSJorge Ramirez-Ortiz 		    &sdata->signature.length);
34749b0febcSJorge Ramirez-Ortiz }
34849b0febcSJorge Ramirez-Ortiz 
do_verify(struct drvcrypt_sign_data * sdata)34949b0febcSJorge Ramirez-Ortiz static TEE_Result do_verify(struct drvcrypt_sign_data *sdata)
35049b0febcSJorge Ramirez-Ortiz {
35149b0febcSJorge Ramirez-Ortiz 	return verify(sdata->algo,
35249b0febcSJorge Ramirez-Ortiz 		      sdata->key,
35349b0febcSJorge Ramirez-Ortiz 		      sdata->message.data,
35449b0febcSJorge Ramirez-Ortiz 		      sdata->message.length,
35549b0febcSJorge Ramirez-Ortiz 		      sdata->signature.data,
35649b0febcSJorge Ramirez-Ortiz 		      sdata->signature.length);
35749b0febcSJorge Ramirez-Ortiz }
35849b0febcSJorge Ramirez-Ortiz 
do_gen_keypair(struct ecc_keypair * s,size_t size_bits)35949b0febcSJorge Ramirez-Ortiz static TEE_Result do_gen_keypair(struct ecc_keypair *s, size_t size_bits)
36049b0febcSJorge Ramirez-Ortiz {
36149b0febcSJorge Ramirez-Ortiz 	/*
362e8bbd0e0SJorge Ramirez-Ortiz 	 * Versal requires little endian so need to memcpy_swp on Versal IP ops.
36349b0febcSJorge Ramirez-Ortiz 	 * We chose not to do it here because some tests might be using
36449b0febcSJorge Ramirez-Ortiz 	 * their own keys
36549b0febcSJorge Ramirez-Ortiz 	 */
3661220a68bSJorge Ramirez-Ortiz 	return pair_ops->generate(s, size_bits);
36749b0febcSJorge Ramirez-Ortiz }
36849b0febcSJorge Ramirez-Ortiz 
do_alloc_keypair(struct ecc_keypair * s,uint32_t type,size_t size_bits)36992d75aefSJorge Ramirez-Ortiz static TEE_Result do_alloc_keypair(struct ecc_keypair *s,
3701220a68bSJorge Ramirez-Ortiz 				   uint32_t type, size_t size_bits)
37149b0febcSJorge Ramirez-Ortiz {
37249b0febcSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
37349b0febcSJorge Ramirez-Ortiz 
3741220a68bSJorge Ramirez-Ortiz 	/* This driver only supports ECDH/ECDSA */
3751220a68bSJorge Ramirez-Ortiz 	if (type != TEE_TYPE_ECDSA_KEYPAIR &&
3761220a68bSJorge Ramirez-Ortiz 	    type != TEE_TYPE_ECDH_KEYPAIR)
3771220a68bSJorge Ramirez-Ortiz 		return TEE_ERROR_NOT_IMPLEMENTED;
3781220a68bSJorge Ramirez-Ortiz 
37949b0febcSJorge Ramirez-Ortiz 	ret = crypto_asym_alloc_ecc_keypair(s, TEE_TYPE_ECDSA_KEYPAIR,
38049b0febcSJorge Ramirez-Ortiz 					    size_bits);
38149b0febcSJorge Ramirez-Ortiz 	if (ret)
38249b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_NOT_IMPLEMENTED;
38349b0febcSJorge Ramirez-Ortiz 
3841220a68bSJorge Ramirez-Ortiz 	/*
3851220a68bSJorge Ramirez-Ortiz 	 * Ignore the software operations, the crypto API will populate
3861220a68bSJorge Ramirez-Ortiz 	 * this interface.
3871220a68bSJorge Ramirez-Ortiz 	 */
38849b0febcSJorge Ramirez-Ortiz 	s->ops = NULL;
38949b0febcSJorge Ramirez-Ortiz 
39049b0febcSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
39149b0febcSJorge Ramirez-Ortiz }
39249b0febcSJorge Ramirez-Ortiz 
do_alloc_publickey(struct ecc_public_key * s,uint32_t type,size_t size_bits)39392d75aefSJorge Ramirez-Ortiz static TEE_Result do_alloc_publickey(struct ecc_public_key *s,
3941220a68bSJorge Ramirez-Ortiz 				     uint32_t type, size_t size_bits)
39549b0febcSJorge Ramirez-Ortiz {
39649b0febcSJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
39749b0febcSJorge Ramirez-Ortiz 
3981220a68bSJorge Ramirez-Ortiz 	/* This driver only supports ECDH/ECDSA */
3991220a68bSJorge Ramirez-Ortiz 	if (type != TEE_TYPE_ECDSA_PUBLIC_KEY &&
4001220a68bSJorge Ramirez-Ortiz 	    type != TEE_TYPE_ECDH_PUBLIC_KEY)
4011220a68bSJorge Ramirez-Ortiz 		return TEE_ERROR_NOT_IMPLEMENTED;
4021220a68bSJorge Ramirez-Ortiz 
40349b0febcSJorge Ramirez-Ortiz 	ret = crypto_asym_alloc_ecc_public_key(s, TEE_TYPE_ECDSA_PUBLIC_KEY,
40449b0febcSJorge Ramirez-Ortiz 					       size_bits);
40549b0febcSJorge Ramirez-Ortiz 	if (ret)
40649b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_NOT_IMPLEMENTED;
40749b0febcSJorge Ramirez-Ortiz 
4081220a68bSJorge Ramirez-Ortiz 	/*
4091220a68bSJorge Ramirez-Ortiz 	 * Ignore the software operations, the crypto API will populate
4101220a68bSJorge Ramirez-Ortiz 	 * this interface.
4111220a68bSJorge Ramirez-Ortiz 	 */
41249b0febcSJorge Ramirez-Ortiz 	s->ops = NULL;
41349b0febcSJorge Ramirez-Ortiz 
41449b0febcSJorge Ramirez-Ortiz 	return TEE_SUCCESS;
41549b0febcSJorge Ramirez-Ortiz }
41649b0febcSJorge Ramirez-Ortiz 
do_free_publickey(struct ecc_public_key * s)41749b0febcSJorge Ramirez-Ortiz static void do_free_publickey(struct ecc_public_key *s)
41849b0febcSJorge Ramirez-Ortiz {
41949b0febcSJorge Ramirez-Ortiz 	return pub_ops->free(s);
42049b0febcSJorge Ramirez-Ortiz }
42149b0febcSJorge Ramirez-Ortiz 
42249b0febcSJorge Ramirez-Ortiz static struct drvcrypt_ecc driver_ecc = {
42349b0febcSJorge Ramirez-Ortiz 	.shared_secret = do_shared_secret,
42449b0febcSJorge Ramirez-Ortiz 	.alloc_publickey = do_alloc_publickey,
42549b0febcSJorge Ramirez-Ortiz 	.free_publickey = do_free_publickey,
42649b0febcSJorge Ramirez-Ortiz 	.alloc_keypair = do_alloc_keypair,
42749b0febcSJorge Ramirez-Ortiz 	.gen_keypair = do_gen_keypair,
42849b0febcSJorge Ramirez-Ortiz 	.verify = do_verify,
42949b0febcSJorge Ramirez-Ortiz 	.sign = do_sign,
43049b0febcSJorge Ramirez-Ortiz };
43149b0febcSJorge Ramirez-Ortiz 
ecc_init(void)43249b0febcSJorge Ramirez-Ortiz static TEE_Result ecc_init(void)
43349b0febcSJorge Ramirez-Ortiz {
43449b0febcSJorge Ramirez-Ortiz 	struct versal_cmd_args arg = { };
43549b0febcSJorge Ramirez-Ortiz 	uint32_t err = 0;
43649b0febcSJorge Ramirez-Ortiz 
43749b0febcSJorge Ramirez-Ortiz 	arg.data[arg.dlen++] = XSECURE_ECDSA_KAT_NIST_P384;
43849b0febcSJorge Ramirez-Ortiz 	if (versal_crypto_request(VERSAL_ELLIPTIC_KAT, &arg, &err)) {
43949b0febcSJorge Ramirez-Ortiz 		EMSG("Versal KAG NIST_P384: %s", versal_ecc_error(err));
44049b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
44149b0febcSJorge Ramirez-Ortiz 	}
44249b0febcSJorge Ramirez-Ortiz 
44349b0febcSJorge Ramirez-Ortiz 	/* Clean previous request */
44449b0febcSJorge Ramirez-Ortiz 	arg.dlen = 0;
44549b0febcSJorge Ramirez-Ortiz 
44649b0febcSJorge Ramirez-Ortiz 	arg.data[arg.dlen++] = XSECURE_ECDSA_KAT_NIST_P521;
44749b0febcSJorge Ramirez-Ortiz 	if (versal_crypto_request(VERSAL_ELLIPTIC_KAT, &arg, &err)) {
44849b0febcSJorge Ramirez-Ortiz 		EMSG("Versal KAG NIST_P521 %s", versal_ecc_error(err));
44949b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
45049b0febcSJorge Ramirez-Ortiz 	}
45149b0febcSJorge Ramirez-Ortiz 
4521220a68bSJorge Ramirez-Ortiz 	pair_ops = crypto_asym_get_ecc_keypair_ops(TEE_TYPE_ECDSA_KEYPAIR);
4531220a68bSJorge Ramirez-Ortiz 	if (!pair_ops)
45449b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
45549b0febcSJorge Ramirez-Ortiz 
45649b0febcSJorge Ramirez-Ortiz 	pub_ops = crypto_asym_get_ecc_public_ops(TEE_TYPE_ECDSA_PUBLIC_KEY);
45749b0febcSJorge Ramirez-Ortiz 	if (!pub_ops)
45849b0febcSJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
45949b0febcSJorge Ramirez-Ortiz 
4601220a68bSJorge Ramirez-Ortiz 	/* This driver supports both ECDH and ECDSA */
4611220a68bSJorge Ramirez-Ortiz 	assert((pub_ops ==
4621220a68bSJorge Ramirez-Ortiz 		crypto_asym_get_ecc_public_ops(TEE_TYPE_ECDH_PUBLIC_KEY)) &&
4631220a68bSJorge Ramirez-Ortiz 	       (pair_ops ==
4641220a68bSJorge Ramirez-Ortiz 		crypto_asym_get_ecc_keypair_ops(TEE_TYPE_ECDH_KEYPAIR)));
4651220a68bSJorge Ramirez-Ortiz 
46649b0febcSJorge Ramirez-Ortiz 	return drvcrypt_register_ecc(&driver_ecc);
46749b0febcSJorge Ramirez-Ortiz }
46849b0febcSJorge Ramirez-Ortiz 
46949b0febcSJorge Ramirez-Ortiz driver_init(ecc_init);
470