416 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip / Atmel ECC (I2C) driver.4 *5 * Copyright (c) 2017, Microchip Technology Inc.6 * Author: Tudor Ambarus7 */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 26static struct atmel_ecc_driver_data driver_data;27 28/**29 * struct atmel_ecdh_ctx - transformation context30 * @client : pointer to i2c client device31 * @fallback : used for unsupported curves or when user wants to use its own32 * private key.33 * @public_key : generated when calling set_secret(). It's the responsibility34 * of the user to not call set_secret() while35 * generate_public_key() or compute_shared_secret() are in flight.36 * @curve_id : elliptic curve id37 * @do_fallback: true when the device doesn't support the curve or when the user38 * wants to use its own private key.39 */40struct 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 48static 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(req->dst, sg_nents_for_len(req->dst, n_sz),63 &cmd->data[RSP_DATA_IDX], n_sz);64 if (copied != n_sz)65 status = -EINVAL;66 67 /* fall through */68free_work_data:69 kfree_sensitive(work_data);70 kpp_request_complete(req, status);71}72 73/*74 * A random private key is generated and stored in the device. The device75 * returns the pair public key.76 */77static 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(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 96 if (params.key_size) {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 will108 * always be the same. Use a macro for the key size to avoid unnecessary109 * 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(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(cmd);128 return 0;129 130free_public_key:131 kfree(public_key);132free_cmd:133 kfree(cmd);134 return ret;135}136 137static 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, 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(req->dst,157 sg_nents_for_len(req->dst, nbytes),158 ctx->public_key, nbytes);159 if (copied != nbytes)160 ret = -EINVAL;161 162 return ret;163}164 165static 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, 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(sizeof(*work_data), 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(&work_data->cmd, req->src);193 if (ret)194 goto free_work_data;195 196 atmel_i2c_enqueue(work_data, atmel_ecdh_done, req);197 198 return -EINPROGRESS;199 200free_work_data:201 kfree(work_data);202 return ret;203}204 205static 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(-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 240static 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(&i2c_priv->tfm_count);245}246 247static 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(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));268 ctx->fallback = fallback;269 270 return 0;271}272 273static 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 282static 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 will291 * always be the same. Use a macro for the key size to avoid unnecessary292 * computations.293 */294 return ATMEL_ECC_PUBKEY_SIZE;295}296 297static 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 314static 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(&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 330 ret = crypto_register_kpp(&atmel_ecdh_nist_p256);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 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 345static 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(&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 function354 * is because in the Linux device model there is no error355 * handling for unbinding a driver.356 * If there is still some action pending, it probably involves357 * 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(&atmel_ecdh_nist_p256);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);368}369 370#ifdef CONFIG_OF371static const struct of_device_id atmel_ecc_dt_ids[] = {372 {373 .compatible = "atmel,atecc508a",374 }, {375 /* sentinel */376 }377};378MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids);379#endif380 381static const struct i2c_device_id atmel_ecc_id[] = {382 { "atecc508a", 0 },383 { }384};385MODULE_DEVICE_TABLE(i2c, atmel_ecc_id);386 387static 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 397static 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 404static void __exit atmel_ecc_exit(void)405{406 atmel_i2c_flush_queue();407 i2c_del_driver(&atmel_ecc_driver);408}409 410module_init(atmel_ecc_init);411module_exit(atmel_ecc_exit);412 413MODULE_AUTHOR("Tudor Ambarus");414MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");415MODULE_LICENSE("GPL v2");416