0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/delay.h>
0010 #include <linux/device.h>
0011 #include <linux/err.h>
0012 #include <linux/errno.h>
0013 #include <linux/i2c.h>
0014 #include <linux/init.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/of_device.h>
0018 #include <linux/scatterlist.h>
0019 #include <linux/slab.h>
0020 #include <linux/workqueue.h>
0021 #include <crypto/internal/kpp.h>
0022 #include <crypto/ecdh.h>
0023 #include <crypto/kpp.h>
0024 #include "atmel-i2c.h"
0025
0026 static struct atmel_ecc_driver_data driver_data;
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 struct atmel_ecdh_ctx {
0041 struct i2c_client *client;
0042 struct crypto_kpp *fallback;
0043 const u8 *public_key;
0044 unsigned int curve_id;
0045 bool do_fallback;
0046 };
0047
0048 static void atmel_ecdh_done(struct atmel_i2c_work_data *work_data, void *areq,
0049 int status)
0050 {
0051 struct kpp_request *req = areq;
0052 struct atmel_i2c_cmd *cmd = &work_data->cmd;
0053 size_t copied, n_sz;
0054
0055 if (status)
0056 goto free_work_data;
0057
0058
0059 n_sz = min_t(size_t, ATMEL_ECC_NIST_P256_N_SIZE, req->dst_len);
0060
0061
0062 copied = sg_copy_from_buffer(req->dst, sg_nents_for_len(req->dst, n_sz),
0063 &cmd->data[RSP_DATA_IDX], n_sz);
0064 if (copied != n_sz)
0065 status = -EINVAL;
0066
0067
0068 free_work_data:
0069 kfree_sensitive(work_data);
0070 kpp_request_complete(req, status);
0071 }
0072
0073
0074
0075
0076
0077 static int atmel_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,
0078 unsigned int len)
0079 {
0080 struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
0081 struct atmel_i2c_cmd *cmd;
0082 void *public_key;
0083 struct ecdh params;
0084 int ret = -ENOMEM;
0085
0086
0087 kfree(ctx->public_key);
0088
0089 ctx->public_key = NULL;
0090
0091 if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0) {
0092 dev_err(&ctx->client->dev, "crypto_ecdh_decode_key failed\n");
0093 return -EINVAL;
0094 }
0095
0096 if (params.key_size) {
0097
0098 ctx->do_fallback = true;
0099 return crypto_kpp_set_secret(ctx->fallback, buf, len);
0100 }
0101
0102 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
0103 if (!cmd)
0104 return -ENOMEM;
0105
0106
0107
0108
0109
0110
0111 public_key = kmalloc(ATMEL_ECC_PUBKEY_SIZE, GFP_KERNEL);
0112 if (!public_key)
0113 goto free_cmd;
0114
0115 ctx->do_fallback = false;
0116
0117 atmel_i2c_init_genkey_cmd(cmd, DATA_SLOT_2);
0118
0119 ret = atmel_i2c_send_receive(ctx->client, cmd);
0120 if (ret)
0121 goto free_public_key;
0122
0123
0124 memcpy(public_key, &cmd->data[RSP_DATA_IDX], ATMEL_ECC_PUBKEY_SIZE);
0125 ctx->public_key = public_key;
0126
0127 kfree(cmd);
0128 return 0;
0129
0130 free_public_key:
0131 kfree(public_key);
0132 free_cmd:
0133 kfree(cmd);
0134 return ret;
0135 }
0136
0137 static int atmel_ecdh_generate_public_key(struct kpp_request *req)
0138 {
0139 struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
0140 struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
0141 size_t copied, nbytes;
0142 int ret = 0;
0143
0144 if (ctx->do_fallback) {
0145 kpp_request_set_tfm(req, ctx->fallback);
0146 return crypto_kpp_generate_public_key(req);
0147 }
0148
0149 if (!ctx->public_key)
0150 return -EINVAL;
0151
0152
0153 nbytes = min_t(size_t, ATMEL_ECC_PUBKEY_SIZE, req->dst_len);
0154
0155
0156 copied = sg_copy_from_buffer(req->dst,
0157 sg_nents_for_len(req->dst, nbytes),
0158 ctx->public_key, nbytes);
0159 if (copied != nbytes)
0160 ret = -EINVAL;
0161
0162 return ret;
0163 }
0164
0165 static int atmel_ecdh_compute_shared_secret(struct kpp_request *req)
0166 {
0167 struct crypto_kpp *tfm = crypto_kpp_reqtfm(req);
0168 struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
0169 struct atmel_i2c_work_data *work_data;
0170 gfp_t gfp;
0171 int ret;
0172
0173 if (ctx->do_fallback) {
0174 kpp_request_set_tfm(req, ctx->fallback);
0175 return crypto_kpp_compute_shared_secret(req);
0176 }
0177
0178
0179 if (req->src_len != ATMEL_ECC_PUBKEY_SIZE)
0180 return -EINVAL;
0181
0182 gfp = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? GFP_KERNEL :
0183 GFP_ATOMIC;
0184
0185 work_data = kmalloc(sizeof(*work_data), gfp);
0186 if (!work_data)
0187 return -ENOMEM;
0188
0189 work_data->ctx = ctx;
0190 work_data->client = ctx->client;
0191
0192 ret = atmel_i2c_init_ecdh_cmd(&work_data->cmd, req->src);
0193 if (ret)
0194 goto free_work_data;
0195
0196 atmel_i2c_enqueue(work_data, atmel_ecdh_done, req);
0197
0198 return -EINPROGRESS;
0199
0200 free_work_data:
0201 kfree(work_data);
0202 return ret;
0203 }
0204
0205 static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
0206 {
0207 struct atmel_i2c_client_priv *i2c_priv, *min_i2c_priv = NULL;
0208 struct i2c_client *client = ERR_PTR(-ENODEV);
0209 int min_tfm_cnt = INT_MAX;
0210 int tfm_cnt;
0211
0212 spin_lock(&driver_data.i2c_list_lock);
0213
0214 if (list_empty(&driver_data.i2c_client_list)) {
0215 spin_unlock(&driver_data.i2c_list_lock);
0216 return ERR_PTR(-ENODEV);
0217 }
0218
0219 list_for_each_entry(i2c_priv, &driver_data.i2c_client_list,
0220 i2c_client_list_node) {
0221 tfm_cnt = atomic_read(&i2c_priv->tfm_count);
0222 if (tfm_cnt < min_tfm_cnt) {
0223 min_tfm_cnt = tfm_cnt;
0224 min_i2c_priv = i2c_priv;
0225 }
0226 if (!min_tfm_cnt)
0227 break;
0228 }
0229
0230 if (min_i2c_priv) {
0231 atomic_inc(&min_i2c_priv->tfm_count);
0232 client = min_i2c_priv->client;
0233 }
0234
0235 spin_unlock(&driver_data.i2c_list_lock);
0236
0237 return client;
0238 }
0239
0240 static void atmel_ecc_i2c_client_free(struct i2c_client *client)
0241 {
0242 struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
0243
0244 atomic_dec(&i2c_priv->tfm_count);
0245 }
0246
0247 static int atmel_ecdh_init_tfm(struct crypto_kpp *tfm)
0248 {
0249 const char *alg = kpp_alg_name(tfm);
0250 struct crypto_kpp *fallback;
0251 struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
0252
0253 ctx->curve_id = ECC_CURVE_NIST_P256;
0254 ctx->client = atmel_ecc_i2c_client_alloc();
0255 if (IS_ERR(ctx->client)) {
0256 pr_err("tfm - i2c_client binding failed\n");
0257 return PTR_ERR(ctx->client);
0258 }
0259
0260 fallback = crypto_alloc_kpp(alg, 0, CRYPTO_ALG_NEED_FALLBACK);
0261 if (IS_ERR(fallback)) {
0262 dev_err(&ctx->client->dev, "Failed to allocate transformation for '%s': %ld\n",
0263 alg, PTR_ERR(fallback));
0264 return PTR_ERR(fallback);
0265 }
0266
0267 crypto_kpp_set_flags(fallback, crypto_kpp_get_flags(tfm));
0268 ctx->fallback = fallback;
0269
0270 return 0;
0271 }
0272
0273 static void atmel_ecdh_exit_tfm(struct crypto_kpp *tfm)
0274 {
0275 struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
0276
0277 kfree(ctx->public_key);
0278 crypto_free_kpp(ctx->fallback);
0279 atmel_ecc_i2c_client_free(ctx->client);
0280 }
0281
0282 static unsigned int atmel_ecdh_max_size(struct crypto_kpp *tfm)
0283 {
0284 struct atmel_ecdh_ctx *ctx = kpp_tfm_ctx(tfm);
0285
0286 if (ctx->fallback)
0287 return crypto_kpp_maxsize(ctx->fallback);
0288
0289
0290
0291
0292
0293
0294 return ATMEL_ECC_PUBKEY_SIZE;
0295 }
0296
0297 static struct kpp_alg atmel_ecdh_nist_p256 = {
0298 .set_secret = atmel_ecdh_set_secret,
0299 .generate_public_key = atmel_ecdh_generate_public_key,
0300 .compute_shared_secret = atmel_ecdh_compute_shared_secret,
0301 .init = atmel_ecdh_init_tfm,
0302 .exit = atmel_ecdh_exit_tfm,
0303 .max_size = atmel_ecdh_max_size,
0304 .base = {
0305 .cra_flags = CRYPTO_ALG_NEED_FALLBACK,
0306 .cra_name = "ecdh-nist-p256",
0307 .cra_driver_name = "atmel-ecdh",
0308 .cra_priority = ATMEL_ECC_PRIORITY,
0309 .cra_module = THIS_MODULE,
0310 .cra_ctxsize = sizeof(struct atmel_ecdh_ctx),
0311 },
0312 };
0313
0314 static int atmel_ecc_probe(struct i2c_client *client,
0315 const struct i2c_device_id *id)
0316 {
0317 struct atmel_i2c_client_priv *i2c_priv;
0318 int ret;
0319
0320 ret = atmel_i2c_probe(client, id);
0321 if (ret)
0322 return ret;
0323
0324 i2c_priv = i2c_get_clientdata(client);
0325
0326 spin_lock(&driver_data.i2c_list_lock);
0327 list_add_tail(&i2c_priv->i2c_client_list_node,
0328 &driver_data.i2c_client_list);
0329 spin_unlock(&driver_data.i2c_list_lock);
0330
0331 ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
0332 if (ret) {
0333 spin_lock(&driver_data.i2c_list_lock);
0334 list_del(&i2c_priv->i2c_client_list_node);
0335 spin_unlock(&driver_data.i2c_list_lock);
0336
0337 dev_err(&client->dev, "%s alg registration failed\n",
0338 atmel_ecdh_nist_p256.base.cra_driver_name);
0339 } else {
0340 dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
0341 }
0342
0343 return ret;
0344 }
0345
0346 static int atmel_ecc_remove(struct i2c_client *client)
0347 {
0348 struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
0349
0350
0351 if (atomic_read(&i2c_priv->tfm_count)) {
0352
0353
0354
0355
0356
0357
0358
0359
0360 dev_emerg(&client->dev, "Device is busy, expect memory corruption.\n");
0361 return 0;
0362 }
0363
0364 crypto_unregister_kpp(&atmel_ecdh_nist_p256);
0365
0366 spin_lock(&driver_data.i2c_list_lock);
0367 list_del(&i2c_priv->i2c_client_list_node);
0368 spin_unlock(&driver_data.i2c_list_lock);
0369
0370 return 0;
0371 }
0372
0373 #ifdef CONFIG_OF
0374 static const struct of_device_id atmel_ecc_dt_ids[] = {
0375 {
0376 .compatible = "atmel,atecc508a",
0377 }, {
0378
0379 }
0380 };
0381 MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids);
0382 #endif
0383
0384 static const struct i2c_device_id atmel_ecc_id[] = {
0385 { "atecc508a", 0 },
0386 { }
0387 };
0388 MODULE_DEVICE_TABLE(i2c, atmel_ecc_id);
0389
0390 static struct i2c_driver atmel_ecc_driver = {
0391 .driver = {
0392 .name = "atmel-ecc",
0393 .of_match_table = of_match_ptr(atmel_ecc_dt_ids),
0394 },
0395 .probe = atmel_ecc_probe,
0396 .remove = atmel_ecc_remove,
0397 .id_table = atmel_ecc_id,
0398 };
0399
0400 static int __init atmel_ecc_init(void)
0401 {
0402 spin_lock_init(&driver_data.i2c_list_lock);
0403 INIT_LIST_HEAD(&driver_data.i2c_client_list);
0404 return i2c_add_driver(&atmel_ecc_driver);
0405 }
0406
0407 static void __exit atmel_ecc_exit(void)
0408 {
0409 atmel_i2c_flush_queue();
0410 i2c_del_driver(&atmel_ecc_driver);
0411 }
0412
0413 module_init(atmel_ecc_init);
0414 module_exit(atmel_ecc_exit);
0415
0416 MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>");
0417 MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
0418 MODULE_LICENSE("GPL v2");