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