cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

atmel-ecc.c (10337B)


      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 <tudor.ambarus@microchip.com>
      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_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>
     24#include "atmel-i2c.h"
     25
     26static 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 */
     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 device
     75 * 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, &params) < 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 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(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 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
    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			   const struct i2c_device_id *id)
    316{
    317	struct atmel_i2c_client_priv *i2c_priv;
    318	int ret;
    319
    320	ret = atmel_i2c_probe(client, id);
    321	if (ret)
    322		return ret;
    323
    324	i2c_priv = i2c_get_clientdata(client);
    325
    326	spin_lock(&driver_data.i2c_list_lock);
    327	list_add_tail(&i2c_priv->i2c_client_list_node,
    328		      &driver_data.i2c_client_list);
    329	spin_unlock(&driver_data.i2c_list_lock);
    330
    331	ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
    332	if (ret) {
    333		spin_lock(&driver_data.i2c_list_lock);
    334		list_del(&i2c_priv->i2c_client_list_node);
    335		spin_unlock(&driver_data.i2c_list_lock);
    336
    337		dev_err(&client->dev, "%s alg registration failed\n",
    338			atmel_ecdh_nist_p256.base.cra_driver_name);
    339	} else {
    340		dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
    341	}
    342
    343	return ret;
    344}
    345
    346static int atmel_ecc_remove(struct i2c_client *client)
    347{
    348	struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
    349
    350	/* Return EBUSY if i2c client already allocated. */
    351	if (atomic_read(&i2c_priv->tfm_count)) {
    352		dev_err(&client->dev, "Device is busy\n");
    353		return -EBUSY;
    354	}
    355
    356	crypto_unregister_kpp(&atmel_ecdh_nist_p256);
    357
    358	spin_lock(&driver_data.i2c_list_lock);
    359	list_del(&i2c_priv->i2c_client_list_node);
    360	spin_unlock(&driver_data.i2c_list_lock);
    361
    362	return 0;
    363}
    364
    365#ifdef CONFIG_OF
    366static const struct of_device_id atmel_ecc_dt_ids[] = {
    367	{
    368		.compatible = "atmel,atecc508a",
    369	}, {
    370		/* sentinel */
    371	}
    372};
    373MODULE_DEVICE_TABLE(of, atmel_ecc_dt_ids);
    374#endif
    375
    376static const struct i2c_device_id atmel_ecc_id[] = {
    377	{ "atecc508a", 0 },
    378	{ }
    379};
    380MODULE_DEVICE_TABLE(i2c, atmel_ecc_id);
    381
    382static struct i2c_driver atmel_ecc_driver = {
    383	.driver = {
    384		.name	= "atmel-ecc",
    385		.of_match_table = of_match_ptr(atmel_ecc_dt_ids),
    386	},
    387	.probe		= atmel_ecc_probe,
    388	.remove		= atmel_ecc_remove,
    389	.id_table	= atmel_ecc_id,
    390};
    391
    392static int __init atmel_ecc_init(void)
    393{
    394	spin_lock_init(&driver_data.i2c_list_lock);
    395	INIT_LIST_HEAD(&driver_data.i2c_client_list);
    396	return i2c_add_driver(&atmel_ecc_driver);
    397}
    398
    399static void __exit atmel_ecc_exit(void)
    400{
    401	atmel_i2c_flush_queue();
    402	i2c_del_driver(&atmel_ecc_driver);
    403}
    404
    405module_init(atmel_ecc_init);
    406module_exit(atmel_ecc_exit);
    407
    408MODULE_AUTHOR("Tudor Ambarus <tudor.ambarus@microchip.com>");
    409MODULE_DESCRIPTION("Microchip / Atmel ECC (I2C) driver");
    410MODULE_LICENSE("GPL v2");