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