xref: /optee_os/core/drivers/crypto/versal/ecc.c (revision 684b77de8bc819d83dab8e1f791804cbd5e01bc8)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) Foundries Ltd. 2022.
4  * Author: Jorge Ramirez <jorge@foundries.io>
5  */
6 
7 #include <drvcrypt.h>
8 #include <drvcrypt_acipher.h>
9 #include <crypto/crypto_impl.h>
10 #include <ecc.h>
11 #include <initcall.h>
12 #include <kernel/panic.h>
13 #include <mm/core_memprot.h>
14 #include <string.h>
15 #include <tee/cache.h>
16 #include <tee/tee_cryp_utl.h>
17 #include <util.h>
18 
19 /* Software based ECDSA operations */
20 static const struct crypto_ecc_keypair_ops *pair_ops;
21 static const struct crypto_ecc_public_ops *pub_ops;
22 
shared_secret(struct ecc_keypair * private_key,struct ecc_public_key * public_key,void * secret,size_t * secret_len)23 static TEE_Result shared_secret(struct ecc_keypair *private_key,
24 				struct ecc_public_key *public_key,
25 				void *secret, size_t *secret_len)
26 {
27 	return pair_ops->shared_secret(private_key, public_key,
28 					  secret, secret_len);
29 }
30 
do_shared_secret(struct drvcrypt_secret_data * sdata)31 static TEE_Result do_shared_secret(struct drvcrypt_secret_data *sdata)
32 {
33 	return shared_secret(sdata->key_priv,
34 			     sdata->key_pub,
35 			     sdata->secret.data,
36 			     &sdata->secret.length);
37 }
38 
do_sign(struct drvcrypt_sign_data * sdata)39 static TEE_Result do_sign(struct drvcrypt_sign_data *sdata)
40 {
41 	TEE_Result ret = TEE_SUCCESS;
42 
43 	ret = versal_ecc_sign(sdata->algo,
44 			      sdata->key,
45 			      sdata->message.data,
46 			      sdata->message.length,
47 			      sdata->signature.data,
48 			      &sdata->signature.length);
49 
50 	if (ret == TEE_ERROR_NOT_SUPPORTED) {
51 		/* Fallback to software */
52 		return pair_ops->sign(sdata->algo, sdata->key,
53 				      sdata->message.data,
54 				      sdata->message.length,
55 				      sdata->signature.data,
56 				      &sdata->signature.length);
57 	}
58 
59 	return ret;
60 }
61 
do_verify(struct drvcrypt_sign_data * sdata)62 static TEE_Result do_verify(struct drvcrypt_sign_data *sdata)
63 {
64 	TEE_Result ret = TEE_SUCCESS;
65 
66 	ret = versal_ecc_verify(sdata->algo,
67 				sdata->key,
68 				sdata->message.data,
69 				sdata->message.length,
70 				sdata->signature.data,
71 				sdata->signature.length);
72 
73 	if (ret == TEE_ERROR_NOT_SUPPORTED) {
74 		/* Fallback to software */
75 		return pub_ops->verify(sdata->algo, sdata->key,
76 				       sdata->message.data,
77 				       sdata->message.length,
78 				       sdata->signature.data,
79 				       sdata->signature.length);
80 	}
81 
82 	return ret;
83 }
84 
do_gen_keypair(struct ecc_keypair * s,size_t size_bits)85 static TEE_Result do_gen_keypair(struct ecc_keypair *s, size_t size_bits)
86 {
87 	TEE_Result ret = TEE_SUCCESS;
88 
89 	/*
90 	 * Versal requires little endian so need to versal_memcpy_swp on Versal
91 	 * IP ops. We chose not to do it here because some tests might be using
92 	 * their own keys
93 	 */
94 	ret = versal_ecc_gen_keypair(s);
95 
96 	if (ret == TEE_ERROR_NOT_SUPPORTED)
97 		/* Fallback to software */
98 		return pair_ops->generate(s, size_bits);
99 
100 #ifdef CFG_VERSAL_PKI_PWCT
101 	if (ret)
102 		return ret;
103 
104 	/* Perform a pairwise consistencty test on the generated key pair */
105 	ret = versal_ecc_keypair_pwct(s);
106 	if (ret)
107 		DMSG("Pair-wise consistency test failed (0x%" PRIx32 ")", ret);
108 #endif
109 
110 	return ret;
111 }
112 
do_alloc_keypair(struct ecc_keypair * s,uint32_t type,size_t size_bits)113 static TEE_Result do_alloc_keypair(struct ecc_keypair *s,
114 				   uint32_t type, size_t size_bits)
115 {
116 	TEE_Result ret = TEE_SUCCESS;
117 
118 	/* This driver only supports ECDH/ECDSA */
119 	if (type != TEE_TYPE_ECDSA_KEYPAIR &&
120 	    type != TEE_TYPE_ECDH_KEYPAIR)
121 		return TEE_ERROR_NOT_IMPLEMENTED;
122 
123 	ret = crypto_asym_alloc_ecc_keypair(s, TEE_TYPE_ECDSA_KEYPAIR,
124 					    size_bits);
125 	if (ret)
126 		return TEE_ERROR_NOT_IMPLEMENTED;
127 
128 	/*
129 	 * Ignore the software operations, the crypto API will populate
130 	 * this interface.
131 	 */
132 	s->ops = NULL;
133 
134 	return TEE_SUCCESS;
135 }
136 
do_alloc_publickey(struct ecc_public_key * s,uint32_t type,size_t size_bits)137 static TEE_Result do_alloc_publickey(struct ecc_public_key *s,
138 				     uint32_t type, size_t size_bits)
139 {
140 	TEE_Result ret = TEE_SUCCESS;
141 
142 	/* This driver only supports ECDH/ECDSA */
143 	if (type != TEE_TYPE_ECDSA_PUBLIC_KEY &&
144 	    type != TEE_TYPE_ECDH_PUBLIC_KEY)
145 		return TEE_ERROR_NOT_IMPLEMENTED;
146 
147 	ret = crypto_asym_alloc_ecc_public_key(s, TEE_TYPE_ECDSA_PUBLIC_KEY,
148 					       size_bits);
149 	if (ret)
150 		return TEE_ERROR_NOT_IMPLEMENTED;
151 
152 	/*
153 	 * Ignore the software operations, the crypto API will populate
154 	 * this interface.
155 	 */
156 	s->ops = NULL;
157 
158 	return TEE_SUCCESS;
159 }
160 
do_free_publickey(struct ecc_public_key * s)161 static void do_free_publickey(struct ecc_public_key *s)
162 {
163 	return pub_ops->free(s);
164 }
165 
166 static struct drvcrypt_ecc driver_ecc = {
167 	.shared_secret = do_shared_secret,
168 	.alloc_publickey = do_alloc_publickey,
169 	.free_publickey = do_free_publickey,
170 	.alloc_keypair = do_alloc_keypair,
171 	.gen_keypair = do_gen_keypair,
172 	.verify = do_verify,
173 	.sign = do_sign,
174 };
175 
ecc_init(void)176 static TEE_Result ecc_init(void)
177 {
178 	TEE_Result ret = TEE_SUCCESS;
179 
180 	/* HW initialization if needed */
181 	ret = versal_ecc_hw_init();
182 	if (ret)
183 		return ret;
184 
185 	/* Run KAT self-tests */
186 	ret = versal_ecc_kat_test();
187 	if (ret)
188 		return ret;
189 
190 	/* Initialize fallback to software implementations, if needed later */
191 	pair_ops = crypto_asym_get_ecc_keypair_ops(TEE_TYPE_ECDSA_KEYPAIR);
192 	if (!pair_ops)
193 		return TEE_ERROR_GENERIC;
194 
195 	pub_ops = crypto_asym_get_ecc_public_ops(TEE_TYPE_ECDSA_PUBLIC_KEY);
196 	if (!pub_ops)
197 		return TEE_ERROR_GENERIC;
198 
199 	/* This driver supports both ECDH and ECDSA */
200 	assert((pub_ops ==
201 		crypto_asym_get_ecc_public_ops(TEE_TYPE_ECDH_PUBLIC_KEY)) &&
202 	       (pair_ops ==
203 		crypto_asym_get_ecc_keypair_ops(TEE_TYPE_ECDH_KEYPAIR)));
204 
205 	return drvcrypt_register_ecc(&driver_ecc);
206 }
207 
208 driver_init(ecc_init);
209