]>
Commit | Line | Data |
---|---|---|
820684cc | 1 | // SPDX-License-Identifier: GPL-2.0 |
11105693 TA |
2 | /* |
3 | * Microchip / Atmel ECC (I2C) driver. | |
4 | * | |
5 | * Copyright (c) 2017, Microchip Technology Inc. | |
c0f7ae27 | 6 | * Author: Tudor Ambarus |
11105693 TA |
7 | */ |
8 | ||
11105693 TA |
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> | |
b0cc7491 | 17 | #include <linux/of.h> |
11105693 TA |
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> | |
c34a3201 | 24 | #include "atmel-i2c.h" |
11105693 TA |
25 | |
26 | static struct atmel_ecc_driver_data driver_data; | |
27 | ||
11105693 | 28 | /** |
71057841 | 29 | * struct atmel_ecdh_ctx - transformation context |
11105693 TA |
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 | |
11105693 TA |
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; | |
11105693 TA |
45 | bool do_fallback; |
46 | }; | |
47 | ||
c34a3201 | 48 | static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq, |
6d2bce6a | 49 | int status) |
11105693 TA |
50 | { |
51 | struct kpp_request *req = areq; | |
c34a3201 | 52 | struct atmel_i2c_cmd *cmd = &work_data->cmd; |
e9440ff3 | 53 | size_t copied, n_sz; |
11105693 TA |
54 | |
55 | if (status) | |
56 | goto free_work_data; | |
57 | ||
e9440ff3 | 58 | /* might want less than we've got */ |
6763f5ea | 59 | n_sz = min_t(size_t, ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len); |
e9440ff3 | 60 | |
11105693 | 61 | /* copy the shared secret */ |
e9440ff3 TA |
62 | copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz), |
63 | &cmd->data[RSP_DATA_IDX], n_sz); | |
11105693 TA |
64 | if (copied != n_sz) |
65 | status = -EINVAL; | |
66 | ||
67 | /* fall through */ | |
68 | free_work_data: | |
453431a5 | 69 | kfree_sensitive(work_data); |
11105693 TA |
70 | kpp_request_complete(req, status); |
71 | } | |
72 | ||
11105693 TA |
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); | |
c34a3201 | 81 | struct atmel_i2c_cmd *cmd; |
11105693 TA |
82 | void *public_key; |
83 | struct ecdh params; | |
84 | int ret = -ENOMEM; | |
85 | ||
86 | /* free the old public key, if any */ | |
87 | kfree(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, ¶ms) < 0) { | |
92 | dev_err(&ctx->client->dev, "crypto_ecdh_decode_key failed\n"); | |
93 | return -EINVAL; | |
94 | } | |
95 | ||
6763f5ea | 96 | if (params.key_size) { |
11105693 TA |
97 | /* fallback to ecdh software implementation */ |
98 | ctx->do_fallback = true; | |
99 | return crypto_kpp_set_secret(ctx->fallback, buf, len); | |
100 | } | |
101 | ||
102 | cmd = kmalloc(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; | |
11105693 | 116 | |
c34a3201 | 117 | atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2); |
11105693 | 118 | |
c34a3201 | 119 | ret = atmel_i2c_send_receive(ctx->client, cmd); |
11105693 TA |
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(cmd); | |
128 | return 0; | |
129 | ||
130 | free_public_key: | |
131 | kfree(public_key); | |
132 | free_cmd: | |
133 | kfree(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); | |
e9440ff3 | 141 | size_t copied, nbytes; |
11105693 TA |
142 | int ret = 0; |
143 | ||
144 | if (ctx->do_fallback) { | |
145 | kpp_request_set_tfm(req, ctx->fallback); | |
146 | return crypto_kpp_generate_public_key(req); | |
147 | } | |
148 | ||
c34a3201 AB |
149 | if (!ctx->public_key) |
150 | return -EINVAL; | |
151 | ||
e9440ff3 TA |
152 | /* might want less than we've got */ |
153 | nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len); | |
154 | ||
11105693 | 155 | /* public key was saved at private key generation */ |
e9440ff3 TA |
156 | copied = sg_copy_from_buffer(req->dst, |
157 | sg_nents_for_len(req->dst, nbytes), | |
158 | ctx->public_key, nbytes); | |
159 | if (copied != nbytes) | |
11105693 TA |
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); | |
c34a3201 | 169 | struct atmel_i2c_work_data *work_data; |
11105693 TA |
170 | gfp_t gfp; |
171 | int ret; | |
172 | ||
173 | if (ctx->do_fallback) { | |
174 | kpp_request_set_tfm(req, ctx->fallback); | |
175 | return crypto_kpp_compute_shared_secret(req); | |
176 | } | |
177 | ||
e9440ff3 TA |
178 | /* must have exactly two points to be on the curve */ |
179 | if (req->src_len != ATMEL_ECC_PUBKEY_SIZE) | |
180 | return -EINVAL; | |
181 | ||
11105693 TA |
182 | gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL : |
183 | GFP_ATOMIC; | |
184 | ||
185 | work_data = kmalloc(sizeof(*work_data), gfp); | |
186 | if (!work_data) | |
187 | return -ENOMEM; | |
188 | ||
189 | work_data->ctx = ctx; | |
c34a3201 | 190 | work_data->client = ctx->client; |
11105693 | 191 | |
c34a3201 | 192 | ret = atmel_i2c_init_ecdh_cmd(&work_data->cmd, req->src); |
11105693 TA |
193 | if (ret) |
194 | goto free_work_data; | |
195 | ||
c34a3201 | 196 | atmel_i2c_enqueue(work_data, atmel_ecdh_done, req); |
11105693 TA |
197 | |
198 | return -EINPROGRESS; | |
199 | ||
200 | free_work_data: | |
201 | kfree(work_data); | |
202 | return ret; | |
203 | } | |
204 | ||
0138d32f | 205 | static struct i2c_client *atmel_ecc_i2c_client_alloc(void) |
11105693 | 206 | { |
c34a3201 | 207 | struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL; |
11105693 TA |
208 | struct i2c_client *client = ERR_PTR(-ENODEV); |
209 | int min_tfm_cnt = INT_MAX; | |
210 | int tfm_cnt; | |
211 | ||
212 | spin_lock(&driver_data.i2c_list_lock); | |
213 | ||
214 | if (list_empty(&driver_data.i2c_client_list)) { | |
215 | spin_unlock(&driver_data.i2c_list_lock); | |
216 | return ERR_PTR(-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(&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(&min_i2c_priv->tfm_count); | |
232 | client = min_i2c_priv->client; | |
233 | } | |
234 | ||
235 | spin_unlock(&driver_data.i2c_list_lock); | |
236 | ||
237 | return client; | |
238 | } | |
239 | ||
0138d32f | 240 | static void atmel_ecc_i2c_client_free(struct i2c_client *client) |
11105693 | 241 | { |
c34a3201 | 242 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); |
11105693 TA |
243 | |
244 | atomic_dec(&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 | ||
6763f5ea | 253 | ctx->curve_id = ECC_CURVE_NIST_P256; |
11105693 TA |
254 | ctx->client = atmel_ecc_i2c_client_alloc(); |
255 | if (IS_ERR(ctx->client)) { | |
256 | pr_err("tfm - i2c_client binding failed\n"); | |
257 | return PTR_ERR(ctx->client); | |
258 | } | |
259 | ||
260 | fallback = crypto_alloc_kpp(alg, 0, CRYPTO_ALG_NEED_FALLBACK); | |
261 | if (IS_ERR(fallback)) { | |
262 | dev_err(&ctx->client->dev, "Failed to allocate transformation for '%s': %ld\n", | |
263 | alg, PTR_ERR(fallback)); | |
264 | return PTR_ERR(fallback); | |
265 | } | |
266 | ||
267 | crypto_kpp_set_flags(fallback, crypto_kpp_get_flags(tfm)); | |
11105693 TA |
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(ctx->public_key); | |
278 | crypto_free_kpp(ctx->fallback); | |
279 | atmel_ecc_i2c_client_free(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(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 | ||
6763f5ea | 297 | static struct kpp_alg atmel_ecdh_nist_p256 = { |
11105693 TA |
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, | |
6763f5ea | 306 | .cra_name = "ecdh-nist-p256", |
11105693 TA |
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 | ||
b8ed0bff | 314 | static int atmel_ecc_probe(struct i2c_client *client) |
11105693 | 315 | { |
c34a3201 | 316 | struct atmel_i2c_client_priv *i2c_priv; |
11105693 | 317 | int ret; |
11105693 | 318 | |
d58fa987 | 319 | ret = atmel_i2c_probe(client); |
11105693 TA |
320 | if (ret) |
321 | return ret; | |
322 | ||
c34a3201 AB |
323 | i2c_priv = i2c_get_clientdata(client); |
324 | ||
11105693 TA |
325 | spin_lock(&driver_data.i2c_list_lock); |
326 | list_add_tail(&i2c_priv->i2c_client_list_node, | |
327 | &driver_data.i2c_client_list); | |
328 | spin_unlock(&driver_data.i2c_list_lock); | |
329 | ||
6763f5ea | 330 | ret = crypto_register_kpp(&atmel_ecdh_nist_p256); |
11105693 TA |
331 | if (ret) { |
332 | spin_lock(&driver_data.i2c_list_lock); | |
333 | list_del(&i2c_priv->i2c_client_list_node); | |
334 | spin_unlock(&driver_data.i2c_list_lock); | |
335 | ||
c34a3201 | 336 | dev_err(&client->dev, "%s alg registration failed\n", |
6763f5ea | 337 | atmel_ecdh_nist_p256.base.cra_driver_name); |
11105693 | 338 | } else { |
c34a3201 | 339 | dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n"); |
11105693 TA |
340 | } |
341 | ||
342 | return ret; | |
343 | } | |
344 | ||
ed5c2f5f | 345 | static void atmel_ecc_remove(struct i2c_client *client) |
11105693 | 346 | { |
c34a3201 | 347 | struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client); |
11105693 TA |
348 | |
349 | /* Return EBUSY if i2c client already allocated. */ | |
350 | if (atomic_read(&i2c_priv->tfm_count)) { | |
7df7563b UKK |
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"); | |
ed5c2f5f | 360 | return; |
11105693 TA |
361 | } |
362 | ||
6763f5ea | 363 | crypto_unregister_kpp(&atmel_ecdh_nist_p256); |
11105693 TA |
364 | |
365 | spin_lock(&driver_data.i2c_list_lock); | |
366 | list_del(&i2c_priv->i2c_client_list_node); | |
367 | spin_unlock(&driver_data.i2c_list_lock); | |
11105693 TA |
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 | }, | |
755b4e7f | 392 | .probe = atmel_ecc_probe, |
11105693 TA |
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(&driver_data.i2c_client_list); | |
401 | return i2c_add_driver(&atmel_ecc_driver); | |
402 | } | |
403 | ||
404 | static void __exit atmel_ecc_exit(void) | |
405 | { | |
0a2f4b57 | 406 | atmel_i2c_flush_queue(); |
11105693 TA |
407 | i2c_del_driver(&atmel_ecc_driver); |
408 | } | |
409 | ||
410 | module_init(atmel_ecc_init); | |
411 | module_exit(atmel_ecc_exit); | |
412 | ||
c0f7ae27 | 413 | MODULE_AUTHOR("Tudor Ambarus"); |
11105693 TA |
414 | MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver"); |
415 | MODULE_LICENSE("GPL v2"); |