Path: blob/master/drivers/crypto/intel/keembay/keembay-ocs-ecc.c
29268 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Intel Keem Bay OCS ECC Crypto Driver.3*4* Copyright (C) 2019-2021 Intel Corporation5*/67#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt89#include <crypto/ecc_curve.h>10#include <crypto/ecdh.h>11#include <crypto/engine.h>12#include <crypto/internal/ecc.h>13#include <crypto/internal/kpp.h>14#include <crypto/kpp.h>15#include <crypto/rng.h>16#include <linux/clk.h>17#include <linux/completion.h>18#include <linux/err.h>19#include <linux/fips.h>20#include <linux/interrupt.h>21#include <linux/io.h>22#include <linux/iopoll.h>23#include <linux/irq.h>24#include <linux/kernel.h>25#include <linux/module.h>26#include <linux/of.h>27#include <linux/platform_device.h>28#include <linux/scatterlist.h>29#include <linux/string.h>3031#define DRV_NAME "keembay-ocs-ecc"3233#define KMB_OCS_ECC_PRIORITY 3503435#define HW_OFFS_OCS_ECC_COMMAND 0x0000000036#define HW_OFFS_OCS_ECC_STATUS 0x0000000437#define HW_OFFS_OCS_ECC_DATA_IN 0x0000008038#define HW_OFFS_OCS_ECC_CX_DATA_OUT 0x0000010039#define HW_OFFS_OCS_ECC_CY_DATA_OUT 0x0000018040#define HW_OFFS_OCS_ECC_ISR 0x0000040041#define HW_OFFS_OCS_ECC_IER 0x000004044243#define HW_OCS_ECC_ISR_INT_STATUS_DONE BIT(0)44#define HW_OCS_ECC_COMMAND_INS_BP BIT(0)4546#define HW_OCS_ECC_COMMAND_START_VAL BIT(0)4748#define OCS_ECC_OP_SIZE_384 BIT(8)49#define OCS_ECC_OP_SIZE_256 05051/* ECC Instruction : for ECC_COMMAND */52#define OCS_ECC_INST_WRITE_AX (0x1 << HW_OCS_ECC_COMMAND_INS_BP)53#define OCS_ECC_INST_WRITE_AY (0x2 << HW_OCS_ECC_COMMAND_INS_BP)54#define OCS_ECC_INST_WRITE_BX_D (0x3 << HW_OCS_ECC_COMMAND_INS_BP)55#define OCS_ECC_INST_WRITE_BY_L (0x4 << HW_OCS_ECC_COMMAND_INS_BP)56#define OCS_ECC_INST_WRITE_P (0x5 << HW_OCS_ECC_COMMAND_INS_BP)57#define OCS_ECC_INST_WRITE_A (0x6 << HW_OCS_ECC_COMMAND_INS_BP)58#define OCS_ECC_INST_CALC_D_IDX_A (0x8 << HW_OCS_ECC_COMMAND_INS_BP)59#define OCS_ECC_INST_CALC_A_POW_B_MODP (0xB << HW_OCS_ECC_COMMAND_INS_BP)60#define OCS_ECC_INST_CALC_A_MUL_B_MODP (0xC << HW_OCS_ECC_COMMAND_INS_BP)61#define OCS_ECC_INST_CALC_A_ADD_B_MODP (0xD << HW_OCS_ECC_COMMAND_INS_BP)6263#define ECC_ENABLE_INTR 16465#define POLL_USEC 10066#define TIMEOUT_USEC 100006768#define KMB_ECC_VLI_MAX_DIGITS ECC_CURVE_NIST_P384_DIGITS69#define KMB_ECC_VLI_MAX_BYTES (KMB_ECC_VLI_MAX_DIGITS \70<< ECC_DIGITS_TO_BYTES_SHIFT)7172#define POW_CUBE 37374/**75* struct ocs_ecc_dev - ECC device context76* @list: List of device contexts77* @dev: OCS ECC device78* @base_reg: IO base address of OCS ECC79* @engine: Crypto engine for the device80* @irq_done: IRQ done completion.81* @irq: IRQ number82*/83struct ocs_ecc_dev {84struct list_head list;85struct device *dev;86void __iomem *base_reg;87struct crypto_engine *engine;88struct completion irq_done;89int irq;90};9192/**93* struct ocs_ecc_ctx - Transformation context.94* @ecc_dev: The ECC driver associated with this context.95* @curve: The elliptic curve used by this transformation.96* @private_key: The private key.97*/98struct ocs_ecc_ctx {99struct ocs_ecc_dev *ecc_dev;100const struct ecc_curve *curve;101u64 private_key[KMB_ECC_VLI_MAX_DIGITS];102};103104/* Driver data. */105struct ocs_ecc_drv {106struct list_head dev_list;107spinlock_t lock; /* Protects dev_list. */108};109110/* Global variable holding the list of OCS ECC devices (only one expected). */111static struct ocs_ecc_drv ocs_ecc = {112.dev_list = LIST_HEAD_INIT(ocs_ecc.dev_list),113.lock = __SPIN_LOCK_UNLOCKED(ocs_ecc.lock),114};115116/* Get OCS ECC tfm context from kpp_request. */117static inline struct ocs_ecc_ctx *kmb_ocs_ecc_tctx(struct kpp_request *req)118{119return kpp_tfm_ctx(crypto_kpp_reqtfm(req));120}121122/* Converts number of digits to number of bytes. */123static inline unsigned int digits_to_bytes(unsigned int n)124{125return n << ECC_DIGITS_TO_BYTES_SHIFT;126}127128/*129* Wait for ECC idle i.e when an operation (other than write operations)130* is done.131*/132static inline int ocs_ecc_wait_idle(struct ocs_ecc_dev *dev)133{134u32 value;135136return readl_poll_timeout((dev->base_reg + HW_OFFS_OCS_ECC_STATUS),137value,138!(value & HW_OCS_ECC_ISR_INT_STATUS_DONE),139POLL_USEC, TIMEOUT_USEC);140}141142static void ocs_ecc_cmd_start(struct ocs_ecc_dev *ecc_dev, u32 op_size)143{144iowrite32(op_size | HW_OCS_ECC_COMMAND_START_VAL,145ecc_dev->base_reg + HW_OFFS_OCS_ECC_COMMAND);146}147148/* Direct write of u32 buffer to ECC engine with associated instruction. */149static void ocs_ecc_write_cmd_and_data(struct ocs_ecc_dev *dev,150u32 op_size,151u32 inst,152const void *data_in,153size_t data_size)154{155iowrite32(op_size | inst, dev->base_reg + HW_OFFS_OCS_ECC_COMMAND);156157/* MMIO Write src uint32 to dst. */158memcpy_toio(dev->base_reg + HW_OFFS_OCS_ECC_DATA_IN, data_in,159data_size);160}161162/* Start OCS ECC operation and wait for its completion. */163static int ocs_ecc_trigger_op(struct ocs_ecc_dev *ecc_dev, u32 op_size,164u32 inst)165{166reinit_completion(&ecc_dev->irq_done);167168iowrite32(ECC_ENABLE_INTR, ecc_dev->base_reg + HW_OFFS_OCS_ECC_IER);169iowrite32(op_size | inst, ecc_dev->base_reg + HW_OFFS_OCS_ECC_COMMAND);170171return wait_for_completion_interruptible(&ecc_dev->irq_done);172}173174/**175* ocs_ecc_read_cx_out() - Read the CX data output buffer.176* @dev: The OCS ECC device to read from.177* @cx_out: The buffer where to store the CX value. Must be at least178* @byte_count byte long.179* @byte_count: The amount of data to read.180*/181static inline void ocs_ecc_read_cx_out(struct ocs_ecc_dev *dev, void *cx_out,182size_t byte_count)183{184memcpy_fromio(cx_out, dev->base_reg + HW_OFFS_OCS_ECC_CX_DATA_OUT,185byte_count);186}187188/**189* ocs_ecc_read_cy_out() - Read the CX data output buffer.190* @dev: The OCS ECC device to read from.191* @cy_out: The buffer where to store the CY value. Must be at least192* @byte_count byte long.193* @byte_count: The amount of data to read.194*/195static inline void ocs_ecc_read_cy_out(struct ocs_ecc_dev *dev, void *cy_out,196size_t byte_count)197{198memcpy_fromio(cy_out, dev->base_reg + HW_OFFS_OCS_ECC_CY_DATA_OUT,199byte_count);200}201202static struct ocs_ecc_dev *kmb_ocs_ecc_find_dev(struct ocs_ecc_ctx *tctx)203{204if (tctx->ecc_dev)205return tctx->ecc_dev;206207spin_lock(&ocs_ecc.lock);208209/* Only a single OCS device available. */210tctx->ecc_dev = list_first_entry(&ocs_ecc.dev_list, struct ocs_ecc_dev,211list);212213spin_unlock(&ocs_ecc.lock);214215return tctx->ecc_dev;216}217218/* Do point multiplication using OCS ECC HW. */219static int kmb_ecc_point_mult(struct ocs_ecc_dev *ecc_dev,220struct ecc_point *result,221const struct ecc_point *point,222u64 *scalar,223const struct ecc_curve *curve)224{225u8 sca[KMB_ECC_VLI_MAX_BYTES]; /* Use the maximum data size. */226u32 op_size = (curve->g.ndigits > ECC_CURVE_NIST_P256_DIGITS) ?227OCS_ECC_OP_SIZE_384 : OCS_ECC_OP_SIZE_256;228size_t nbytes = digits_to_bytes(curve->g.ndigits);229int rc = 0;230231/* Generate random nbytes for Simple and Differential SCA protection. */232rc = crypto_get_default_rng();233if (rc)234return rc;235236rc = crypto_rng_get_bytes(crypto_default_rng, sca, nbytes);237crypto_put_default_rng();238if (rc)239return rc;240241/* Wait engine to be idle before starting new operation. */242rc = ocs_ecc_wait_idle(ecc_dev);243if (rc)244return rc;245246/* Send ecc_start pulse as well as indicating operation size. */247ocs_ecc_cmd_start(ecc_dev, op_size);248249/* Write ax param; Base point (Gx). */250ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AX,251point->x, nbytes);252253/* Write ay param; Base point (Gy). */254ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AY,255point->y, nbytes);256257/*258* Write the private key into DATA_IN reg.259*260* Since DATA_IN register is used to write different values during the261* computation private Key value is overwritten with262* side-channel-resistance value.263*/264ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_BX_D,265scalar, nbytes);266267/* Write operand by/l. */268ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_BY_L,269sca, nbytes);270memzero_explicit(sca, sizeof(sca));271272/* Write p = curve prime(GF modulus). */273ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_P,274curve->p, nbytes);275276/* Write a = curve coefficient. */277ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_A,278curve->a, nbytes);279280/* Make hardware perform the multiplication. */281rc = ocs_ecc_trigger_op(ecc_dev, op_size, OCS_ECC_INST_CALC_D_IDX_A);282if (rc)283return rc;284285/* Read result. */286ocs_ecc_read_cx_out(ecc_dev, result->x, nbytes);287ocs_ecc_read_cy_out(ecc_dev, result->y, nbytes);288289return 0;290}291292/**293* kmb_ecc_do_scalar_op() - Perform Scalar operation using OCS ECC HW.294* @ecc_dev: The OCS ECC device to use.295* @scalar_out: Where to store the output scalar.296* @scalar_a: Input scalar operand 'a'.297* @scalar_b: Input scalar operand 'b'298* @curve: The curve on which the operation is performed.299* @ndigits: The size of the operands (in digits).300* @inst: The operation to perform (as an OCS ECC instruction).301*302* Return: 0 on success, negative error code otherwise.303*/304static int kmb_ecc_do_scalar_op(struct ocs_ecc_dev *ecc_dev, u64 *scalar_out,305const u64 *scalar_a, const u64 *scalar_b,306const struct ecc_curve *curve,307unsigned int ndigits, const u32 inst)308{309u32 op_size = (ndigits > ECC_CURVE_NIST_P256_DIGITS) ?310OCS_ECC_OP_SIZE_384 : OCS_ECC_OP_SIZE_256;311size_t nbytes = digits_to_bytes(ndigits);312int rc;313314/* Wait engine to be idle before starting new operation. */315rc = ocs_ecc_wait_idle(ecc_dev);316if (rc)317return rc;318319/* Send ecc_start pulse as well as indicating operation size. */320ocs_ecc_cmd_start(ecc_dev, op_size);321322/* Write ax param (Base point (Gx).*/323ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AX,324scalar_a, nbytes);325326/* Write ay param Base point (Gy).*/327ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_AY,328scalar_b, nbytes);329330/* Write p = curve prime(GF modulus).*/331ocs_ecc_write_cmd_and_data(ecc_dev, op_size, OCS_ECC_INST_WRITE_P,332curve->p, nbytes);333334/* Give instruction A.B or A+B to ECC engine. */335rc = ocs_ecc_trigger_op(ecc_dev, op_size, inst);336if (rc)337return rc;338339ocs_ecc_read_cx_out(ecc_dev, scalar_out, nbytes);340341if (vli_is_zero(scalar_out, ndigits))342return -EINVAL;343344return 0;345}346347/* SP800-56A section 5.6.2.3.4 partial verification: ephemeral keys only */348static int kmb_ocs_ecc_is_pubkey_valid_partial(struct ocs_ecc_dev *ecc_dev,349const struct ecc_curve *curve,350struct ecc_point *pk)351{352u64 xxx[KMB_ECC_VLI_MAX_DIGITS] = { 0 };353u64 yy[KMB_ECC_VLI_MAX_DIGITS] = { 0 };354u64 w[KMB_ECC_VLI_MAX_DIGITS] = { 0 };355int rc;356357if (WARN_ON(pk->ndigits != curve->g.ndigits))358return -EINVAL;359360/* Check 1: Verify key is not the zero point. */361if (ecc_point_is_zero(pk))362return -EINVAL;363364/* Check 2: Verify key is in the range [0, p-1]. */365if (vli_cmp(curve->p, pk->x, pk->ndigits) != 1)366return -EINVAL;367368if (vli_cmp(curve->p, pk->y, pk->ndigits) != 1)369return -EINVAL;370371/* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p */372373/* y^2 */374/* Compute y^2 -> store in yy */375rc = kmb_ecc_do_scalar_op(ecc_dev, yy, pk->y, pk->y, curve, pk->ndigits,376OCS_ECC_INST_CALC_A_MUL_B_MODP);377if (rc)378goto exit;379380/* x^3 */381/* Assigning w = 3, used for calculating x^3. */382w[0] = POW_CUBE;383/* Load the next stage.*/384rc = kmb_ecc_do_scalar_op(ecc_dev, xxx, pk->x, w, curve, pk->ndigits,385OCS_ECC_INST_CALC_A_POW_B_MODP);386if (rc)387goto exit;388389/* Do a*x -> store in w. */390rc = kmb_ecc_do_scalar_op(ecc_dev, w, curve->a, pk->x, curve,391pk->ndigits,392OCS_ECC_INST_CALC_A_MUL_B_MODP);393if (rc)394goto exit;395396/* Do ax + b == w + b; store in w. */397rc = kmb_ecc_do_scalar_op(ecc_dev, w, w, curve->b, curve,398pk->ndigits,399OCS_ECC_INST_CALC_A_ADD_B_MODP);400if (rc)401goto exit;402403/* x^3 + ax + b == x^3 + w -> store in w. */404rc = kmb_ecc_do_scalar_op(ecc_dev, w, xxx, w, curve, pk->ndigits,405OCS_ECC_INST_CALC_A_ADD_B_MODP);406if (rc)407goto exit;408409/* Compare y^2 == x^3 + a·x + b. */410rc = vli_cmp(yy, w, pk->ndigits);411if (rc)412rc = -EINVAL;413414exit:415memzero_explicit(xxx, sizeof(xxx));416memzero_explicit(yy, sizeof(yy));417memzero_explicit(w, sizeof(w));418419return rc;420}421422/* SP800-56A section 5.6.2.3.3 full verification */423static int kmb_ocs_ecc_is_pubkey_valid_full(struct ocs_ecc_dev *ecc_dev,424const struct ecc_curve *curve,425struct ecc_point *pk)426{427struct ecc_point *nQ;428int rc;429430/* Checks 1 through 3 */431rc = kmb_ocs_ecc_is_pubkey_valid_partial(ecc_dev, curve, pk);432if (rc)433return rc;434435/* Check 4: Verify that nQ is the zero point. */436nQ = ecc_alloc_point(pk->ndigits);437if (!nQ)438return -ENOMEM;439440rc = kmb_ecc_point_mult(ecc_dev, nQ, pk, curve->n, curve);441if (rc)442goto exit;443444if (!ecc_point_is_zero(nQ))445rc = -EINVAL;446447exit:448ecc_free_point(nQ);449450return rc;451}452453static int kmb_ecc_is_key_valid(const struct ecc_curve *curve,454const u64 *private_key, size_t private_key_len)455{456size_t ndigits = curve->g.ndigits;457u64 one[KMB_ECC_VLI_MAX_DIGITS] = {1};458u64 res[KMB_ECC_VLI_MAX_DIGITS];459460if (private_key_len != digits_to_bytes(ndigits))461return -EINVAL;462463if (!private_key)464return -EINVAL;465466/* Make sure the private key is in the range [2, n-3]. */467if (vli_cmp(one, private_key, ndigits) != -1)468return -EINVAL;469470vli_sub(res, curve->n, one, ndigits);471vli_sub(res, res, one, ndigits);472if (vli_cmp(res, private_key, ndigits) != 1)473return -EINVAL;474475return 0;476}477478/*479* ECC private keys are generated using the method of extra random bits,480* equivalent to that described in FIPS 186-4, Appendix B.4.1.481*482* d = (c mod(n–1)) + 1 where c is a string of random bits, 64 bits longer483* than requested484* 0 <= c mod(n-1) <= n-2 and implies that485* 1 <= d <= n-1486*487* This method generates a private key uniformly distributed in the range488* [1, n-1].489*/490static int kmb_ecc_gen_privkey(const struct ecc_curve *curve, u64 *privkey)491{492size_t nbytes = digits_to_bytes(curve->g.ndigits);493u64 priv[KMB_ECC_VLI_MAX_DIGITS];494size_t nbits;495int rc;496497nbits = vli_num_bits(curve->n, curve->g.ndigits);498499/* Check that N is included in Table 1 of FIPS 186-4, section 6.1.1 */500if (nbits < 160 || curve->g.ndigits > ARRAY_SIZE(priv))501return -EINVAL;502503/*504* FIPS 186-4 recommends that the private key should be obtained from a505* RBG with a security strength equal to or greater than the security506* strength associated with N.507*508* The maximum security strength identified by NIST SP800-57pt1r4 for509* ECC is 256 (N >= 512).510*511* This condition is met by the default RNG because it selects a favored512* DRBG with a security strength of 256.513*/514if (crypto_get_default_rng())515return -EFAULT;516517rc = crypto_rng_get_bytes(crypto_default_rng, (u8 *)priv, nbytes);518crypto_put_default_rng();519if (rc)520goto cleanup;521522rc = kmb_ecc_is_key_valid(curve, priv, nbytes);523if (rc)524goto cleanup;525526ecc_swap_digits(priv, privkey, curve->g.ndigits);527528cleanup:529memzero_explicit(&priv, sizeof(priv));530531return rc;532}533534static int kmb_ocs_ecdh_set_secret(struct crypto_kpp *tfm, const void *buf,535unsigned int len)536{537struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);538struct ecdh params;539int rc = 0;540541rc = crypto_ecdh_decode_key(buf, len, ¶ms);542if (rc)543goto cleanup;544545/* Ensure key size is not bigger then expected. */546if (params.key_size > digits_to_bytes(tctx->curve->g.ndigits)) {547rc = -EINVAL;548goto cleanup;549}550551/* Auto-generate private key is not provided. */552if (!params.key || !params.key_size) {553rc = kmb_ecc_gen_privkey(tctx->curve, tctx->private_key);554goto cleanup;555}556557rc = kmb_ecc_is_key_valid(tctx->curve, (const u64 *)params.key,558params.key_size);559if (rc)560goto cleanup;561562ecc_swap_digits((const u64 *)params.key, tctx->private_key,563tctx->curve->g.ndigits);564cleanup:565memzero_explicit(¶ms, sizeof(params));566567if (rc)568tctx->curve = NULL;569570return rc;571}572573/* Compute shared secret. */574static int kmb_ecc_do_shared_secret(struct ocs_ecc_ctx *tctx,575struct kpp_request *req)576{577struct ocs_ecc_dev *ecc_dev = tctx->ecc_dev;578const struct ecc_curve *curve = tctx->curve;579u64 shared_secret[KMB_ECC_VLI_MAX_DIGITS];580u64 pubk_buf[KMB_ECC_VLI_MAX_DIGITS * 2];581size_t copied, nbytes, pubk_len;582struct ecc_point *pk, *result;583int rc;584585nbytes = digits_to_bytes(curve->g.ndigits);586587/* Public key is a point, thus it has two coordinates */588pubk_len = 2 * nbytes;589590/* Copy public key from SG list to pubk_buf. */591copied = sg_copy_to_buffer(req->src,592sg_nents_for_len(req->src, pubk_len),593pubk_buf, pubk_len);594if (copied != pubk_len)595return -EINVAL;596597/* Allocate and initialize public key point. */598pk = ecc_alloc_point(curve->g.ndigits);599if (!pk)600return -ENOMEM;601602ecc_swap_digits(pubk_buf, pk->x, curve->g.ndigits);603ecc_swap_digits(&pubk_buf[curve->g.ndigits], pk->y, curve->g.ndigits);604605/*606* Check the public key for following607* Check 1: Verify key is not the zero point.608* Check 2: Verify key is in the range [1, p-1].609* Check 3: Verify that y^2 == (x^3 + a·x + b) mod p610*/611rc = kmb_ocs_ecc_is_pubkey_valid_partial(ecc_dev, curve, pk);612if (rc)613goto exit_free_pk;614615/* Allocate point for storing computed shared secret. */616result = ecc_alloc_point(pk->ndigits);617if (!result) {618rc = -ENOMEM;619goto exit_free_pk;620}621622/* Calculate the shared secret.*/623rc = kmb_ecc_point_mult(ecc_dev, result, pk, tctx->private_key, curve);624if (rc)625goto exit_free_result;626627if (ecc_point_is_zero(result)) {628rc = -EFAULT;629goto exit_free_result;630}631632/* Copy shared secret from point to buffer. */633ecc_swap_digits(result->x, shared_secret, result->ndigits);634635/* Request might ask for less bytes than what we have. */636nbytes = min_t(size_t, nbytes, req->dst_len);637638copied = sg_copy_from_buffer(req->dst,639sg_nents_for_len(req->dst, nbytes),640shared_secret, nbytes);641642if (copied != nbytes)643rc = -EINVAL;644645memzero_explicit(shared_secret, sizeof(shared_secret));646647exit_free_result:648ecc_free_point(result);649650exit_free_pk:651ecc_free_point(pk);652653return rc;654}655656/* Compute public key. */657static int kmb_ecc_do_public_key(struct ocs_ecc_ctx *tctx,658struct kpp_request *req)659{660const struct ecc_curve *curve = tctx->curve;661u64 pubk_buf[KMB_ECC_VLI_MAX_DIGITS * 2];662struct ecc_point *pk;663size_t pubk_len;664size_t copied;665int rc;666667/* Public key is a point, so it has double the digits. */668pubk_len = 2 * digits_to_bytes(curve->g.ndigits);669670pk = ecc_alloc_point(curve->g.ndigits);671if (!pk)672return -ENOMEM;673674/* Public Key(pk) = priv * G. */675rc = kmb_ecc_point_mult(tctx->ecc_dev, pk, &curve->g, tctx->private_key,676curve);677if (rc)678goto exit;679680/* SP800-56A rev 3 5.6.2.1.3 key check */681if (kmb_ocs_ecc_is_pubkey_valid_full(tctx->ecc_dev, curve, pk)) {682rc = -EAGAIN;683goto exit;684}685686/* Copy public key from point to buffer. */687ecc_swap_digits(pk->x, pubk_buf, pk->ndigits);688ecc_swap_digits(pk->y, &pubk_buf[pk->ndigits], pk->ndigits);689690/* Copy public key to req->dst. */691copied = sg_copy_from_buffer(req->dst,692sg_nents_for_len(req->dst, pubk_len),693pubk_buf, pubk_len);694695if (copied != pubk_len)696rc = -EINVAL;697698exit:699ecc_free_point(pk);700701return rc;702}703704static int kmb_ocs_ecc_do_one_request(struct crypto_engine *engine,705void *areq)706{707struct kpp_request *req = container_of(areq, struct kpp_request, base);708struct ocs_ecc_ctx *tctx = kmb_ocs_ecc_tctx(req);709struct ocs_ecc_dev *ecc_dev = tctx->ecc_dev;710int rc;711712if (req->src)713rc = kmb_ecc_do_shared_secret(tctx, req);714else715rc = kmb_ecc_do_public_key(tctx, req);716717crypto_finalize_kpp_request(ecc_dev->engine, req, rc);718719return 0;720}721722static int kmb_ocs_ecdh_generate_public_key(struct kpp_request *req)723{724struct ocs_ecc_ctx *tctx = kmb_ocs_ecc_tctx(req);725const struct ecc_curve *curve = tctx->curve;726727/* Ensure kmb_ocs_ecdh_set_secret() has been successfully called. */728if (!tctx->curve)729return -EINVAL;730731/* Ensure dst is present. */732if (!req->dst)733return -EINVAL;734735/* Check the request dst is big enough to hold the public key. */736if (req->dst_len < (2 * digits_to_bytes(curve->g.ndigits)))737return -EINVAL;738739/* 'src' is not supposed to be present when generate pubk is called. */740if (req->src)741return -EINVAL;742743return crypto_transfer_kpp_request_to_engine(tctx->ecc_dev->engine,744req);745}746747static int kmb_ocs_ecdh_compute_shared_secret(struct kpp_request *req)748{749struct ocs_ecc_ctx *tctx = kmb_ocs_ecc_tctx(req);750const struct ecc_curve *curve = tctx->curve;751752/* Ensure kmb_ocs_ecdh_set_secret() has been successfully called. */753if (!tctx->curve)754return -EINVAL;755756/* Ensure dst is present. */757if (!req->dst)758return -EINVAL;759760/* Ensure src is present. */761if (!req->src)762return -EINVAL;763764/*765* req->src is expected to the (other-side) public key, so its length766* must be 2 * coordinate size (in bytes).767*/768if (req->src_len != 2 * digits_to_bytes(curve->g.ndigits))769return -EINVAL;770771return crypto_transfer_kpp_request_to_engine(tctx->ecc_dev->engine,772req);773}774775static int kmb_ecc_tctx_init(struct ocs_ecc_ctx *tctx, unsigned int curve_id)776{777memset(tctx, 0, sizeof(*tctx));778779tctx->ecc_dev = kmb_ocs_ecc_find_dev(tctx);780781if (IS_ERR(tctx->ecc_dev)) {782pr_err("Failed to find the device : %ld\n",783PTR_ERR(tctx->ecc_dev));784return PTR_ERR(tctx->ecc_dev);785}786787tctx->curve = ecc_get_curve(curve_id);788if (!tctx->curve)789return -EOPNOTSUPP;790791return 0;792}793794static int kmb_ocs_ecdh_nist_p256_init_tfm(struct crypto_kpp *tfm)795{796struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);797798return kmb_ecc_tctx_init(tctx, ECC_CURVE_NIST_P256);799}800801static int kmb_ocs_ecdh_nist_p384_init_tfm(struct crypto_kpp *tfm)802{803struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);804805return kmb_ecc_tctx_init(tctx, ECC_CURVE_NIST_P384);806}807808static void kmb_ocs_ecdh_exit_tfm(struct crypto_kpp *tfm)809{810struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);811812memzero_explicit(tctx->private_key, sizeof(*tctx->private_key));813}814815static unsigned int kmb_ocs_ecdh_max_size(struct crypto_kpp *tfm)816{817struct ocs_ecc_ctx *tctx = kpp_tfm_ctx(tfm);818819/* Public key is made of two coordinates, so double the digits. */820return digits_to_bytes(tctx->curve->g.ndigits) * 2;821}822823static struct kpp_engine_alg ocs_ecdh_p256 = {824.base.set_secret = kmb_ocs_ecdh_set_secret,825.base.generate_public_key = kmb_ocs_ecdh_generate_public_key,826.base.compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,827.base.init = kmb_ocs_ecdh_nist_p256_init_tfm,828.base.exit = kmb_ocs_ecdh_exit_tfm,829.base.max_size = kmb_ocs_ecdh_max_size,830.base.base = {831.cra_name = "ecdh-nist-p256",832.cra_driver_name = "ecdh-nist-p256-keembay-ocs",833.cra_priority = KMB_OCS_ECC_PRIORITY,834.cra_module = THIS_MODULE,835.cra_ctxsize = sizeof(struct ocs_ecc_ctx),836},837.op.do_one_request = kmb_ocs_ecc_do_one_request,838};839840static struct kpp_engine_alg ocs_ecdh_p384 = {841.base.set_secret = kmb_ocs_ecdh_set_secret,842.base.generate_public_key = kmb_ocs_ecdh_generate_public_key,843.base.compute_shared_secret = kmb_ocs_ecdh_compute_shared_secret,844.base.init = kmb_ocs_ecdh_nist_p384_init_tfm,845.base.exit = kmb_ocs_ecdh_exit_tfm,846.base.max_size = kmb_ocs_ecdh_max_size,847.base.base = {848.cra_name = "ecdh-nist-p384",849.cra_driver_name = "ecdh-nist-p384-keembay-ocs",850.cra_priority = KMB_OCS_ECC_PRIORITY,851.cra_module = THIS_MODULE,852.cra_ctxsize = sizeof(struct ocs_ecc_ctx),853},854.op.do_one_request = kmb_ocs_ecc_do_one_request,855};856857static irqreturn_t ocs_ecc_irq_handler(int irq, void *dev_id)858{859struct ocs_ecc_dev *ecc_dev = dev_id;860u32 status;861862/*863* Read the status register and write it back to clear the864* DONE_INT_STATUS bit.865*/866status = ioread32(ecc_dev->base_reg + HW_OFFS_OCS_ECC_ISR);867iowrite32(status, ecc_dev->base_reg + HW_OFFS_OCS_ECC_ISR);868869if (!(status & HW_OCS_ECC_ISR_INT_STATUS_DONE))870return IRQ_NONE;871872complete(&ecc_dev->irq_done);873874return IRQ_HANDLED;875}876877static int kmb_ocs_ecc_probe(struct platform_device *pdev)878{879struct device *dev = &pdev->dev;880struct ocs_ecc_dev *ecc_dev;881int rc;882883ecc_dev = devm_kzalloc(dev, sizeof(*ecc_dev), GFP_KERNEL);884if (!ecc_dev)885return -ENOMEM;886887ecc_dev->dev = dev;888889platform_set_drvdata(pdev, ecc_dev);890891INIT_LIST_HEAD(&ecc_dev->list);892init_completion(&ecc_dev->irq_done);893894/* Get base register address. */895ecc_dev->base_reg = devm_platform_ioremap_resource(pdev, 0);896if (IS_ERR(ecc_dev->base_reg)) {897dev_err(dev, "Failed to get base address\n");898rc = PTR_ERR(ecc_dev->base_reg);899goto list_del;900}901902/* Get and request IRQ */903ecc_dev->irq = platform_get_irq(pdev, 0);904if (ecc_dev->irq < 0) {905rc = ecc_dev->irq;906goto list_del;907}908909rc = devm_request_threaded_irq(dev, ecc_dev->irq, ocs_ecc_irq_handler,910NULL, 0, "keembay-ocs-ecc", ecc_dev);911if (rc < 0) {912dev_err(dev, "Could not request IRQ\n");913goto list_del;914}915916/* Add device to the list of OCS ECC devices. */917spin_lock(&ocs_ecc.lock);918list_add_tail(&ecc_dev->list, &ocs_ecc.dev_list);919spin_unlock(&ocs_ecc.lock);920921/* Initialize crypto engine. */922ecc_dev->engine = crypto_engine_alloc_init(dev, 1);923if (!ecc_dev->engine) {924dev_err(dev, "Could not allocate crypto engine\n");925rc = -ENOMEM;926goto list_del;927}928929rc = crypto_engine_start(ecc_dev->engine);930if (rc) {931dev_err(dev, "Could not start crypto engine\n");932goto cleanup;933}934935/* Register the KPP algo. */936rc = crypto_engine_register_kpp(&ocs_ecdh_p256);937if (rc) {938dev_err(dev,939"Could not register OCS algorithms with Crypto API\n");940goto cleanup;941}942943rc = crypto_engine_register_kpp(&ocs_ecdh_p384);944if (rc) {945dev_err(dev,946"Could not register OCS algorithms with Crypto API\n");947goto ocs_ecdh_p384_error;948}949950return 0;951952ocs_ecdh_p384_error:953crypto_engine_unregister_kpp(&ocs_ecdh_p256);954955cleanup:956crypto_engine_exit(ecc_dev->engine);957958list_del:959spin_lock(&ocs_ecc.lock);960list_del(&ecc_dev->list);961spin_unlock(&ocs_ecc.lock);962963return rc;964}965966static void kmb_ocs_ecc_remove(struct platform_device *pdev)967{968struct ocs_ecc_dev *ecc_dev;969970ecc_dev = platform_get_drvdata(pdev);971972crypto_engine_unregister_kpp(&ocs_ecdh_p384);973crypto_engine_unregister_kpp(&ocs_ecdh_p256);974975spin_lock(&ocs_ecc.lock);976list_del(&ecc_dev->list);977spin_unlock(&ocs_ecc.lock);978979crypto_engine_exit(ecc_dev->engine);980}981982/* Device tree driver match. */983static const struct of_device_id kmb_ocs_ecc_of_match[] = {984{985.compatible = "intel,keembay-ocs-ecc",986},987{}988};989990/* The OCS driver is a platform device. */991static struct platform_driver kmb_ocs_ecc_driver = {992.probe = kmb_ocs_ecc_probe,993.remove = kmb_ocs_ecc_remove,994.driver = {995.name = DRV_NAME,996.of_match_table = kmb_ocs_ecc_of_match,997},998};999module_platform_driver(kmb_ocs_ecc_driver);10001001MODULE_LICENSE("GPL");1002MODULE_DESCRIPTION("Intel Keem Bay OCS ECC Driver");1003MODULE_ALIAS_CRYPTO("ecdh-nist-p256");1004MODULE_ALIAS_CRYPTO("ecdh-nist-p384");1005MODULE_ALIAS_CRYPTO("ecdh-nist-p256-keembay-ocs");1006MODULE_ALIAS_CRYPTO("ecdh-nist-p384-keembay-ocs");100710081009