1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Microchip / Atmel ECC (I2C) driver. |
4 | * |
5 | * Copyright (c) 2017, Microchip Technology Inc. |
6 | * Author: Tudor Ambarus |
7 | */ |
8 | |
9 | #include <linux/delay.h> |
10 | #include <linux/device.h> |
11 | #include <linux/err.h> |
12 | #include <linux/errno.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/init.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/scatterlist.h> |
19 | #include <linux/slab.h> |
20 | #include <linux/workqueue.h> |
21 | #include <crypto/internal/kpp.h> |
22 | #include <crypto/ecdh.h> |
23 | #include <crypto/kpp.h> |
24 | #include "atmel-i2c.h" |
25 | |
26 | static struct atmel_ecc_driver_data driver_data; |
27 | |
28 | /** |
29 | * struct atmel_ecdh_ctx - transformation context |
30 | * @client : pointer to i2c client device |
31 | * @fallback : used for unsupported curves or when user wants to use its own |
32 | * private key. |
33 | * @public_key : generated when calling set_secret(). It's the responsibility |
34 | * of the user to not call set_secret() while |
35 | * generate_public_key() or compute_shared_secret() are in flight. |
36 | * @curve_id : elliptic curve id |
37 | * @do_fallback: true when the device doesn't support the curve or when the user |
38 | * wants to use its own private key. |
39 | */ |
40 | struct atmel_ecdh_ctx { |
41 | struct i2c_client *client; |
42 | struct crypto_kpp *fallback; |
43 | const u8 *public_key; |
44 | unsigned int curve_id; |
45 | bool do_fallback; |
46 | }; |
47 | |
48 | static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, |
49 | int status) |
50 | { |
51 | struct kpp_request *req = areq; |
52 | struct atmel_i2c_cmd *cmd = &work_data->cmd; |
53 | size_t copied, n_sz; |
54 | |
55 | if (status) |
56 | goto free_work_data; |
57 | |
58 | /* might want less than we've got */ |
59 | n_sz = min_t(size_t, ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len); |
60 | |
61 | /* copy the shared secret */ |
62 | copied = sg_copy_from_buffer(sgl: req->dst, nents: sg_nents_for_len(sg: req->dst, len: n_sz), |
63 | buf: &cmd->data[RSP_DATA_IDX], buflen: n_sz); |
64 | if (copied != n_sz) |
65 | status = -EINVAL; |
66 | |
67 | /* fall through */ |
68 | free_work_data: |
69 | kfree_sensitive(objp: work_data); |
70 | kpp_request_complete(req, err: status); |
71 | } |
72 | |
73 | /* |
74 | * A random private key is generated and stored in the device. The device |
75 | * returns the pair public key. |
76 | */ |
77 | static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf, |
78 | unsigned int len) |
79 | { |
80 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
81 | struct atmel_i2c_cmd *cmd; |
82 | void *public_key; |
83 | struct ecdh params; |
84 | int ret = -ENOMEM; |
85 | |
86 | /* free the old public key, if any */ |
87 | kfree(objp: ctx->public_key); |
88 | /* make sure you don't free the old public key twice */ |
89 | ctx->public_key = NULL; |
90 | |
91 | if (crypto_ecdh_decode_key(buf, len, p: ¶ms) < 0) { |
92 | dev_err(&ctx->client->dev, "crypto_ecdh_decode_key failed\n" ); |
93 | return -EINVAL; |
94 | } |
95 | |
96 | if (params.key_size) { |
97 | /* fallback to ecdh software implementation */ |
98 | ctx->do_fallback = true; |
99 | return crypto_kpp_set_secret(tfm: ctx->fallback, buffer: buf, len); |
100 | } |
101 | |
102 | cmd = kmalloc(size: sizeof(*cmd), GFP_KERNEL); |
103 | if (!cmd) |
104 | return -ENOMEM; |
105 | |
106 | /* |
107 | * The device only supports NIST P256 ECC keys. The public key size will |
108 | * always be the same. Use a macro for the key size to avoid unnecessary |
109 | * computations. |
110 | */ |
111 | public_key = kmalloc(ATMEL_ECC_PUBKEY_SIZE, GFP_KERNEL); |
112 | if (!public_key) |
113 | goto free_cmd; |
114 | |
115 | ctx->do_fallback = false; |
116 | |
117 | atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2); |
118 | |
119 | ret = atmel_i2c_send_receive(client: ctx->client, cmd); |
120 | if (ret) |
121 | goto free_public_key; |
122 | |
123 | /* save the public key */ |
124 | memcpy(public_key, &cmd->data[RSP_DATA_IDX], ATMEL_ECC_PUBKEY_SIZE); |
125 | ctx->public_key = public_key; |
126 | |
127 | kfree(objp: cmd); |
128 | return 0; |
129 | |
130 | free_public_key: |
131 | kfree(objp: public_key); |
132 | free_cmd: |
133 | kfree(objp: cmd); |
134 | return ret; |
135 | } |
136 | |
137 | static int atmel_ecdh_generate_public_key(struct kpp_request *req) |
138 | { |
139 | struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); |
140 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
141 | size_t copied, nbytes; |
142 | int ret = 0; |
143 | |
144 | if (ctx->do_fallback) { |
145 | kpp_request_set_tfm(req, tfm: ctx->fallback); |
146 | return crypto_kpp_generate_public_key(req); |
147 | } |
148 | |
149 | if (!ctx->public_key) |
150 | return -EINVAL; |
151 | |
152 | /* might want less than we've got */ |
153 | nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); |
154 | |
155 | /* public key was saved at private key generation */ |
156 | copied = sg_copy_from_buffer(sgl: req->dst, |
157 | nents: sg_nents_for_len(sg: req->dst, len: nbytes), |
158 | buf: ctx->public_key, buflen: nbytes); |
159 | if (copied != nbytes) |
160 | ret = -EINVAL; |
161 | |
162 | return ret; |
163 | } |
164 | |
165 | static int atmel_ecdh_compute_shared_secret(struct kpp_request *req) |
166 | { |
167 | struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); |
168 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
169 | struct atmel_i2c_work_data *work_data; |
170 | gfp_t gfp; |
171 | int ret; |
172 | |
173 | if (ctx->do_fallback) { |
174 | kpp_request_set_tfm(req, tfm: ctx->fallback); |
175 | return crypto_kpp_compute_shared_secret(req); |
176 | } |
177 | |
178 | /* must have exactly two points to be on the curve */ |
179 | if (req->src_len != ATMEL_ECC_PUBKEY_SIZE) |
180 | return -EINVAL; |
181 | |
182 | gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : |
183 | GFP_ATOMIC; |
184 | |
185 | work_data = kmalloc(size: sizeof(*work_data), flags: gfp); |
186 | if (!work_data) |
187 | return -ENOMEM; |
188 | |
189 | work_data->ctx = ctx; |
190 | work_data->client = ctx->client; |
191 | |
192 | ret = atmel_i2c_init_ecdh_cmd(cmd: &work_data->cmd, pubkey: req->src); |
193 | if (ret) |
194 | goto free_work_data; |
195 | |
196 | atmel_i2c_enqueue(work_data, cbk: atmel_ecdh_done, areq: req); |
197 | |
198 | return -EINPROGRESS; |
199 | |
200 | free_work_data: |
201 | kfree(objp: work_data); |
202 | return ret; |
203 | } |
204 | |
205 | static struct i2c_client *atmel_ecc_i2c_client_alloc(void) |
206 | { |
207 | struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; |
208 | struct i2c_client *client = ERR_PTR(error: -ENODEV); |
209 | int min_tfm_cnt = INT_MAX; |
210 | int tfm_cnt; |
211 | |
212 | spin_lock(lock: &driver_data.i2c_list_lock); |
213 | |
214 | if (list_empty(head: &driver_data.i2c_client_list)) { |
215 | spin_unlock(lock: &driver_data.i2c_list_lock); |
216 | return ERR_PTR(error: -ENODEV); |
217 | } |
218 | |
219 | list_for_each_entry(i2c_priv, &driver_data.i2c_client_list, |
220 | i2c_client_list_node) { |
221 | tfm_cnt = atomic_read(v: &i2c_priv->tfm_count); |
222 | if (tfm_cnt < min_tfm_cnt) { |
223 | min_tfm_cnt = tfm_cnt; |
224 | min_i2c_priv = i2c_priv; |
225 | } |
226 | if (!min_tfm_cnt) |
227 | break; |
228 | } |
229 | |
230 | if (min_i2c_priv) { |
231 | atomic_inc(v: &min_i2c_priv->tfm_count); |
232 | client = min_i2c_priv->client; |
233 | } |
234 | |
235 | spin_unlock(lock: &driver_data.i2c_list_lock); |
236 | |
237 | return client; |
238 | } |
239 | |
240 | static void atmel_ecc_i2c_client_free(struct i2c_client *client) |
241 | { |
242 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); |
243 | |
244 | atomic_dec(v: &i2c_priv->tfm_count); |
245 | } |
246 | |
247 | static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm) |
248 | { |
249 | const char *alg = kpp_alg_name(tfm); |
250 | struct crypto_kpp *fallback; |
251 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
252 | |
253 | ctx->curve_id = ECC_CURVE_NIST_P256; |
254 | ctx->client = atmel_ecc_i2c_client_alloc(); |
255 | if (IS_ERR(ptr: ctx->client)) { |
256 | pr_err("tfm - i2c_client binding failed\n" ); |
257 | return PTR_ERR(ptr: ctx->client); |
258 | } |
259 | |
260 | fallback = crypto_alloc_kpp(alg_name: alg, type: 0, CRYPTO_ALG_NEED_FALLBACK); |
261 | if (IS_ERR(ptr: fallback)) { |
262 | dev_err(&ctx->client->dev, "Failed to allocate transformation for '%s': %ld\n" , |
263 | alg, PTR_ERR(fallback)); |
264 | return PTR_ERR(ptr: fallback); |
265 | } |
266 | |
267 | crypto_kpp_set_flags(tfm: fallback, flags: crypto_kpp_get_flags(tfm)); |
268 | ctx->fallback = fallback; |
269 | |
270 | return 0; |
271 | } |
272 | |
273 | static void atmel_ecdh_exit_tfm(struct crypto_kpp *tfm) |
274 | { |
275 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
276 | |
277 | kfree(objp: ctx->public_key); |
278 | crypto_free_kpp(tfm: ctx->fallback); |
279 | atmel_ecc_i2c_client_free(client: ctx->client); |
280 | } |
281 | |
282 | static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm) |
283 | { |
284 | struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm); |
285 | |
286 | if (ctx->fallback) |
287 | return crypto_kpp_maxsize(tfm: ctx->fallback); |
288 | |
289 | /* |
290 | * The device only supports NIST P256 ECC keys. The public key size will |
291 | * always be the same. Use a macro for the key size to avoid unnecessary |
292 | * computations. |
293 | */ |
294 | return ATMEL_ECC_PUBKEY_SIZE; |
295 | } |
296 | |
297 | static struct kpp_alg atmel_ecdh_nist_p256 = { |
298 | .set_secret = atmel_ecdh_set_secret, |
299 | .generate_public_key = atmel_ecdh_generate_public_key, |
300 | .compute_shared_secret = atmel_ecdh_compute_shared_secret, |
301 | .init = atmel_ecdh_init_tfm, |
302 | .exit = atmel_ecdh_exit_tfm, |
303 | .max_size = atmel_ecdh_max_size, |
304 | .base = { |
305 | .cra_flags = CRYPTO_ALG_NEED_FALLBACK, |
306 | .cra_name = "ecdh-nist-p256" , |
307 | .cra_driver_name = "atmel-ecdh" , |
308 | .cra_priority = ATMEL_ECC_PRIORITY, |
309 | .cra_module = THIS_MODULE, |
310 | .cra_ctxsize = sizeof(struct atmel_ecdh_ctx), |
311 | }, |
312 | }; |
313 | |
314 | static int atmel_ecc_probe(struct i2c_client *client) |
315 | { |
316 | struct atmel_i2c_client_priv *i2c_priv; |
317 | int ret; |
318 | |
319 | ret = atmel_i2c_probe(client); |
320 | if (ret) |
321 | return ret; |
322 | |
323 | i2c_priv = i2c_get_clientdata(client); |
324 | |
325 | spin_lock(lock: &driver_data.i2c_list_lock); |
326 | list_add_tail(new: &i2c_priv->i2c_client_list_node, |
327 | head: &driver_data.i2c_client_list); |
328 | spin_unlock(lock: &driver_data.i2c_list_lock); |
329 | |
330 | ret = crypto_register_kpp(alg: &atmel_ecdh_nist_p256); |
331 | if (ret) { |
332 | spin_lock(lock: &driver_data.i2c_list_lock); |
333 | list_del(entry: &i2c_priv->i2c_client_list_node); |
334 | spin_unlock(lock: &driver_data.i2c_list_lock); |
335 | |
336 | dev_err(&client->dev, "%s alg registration failed\n" , |
337 | atmel_ecdh_nist_p256.base.cra_driver_name); |
338 | } else { |
339 | dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n" ); |
340 | } |
341 | |
342 | return ret; |
343 | } |
344 | |
345 | static void atmel_ecc_remove(struct i2c_client *client) |
346 | { |
347 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); |
348 | |
349 | /* Return EBUSY if i2c client already allocated. */ |
350 | if (atomic_read(v: &i2c_priv->tfm_count)) { |
351 | /* |
352 | * After we return here, the memory backing the device is freed. |
353 | * That happens no matter what the return value of this function |
354 | * is because in the Linux device model there is no error |
355 | * handling for unbinding a driver. |
356 | * If there is still some action pending, it probably involves |
357 | * accessing the freed memory. |
358 | */ |
359 | dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n" ); |
360 | return; |
361 | } |
362 | |
363 | crypto_unregister_kpp(alg: &atmel_ecdh_nist_p256); |
364 | |
365 | spin_lock(lock: &driver_data.i2c_list_lock); |
366 | list_del(entry: &i2c_priv->i2c_client_list_node); |
367 | spin_unlock(lock: &driver_data.i2c_list_lock); |
368 | } |
369 | |
370 | #ifdef CONFIG_OF |
371 | static const struct of_device_id atmel_ecc_dt_ids[] = { |
372 | { |
373 | .compatible = "atmel,atecc508a" , |
374 | }, { |
375 | /* sentinel */ |
376 | } |
377 | }; |
378 | MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids); |
379 | #endif |
380 | |
381 | static const struct i2c_device_id atmel_ecc_id[] = { |
382 | { "atecc508a" , 0 }, |
383 | { } |
384 | }; |
385 | MODULE_DEVICE_TABLE(i2c, atmel_ecc_id); |
386 | |
387 | static struct i2c_driver atmel_ecc_driver = { |
388 | .driver = { |
389 | .name = "atmel-ecc" , |
390 | .of_match_table = of_match_ptr(atmel_ecc_dt_ids), |
391 | }, |
392 | .probe = atmel_ecc_probe, |
393 | .remove = atmel_ecc_remove, |
394 | .id_table = atmel_ecc_id, |
395 | }; |
396 | |
397 | static int __init atmel_ecc_init(void) |
398 | { |
399 | spin_lock_init(&driver_data.i2c_list_lock); |
400 | INIT_LIST_HEAD(list: &driver_data.i2c_client_list); |
401 | return i2c_add_driver(&atmel_ecc_driver); |
402 | } |
403 | |
404 | static void __exit atmel_ecc_exit(void) |
405 | { |
406 | atmel_i2c_flush_queue(); |
407 | i2c_del_driver(driver: &atmel_ecc_driver); |
408 | } |
409 | |
410 | module_init(atmel_ecc_init); |
411 | module_exit(atmel_ecc_exit); |
412 | |
413 | MODULE_AUTHOR("Tudor Ambarus" ); |
414 | MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver" ); |
415 | MODULE_LICENSE("GPL v2" ); |
416 | |