From: Alex Ousherovitch <[email protected]>

Register ECDSA and SM2 sig algorithms using the CMH PKE core.
Supports P-256, P-384, P-521, and SM2 curves for sign and verify
operations.  SM2 is registered as verify-only via the crypto API;
full SM2 operations (encrypt, decrypt, key exchange) are available
through the /dev/cmh_mgmt ioctl interface.

Co-developed-by: Saravanakrishnan Krishnamoorthy <[email protected]>
Signed-off-by: Saravanakrishnan Krishnamoorthy <[email protected]>
Signed-off-by: Alex Ousherovitch <[email protected]>
Reviewed-by: Joel Wittenauer <[email protected]>
Reviewed-by: Thi Nguyen <[email protected]>
---
 drivers/crypto/cmh/Makefile        |   3 +-
 drivers/crypto/cmh/cmh_main.c      |   8 +
 drivers/crypto/cmh/cmh_pke_ecdsa.c | 575 +++++++++++++++++++++++++++++
 3 files changed, 585 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/cmh/cmh_pke_ecdsa.c

diff --git a/drivers/crypto/cmh/Makefile b/drivers/crypto/cmh/Makefile
index 7afd9852c337..fdbf66b13628 100644
--- a/drivers/crypto/cmh/Makefile
+++ b/drivers/crypto/cmh/Makefile
@@ -31,7 +31,8 @@ cmh-y := \
        cmh_ccp_poly.o \
        cmh_rng.o \
        cmh_pke_common.o \
-       cmh_pke_rsa.o
+       cmh_pke_rsa.o \
+       cmh_pke_ecdsa.o
 
 # Management ioctl device (/dev/cmh_mgmt): key lifecycle, PKE, PQC ioctls.
 cmh-$(CONFIG_CRYPTO_DEV_CMH_MGMT) += \
diff --git a/drivers/crypto/cmh/cmh_main.c b/drivers/crypto/cmh/cmh_main.c
index 07f26b0dd2ef..2191682f3d54 100644
--- a/drivers/crypto/cmh/cmh_main.c
+++ b/drivers/crypto/cmh/cmh_main.c
@@ -287,6 +287,11 @@ static int cmh_probe(struct platform_device *pdev)
        if (ret)
                goto err_pke_rsa_register;
 
+       /* Register PKE ECDSA/SM2 sig */
+       ret = cmh_pke_ecdsa_register();
+       if (ret)
+               goto err_pke_ecdsa_register;
+
        /* Register key management device (/dev/cmh_mgmt) */
        ret = cmh_mgmt_register();
        if (ret)
@@ -299,6 +304,8 @@ static int cmh_probe(struct platform_device *pdev)
        return 0;
 
 err_mgmt_register:
+       cmh_pke_ecdsa_unregister();
+err_pke_ecdsa_register:
        cmh_pke_rsa_unregister();
 err_pke_rsa_register:
        cmh_ccp_poly_unregister();
@@ -357,6 +364,7 @@ static void cmh_remove(struct platform_device *pdev)
        cfg = &dev->config;
 
        cmh_mgmt_unregister();
+       cmh_pke_ecdsa_unregister();
        cmh_pke_rsa_unregister();
        cmh_ccp_poly_unregister();
        cmh_ccp_aead_unregister();
diff --git a/drivers/crypto/cmh/cmh_pke_ecdsa.c 
b/drivers/crypto/cmh/cmh_pke_ecdsa.c
new file mode 100644
index 000000000000..6b65f7fb72cc
--- /dev/null
+++ b/drivers/crypto/cmh/cmh_pke_ecdsa.c
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2026 Cryptography Research, Inc. (CRI).
+ * CMH LKM -- ECDSA / SM2 Signature Driver (sig_alg, synchronous)
+ *
+ * Registers "ecdsa-nist-p256", "ecdsa-nist-p384", and "ecdsa-nist-p521"
+ * sig algorithms with sign, verify, set_pub_key, and set_priv_key callbacks.
+ * Registers "sm2" as verify-only (set_pub_key + verify); SM2 sign is
+ * provided via the cmh_mgmt ioctl path in cmh_pke_sm2.c.
+ *
+ * In-kernel consumers typically use verify-only (module signatures, IMA),
+ * but we provide sign as well for completeness -- matching the CMH eSW
+ * capability.
+ *
+ * Key format: Public key = raw 04 || X || Y (uncompressed).
+ * Signature format: struct ecdsa_raw_sig (two u64[ECC_MAX_DIGITS] arrays
+ * in VLI format -- native byte order, LE digit order) for both sign
+ * output and verify input.  This matches the kernel crypto sig API.
+ *
+ * Private key via cmh_key_ctx: raw keys written via SYS_REF_TEMP.
+ * Datastore-referenced keys are only reachable through the ioctl
+ * path (cmh_mgmt.c).
+ *
+ * SM2 note: The SM2 sig entry is verify-only (no sign/set_priv_key).
+ * SM2 signature verification requires the digest to be SM3(ZA || M)
+ * where ZA = SM3(ENTLA || IDA || a || b || xG || yG || xA || yA).
+ * The ZA identity pre-hash is the caller's responsibility; the driver
+ * passes the digest directly to the CMH eSW SM2 verify engine.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <crypto/sha2.h>
+#include <crypto/sig.h>
+#include <crypto/internal/sig.h>
+#include <crypto/internal/ecc.h>
+
+#include "cmh_pke.h"
+#include "cmh_sys.h"
+#include "cmh_sys_abi.h"
+#include "cmh_txn.h"
+#include "cmh_dma.h"
+#include "cmh_key.h"
+
+/*
+ * Number of ECC digits needed for a given coordinate byte length.
+ * P-256: 4, P-384: 6, P-521/SM2(clen=68): 9.
+ */
+static inline unsigned int clen_to_ndigits(u32 clen)
+{
+       return DIV_ROUND_UP(clen, sizeof(u64));
+}
+
+struct cmh_ecdsa_tfm_ctx {
+       struct cmh_key_ctx key;         /* private key (raw only) */
+       u8 *pub_key;                    /* uncompressed (x, y) without 04 
prefix */
+       u32 pub_key_len;
+       u32 curve;                      /* PKE_CURVE_* */
+       u32 clen;                       /* coordinate length in bytes */
+};
+
+static inline struct cmh_ecdsa_tfm_ctx *cmh_ecdsa_ctx(struct crypto_sig *tfm)
+{
+       return crypto_sig_ctx(tfm);
+}
+
+/*
+ * Convert one VLI component (u64 array, LE digit order, native byte order)
+ * to big-endian byte array of @out_len bytes.  The VLI value is right-aligned
+ * in the output (leading zero bytes if ndigits*8 > out_len are discarded;
+ * leading zero padding added if ndigits*8 < out_len).
+ */
+static void ecdsa_vli_to_be(const u64 *vli, unsigned int ndigits,
+                           u8 *out, unsigned int out_len)
+{
+       unsigned int full_len = ndigits * sizeof(u64);
+       unsigned int i, skip;
+
+       memset(out, 0, out_len);
+
+       if (full_len <= out_len) {
+               /* VLI fits entirely -- write at right end of out */
+               u8 *dst = out + (out_len - full_len);
+
+               for (i = 0; i < ndigits; i++)
+                       put_unaligned_be64(vli[ndigits - 1 - i],
+                                          &dst[i * sizeof(u64)]);
+       } else {
+               /* VLI wider than out -- skip leading (zero) bytes */
+               u8 tmp[ECC_MAX_BYTES];
+
+               for (i = 0; i < ndigits; i++)
+                       put_unaligned_be64(vli[ndigits - 1 - i],
+                                          &tmp[i * sizeof(u64)]);
+               skip = full_len - out_len;
+               WARN_ON_ONCE(memchr_inv(tmp, 0, skip));
+               memcpy(out, tmp + skip, out_len);
+       }
+}
+
+/*
+ * Convert big-endian byte array to VLI (u64 array, LE digit order).
+ * Output is zero-filled to @max_digits entries.
+ */
+static void ecdsa_be_to_vli(const u8 *in, unsigned int in_len,
+                           u64 *vli, unsigned int max_digits)
+{
+       unsigned int full_len = max_digits * sizeof(u64);
+       u8 tmp[ECC_MAX_BYTES];
+       unsigned int i;
+
+       if (WARN_ON_ONCE(max_digits > ECC_MAX_DIGITS))
+               max_digits = ECC_MAX_DIGITS;
+
+       memset(tmp, 0, full_len);
+       if (in_len <= full_len)
+               memcpy(tmp + (full_len - in_len), in, in_len);
+       else
+               memcpy(tmp, in + (in_len - full_len), full_len);
+
+       for (i = 0; i < max_digits; i++) {
+               unsigned int off = (max_digits - 1 - i) * sizeof(u64);
+
+               vli[i] = get_unaligned_be64(&tmp[off]);
+       }
+}
+
+/*
+ * Extract raw (r || s) big-endian byte arrays from struct ecdsa_raw_sig.
+ * Each component is written as @clen bytes into @raw_rs.
+ */
+static int ecdsa_sig_to_raw(const void *src, unsigned int slen,
+                           u8 *raw_rs, u32 clen)
+{
+       const struct ecdsa_raw_sig *sig = src;
+       unsigned int ndigits = clen_to_ndigits(clen);
+
+       if (slen != sizeof(struct ecdsa_raw_sig))
+               return -EINVAL;
+
+       ecdsa_vli_to_be(sig->r, ndigits, raw_rs, clen);
+       ecdsa_vli_to_be(sig->s, ndigits, raw_rs + clen, clen);
+       return 0;
+}
+
+/*
+ * Encode raw (r || s) big-endian byte arrays into struct ecdsa_raw_sig.
+ * Returns sizeof(struct ecdsa_raw_sig) on success.
+ */
+static int ecdsa_raw_to_sig(const u8 *raw_rs, u32 clen,
+                           void *dst, unsigned int dlen)
+{
+       struct ecdsa_raw_sig *sig = dst;
+
+       if (dlen < sizeof(struct ecdsa_raw_sig))
+               return -ENOSPC;
+
+       memset(sig, 0, sizeof(*sig));
+       ecdsa_be_to_vli(raw_rs, clen, sig->r, ECC_MAX_DIGITS);
+       ecdsa_be_to_vli(raw_rs + clen, clen, sig->s, ECC_MAX_DIGITS);
+       return sizeof(struct ecdsa_raw_sig);
+}
+
+/*
+ * ECDSA verify (synchronous sig_alg)
+ *
+ * @src:    struct ecdsa_raw_sig (VLI format)
+ * @slen:   signature length (must be sizeof(struct ecdsa_raw_sig))
+ * @digest: hash digest
+ * @dlen:   digest length
+ *
+ * Returns 0 on successful verification, negative errno on failure.
+ */
+static int cmh_ecdsa_verify(struct crypto_sig *tfm,
+                           const void *src, unsigned int slen,
+                           const void *digest, unsigned int dlen)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+       u32 clen = ctx->clen;
+       u32 sig_raw_len = 2 * clen;
+       u32 copy_len = min_t(u32, dlen, clen);
+       struct core_dispatch d = cmh_core_select_instance(CMH_CORE_PKE);
+       struct vcq_cmd vcq[PKE_VCQ_CMDS_MIN];
+       u8 *sig_raw = NULL, *dig_buf = NULL, *pk_buf = NULL, *rp_buf = NULL;
+       dma_addr_t pk_dma, dig_dma, sig_dma, rp_dma;
+       int ret;
+
+       if (!ctx->pub_key)
+               return -EINVAL;
+
+       sig_raw = kzalloc(sig_raw_len, GFP_KERNEL);
+       dig_buf = kzalloc(clen, GFP_KERNEL);
+       pk_buf = kmemdup(ctx->pub_key, ctx->pub_key_len, GFP_KERNEL);
+       rp_buf = kzalloc(clen, GFP_KERNEL);
+       if (!sig_raw || !dig_buf || !pk_buf || !rp_buf) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       /* Extract raw (r, s) big-endian from VLI signature */
+       ret = ecdsa_sig_to_raw(src, slen, sig_raw, clen);
+       if (ret)
+               goto out_free;
+
+       /*
+        * Truncate or zero-pad digest to clen bytes, right-aligned.
+        * Matches ECDSA bits2int: use leftmost min(dlen, clen) bytes,
+        * zero-pad on the left when dlen < clen.
+        */
+       memcpy(dig_buf + (clen - copy_len), digest, copy_len);
+
+       pk_dma = cmh_dma_map_single(pk_buf, ctx->pub_key_len, DMA_TO_DEVICE);
+       dig_dma = cmh_dma_map_single(dig_buf, clen, DMA_TO_DEVICE);
+       sig_dma = cmh_dma_map_single(sig_raw, sig_raw_len, DMA_TO_DEVICE);
+       rp_dma = cmh_dma_map_single(rp_buf, clen, DMA_FROM_DEVICE);
+
+       if (cmh_dma_map_error(pk_dma) || cmh_dma_map_error(dig_dma) ||
+           cmh_dma_map_error(sig_dma) || cmh_dma_map_error(rp_dma)) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
+       vcq_set_header(&vcq[0], PKE_VCQ_CMDS_MIN);
+       vcq_add_pke_ecdsa_verify(&vcq[1], d.core_id, ctx->curve, clen,
+                                pk_dma, dig_dma, sig_dma, rp_dma,
+                                pke_swap_flags(ctx->curve));
+       vcq_add_pke_flush(&vcq[2], d.core_id);
+
+       ret = cmh_tm_submit_sync_mbx(vcq, PKE_VCQ_CMDS_MIN, 1, d.mbx_idx);
+
+out_unmap:
+       if (!cmh_dma_map_error(rp_dma))
+               cmh_dma_unmap_single(rp_dma, clen, DMA_FROM_DEVICE);
+       if (!cmh_dma_map_error(sig_dma))
+               cmh_dma_unmap_single(sig_dma, sig_raw_len, DMA_TO_DEVICE);
+       if (!cmh_dma_map_error(dig_dma))
+               cmh_dma_unmap_single(dig_dma, clen, DMA_TO_DEVICE);
+       if (!cmh_dma_map_error(pk_dma))
+               cmh_dma_unmap_single(pk_dma, ctx->pub_key_len, DMA_TO_DEVICE);
+
+out_free:
+       kfree(rp_buf);
+       kfree(pk_buf);
+       kfree(sig_raw);
+       kfree(dig_buf);
+       return ret;
+}
+
+/*
+ * ECDSA sign (synchronous sig_alg)
+ *
+ * @src:  hash digest
+ * @slen: digest length
+ * @dst:  output buffer for struct ecdsa_raw_sig (VLI format)
+ * @dlen: output buffer length
+ *
+ * Returns sizeof(struct ecdsa_raw_sig) on success, negative errno on failure.
+ */
+static int cmh_ecdsa_sign(struct crypto_sig *tfm,
+                         const void *src, unsigned int slen,
+                         void *dst, unsigned int dlen)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+       u32 clen = ctx->clen;
+       u32 sig_raw_len = 2 * clen;
+       u32 copy_len = min_t(u32, slen, clen);
+       struct core_dispatch dd;
+       struct vcq_cmd vcq[PKE_VCQ_CMDS_MAX];
+       u8 *dig_buf = NULL, *sig_buf = NULL, *sk_buf = NULL;
+       dma_addr_t dig_dma, sig_dma, sk_dma;
+       int ret, idx;
+
+       if (ctx->key.mode != CMH_KEY_RAW)
+               return -EINVAL;
+       if (dlen < sizeof(struct ecdsa_raw_sig))
+               return -EINVAL;
+
+       dig_buf = kzalloc(clen, GFP_KERNEL);
+       sig_buf = kzalloc(sig_raw_len, GFP_KERNEL);
+       sk_buf = kmemdup(ctx->key.raw.data, ctx->key.raw.len, GFP_KERNEL);
+       if (!dig_buf || !sig_buf || !sk_buf) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       /*
+        * Truncate or zero-pad digest to clen bytes, right-aligned.
+        * Matches ECDSA bits2int: use leftmost min(slen, clen) bytes,
+        * zero-pad on the left when slen < clen.
+        */
+       memcpy(dig_buf + (clen - copy_len), src, copy_len);
+
+       dig_dma = cmh_dma_map_single(dig_buf, clen, DMA_TO_DEVICE);
+       sig_dma = cmh_dma_map_single(sig_buf, sig_raw_len, DMA_FROM_DEVICE);
+       sk_dma = cmh_dma_map_single(sk_buf, ctx->key.raw.len, DMA_TO_DEVICE);
+
+       if (cmh_dma_map_error(dig_dma) || cmh_dma_map_error(sig_dma) ||
+           cmh_dma_map_error(sk_dma)) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
+       dd = cmh_core_select_instance(CMH_CORE_PKE);
+
+       idx = 1;
+       vcq_add_sys_write(&vcq[idx], SYS_REF_TEMP, sk_dma,
+                         SYS_REF_NONE, ctx->key.raw.len,
+                         ctx->key.raw.sys_type);
+       vcq[idx].id |= pke_swap_flags(ctx->curve);
+       idx++;
+       vcq_add_pke_ecdsa_sign(&vcq[idx++], dd.core_id, ctx->curve, clen,
+                              dig_dma, sig_dma, SYS_REF_TEMP,
+                              clen, pke_swap_flags(ctx->curve));
+       vcq_add_pke_flush(&vcq[idx++], dd.core_id);
+       vcq_set_header(&vcq[0], idx);
+
+       ret = cmh_tm_submit_sync_mbx(vcq, idx, 1, dd.mbx_idx);
+       if (!ret) {
+               /* Sync bounce buffer so CPU sees the DMA-written signature */
+               cmh_dma_sync_for_cpu(sig_dma, sig_raw_len, DMA_FROM_DEVICE);
+
+               /* Encode raw (r||s) into VLI ecdsa_raw_sig for kernel API */
+               ret = ecdsa_raw_to_sig(sig_buf, clen, dst, dlen);
+       }
+
+out_unmap:
+       if (!cmh_dma_map_error(sk_dma))
+               cmh_dma_unmap_single(sk_dma, ctx->key.raw.len, DMA_TO_DEVICE);
+       if (!cmh_dma_map_error(sig_dma))
+               cmh_dma_unmap_single(sig_dma, sig_raw_len, DMA_FROM_DEVICE);
+       if (!cmh_dma_map_error(dig_dma))
+               cmh_dma_unmap_single(dig_dma, clen, DMA_TO_DEVICE);
+
+out_free:
+       kfree_sensitive(sk_buf);
+       kfree(sig_buf);
+       kfree(dig_buf);
+       return ret;
+}
+
+static int cmh_ecdsa_set_pub_key(struct crypto_sig *tfm,
+                                const void *key, unsigned int keylen)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+       const u8 *d = key;
+       u32 clen = ctx->clen;
+       u32 raw_clen;
+
+       /* Accept 04 || X || Y (uncompressed point) */
+       if (keylen < 1 || d[0] != 0x04)
+               return -EINVAL;
+       d++;
+       keylen--;
+
+       if (keylen & 1)
+               return -EINVAL;
+       raw_clen = keylen / 2;
+
+       /*
+        * Kernel passes ceil(bits/8) per coordinate (e.g. 66 for P-521),
+        * but our HW ABI uses clen (ALIGN(66,4)=68 for P-521).
+        * Accept raw_clen <= clen and zero-pad on the left.
+        */
+       if (raw_clen > clen || raw_clen == 0)
+               return -EINVAL;
+
+       kfree(ctx->pub_key);
+       ctx->pub_key = NULL;
+       ctx->pub_key_len = 0;
+
+       ctx->pub_key = kzalloc(2 * clen, GFP_KERNEL);
+       if (!ctx->pub_key)
+               return -ENOMEM;
+
+       /* Right-align each coordinate to clen bytes */
+       memcpy(ctx->pub_key + (clen - raw_clen), d, raw_clen);
+       memcpy(ctx->pub_key + clen + (clen - raw_clen), d + raw_clen,
+              raw_clen);
+       ctx->pub_key_len = 2 * clen;
+       return 0;
+}
+
+static int cmh_ecdsa_set_priv_key(struct crypto_sig *tfm,
+                                 const void *key, unsigned int keylen)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       if (keylen != ctx->clen)
+               return -EINVAL;
+
+       return cmh_key_setkey_raw(&ctx->key, key, keylen, CORE_ID_PKE);
+}
+
+static unsigned int cmh_ecdsa_key_size(struct crypto_sig *tfm)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       /* crypto_sig_keysize() returns bits, not bytes */
+       return pke_curve_bits(ctx->curve);
+}
+
+static unsigned int cmh_ecdsa_max_size(struct crypto_sig *tfm)
+{
+       return sizeof(struct ecdsa_raw_sig);
+}
+
+static unsigned int cmh_ecdsa_digest_size(struct crypto_sig *tfm)
+{
+       /*
+        * Accept digests up to SHA-512 (64 bytes).  Digests longer
+        * than the curve order are truncated per ECDSA bits2int.
+        * Matches kernel ecdsa_digest_size().
+        */
+       return SHA512_DIGEST_SIZE;
+}
+
+static int cmh_ecdsa_p256_init(struct crypto_sig *tfm)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->curve = PKE_CURVE_P256;
+       ctx->clen = pke_curve_clen(PKE_CURVE_P256);
+       return 0;
+}
+
+static int cmh_ecdsa_p384_init(struct crypto_sig *tfm)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->curve = PKE_CURVE_P384;
+       ctx->clen = pke_curve_clen(PKE_CURVE_P384);
+       return 0;
+}
+
+static int cmh_ecdsa_p521_init(struct crypto_sig *tfm)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->curve = PKE_CURVE_P521;
+       ctx->clen = pke_curve_clen(PKE_CURVE_P521);
+       return 0;
+}
+
+static int cmh_sm2_init(struct crypto_sig *tfm)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->curve = PKE_CURVE_SM2;
+       ctx->clen = pke_curve_clen(PKE_CURVE_SM2);
+       return 0;
+}
+
+static void cmh_ecdsa_exit(struct crypto_sig *tfm)
+{
+       struct cmh_ecdsa_tfm_ctx *ctx = cmh_ecdsa_ctx(tfm);
+
+       cmh_key_destroy(&ctx->key);
+       kfree(ctx->pub_key);
+       ctx->pub_key = NULL;
+}
+
+static struct sig_alg cmh_ecdsa_algs[] = {
+       {
+               .sign           = cmh_ecdsa_sign,
+               .verify         = cmh_ecdsa_verify,
+               .set_pub_key    = cmh_ecdsa_set_pub_key,
+               .set_priv_key   = cmh_ecdsa_set_priv_key,
+               .key_size       = cmh_ecdsa_key_size,
+               .max_size       = cmh_ecdsa_max_size,
+               .digest_size    = cmh_ecdsa_digest_size,
+               .init           = cmh_ecdsa_p256_init,
+               .exit           = cmh_ecdsa_exit,
+               .base = {
+                       .cra_name         = "ecdsa-nist-p256",
+                       .cra_driver_name  = "cri-cmh-ecdsa-nist-p256",
+                       .cra_priority     = 300,
+                       .cra_module       = THIS_MODULE,
+                       .cra_ctxsize      = sizeof(struct cmh_ecdsa_tfm_ctx),
+               },
+       },
+       {
+               .sign           = cmh_ecdsa_sign,
+               .verify         = cmh_ecdsa_verify,
+               .set_pub_key    = cmh_ecdsa_set_pub_key,
+               .set_priv_key   = cmh_ecdsa_set_priv_key,
+               .key_size       = cmh_ecdsa_key_size,
+               .max_size       = cmh_ecdsa_max_size,
+               .digest_size    = cmh_ecdsa_digest_size,
+               .init           = cmh_ecdsa_p384_init,
+               .exit           = cmh_ecdsa_exit,
+               .base = {
+                       .cra_name         = "ecdsa-nist-p384",
+                       .cra_driver_name  = "cri-cmh-ecdsa-nist-p384",
+                       .cra_priority     = 300,
+                       .cra_module       = THIS_MODULE,
+                       .cra_ctxsize      = sizeof(struct cmh_ecdsa_tfm_ctx),
+               },
+       },
+       {
+               .sign           = cmh_ecdsa_sign,
+               .verify         = cmh_ecdsa_verify,
+               .set_pub_key    = cmh_ecdsa_set_pub_key,
+               .set_priv_key   = cmh_ecdsa_set_priv_key,
+               .key_size       = cmh_ecdsa_key_size,
+               .max_size       = cmh_ecdsa_max_size,
+               .digest_size    = cmh_ecdsa_digest_size,
+               .init           = cmh_ecdsa_p521_init,
+               .exit           = cmh_ecdsa_exit,
+               .base = {
+                       .cra_name         = "ecdsa-nist-p521",
+                       .cra_driver_name  = "cri-cmh-ecdsa-nist-p521",
+                       .cra_priority     = 300,
+                       .cra_module       = THIS_MODULE,
+                       .cra_ctxsize      = sizeof(struct cmh_ecdsa_tfm_ctx),
+               },
+       },
+       {
+               .verify         = cmh_ecdsa_verify,
+               .set_pub_key    = cmh_ecdsa_set_pub_key,
+               .key_size       = cmh_ecdsa_key_size,
+               .max_size       = cmh_ecdsa_max_size,
+               .digest_size    = cmh_ecdsa_digest_size,
+               .init           = cmh_sm2_init,
+               .exit           = cmh_ecdsa_exit,
+               .base = {
+                       .cra_name         = "sm2",
+                       .cra_driver_name  = "cri-cmh-sm2",
+                       .cra_priority     = 300,
+                       .cra_module       = THIS_MODULE,
+                       .cra_ctxsize      = sizeof(struct cmh_ecdsa_tfm_ctx),
+               },
+       },
+};
+
+/**
+ * cmh_pke_ecdsa_register() - Register ECDSA/SM2 sig algorithms with the 
crypto framework
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int cmh_pke_ecdsa_register(void)
+{
+       int ret, i;
+
+       for (i = 0; i < ARRAY_SIZE(cmh_ecdsa_algs); i++) {
+               ret = crypto_register_sig(&cmh_ecdsa_algs[i]);
+               if (ret) {
+                       dev_err(cmh_dev(), "cmh: failed to register %s (%d)\n",
+                               cmh_ecdsa_algs[i].base.cra_name, ret);
+                       goto err_unregister;
+               }
+       }
+
+       return 0;
+
+err_unregister:
+       while (i--)
+               crypto_unregister_sig(&cmh_ecdsa_algs[i]);
+       return ret;
+}
+
+/**
+ * cmh_pke_ecdsa_unregister() - Unregister ECDSA/SM2 sig algorithms from the 
crypto framework
+ */
+void cmh_pke_ecdsa_unregister(void)
+{
+       int i = ARRAY_SIZE(cmh_ecdsa_algs);
+
+       while (i--)
+               crypto_unregister_sig(&cmh_ecdsa_algs[i]);
+}
-- 
2.43.7


Reply via email to