All of lore.kernel.org
 help / color / mirror / Atom feed
From: 'Guanjun' <guanjun@linux.alibaba.com>
To: herbert@gondor.apana.org.au, elliott@hpe.com
Cc: zelin.deng@linux.alibaba.com, artie.ding@linux.alibaba.com,
	guanjun@linux.alibaba.com, linux-crypto@vger.kernel.org,
	linux-kernel@vger.kernel.org, xuchun.shang@linux.alibaba.com
Subject: [PATCH v3 8/9] crypto/ycc: Add sm2 algorithm support
Date: Tue, 25 Oct 2022 17:53:35 +0800	[thread overview]
Message-ID: <1666691616-69983-9-git-send-email-guanjun@linux.alibaba.com> (raw)
In-Reply-To: <1666691616-69983-1-git-send-email-guanjun@linux.alibaba.com>

From: Xuchun Shang <xuchun.shang@linux.alibaba.com>

Only support verification through sm2 at present.

Signed-off-by: Xuchun Shang <xuchun.shang@linux.alibaba.com>
---
 drivers/crypto/ycc/Makefile            |   4 +
 drivers/crypto/ycc/sm2signature_asn1.c |  38 +++++
 drivers/crypto/ycc/sm2signature_asn1.h |  13 ++
 drivers/crypto/ycc/ycc_algs.h          |   2 +
 drivers/crypto/ycc/ycc_pke.c           | 252 ++++++++++++++++++++++++++++++++-
 drivers/crypto/ycc/ycc_ring.h          |   8 ++
 6 files changed, 316 insertions(+), 1 deletion(-)
 create mode 100644 drivers/crypto/ycc/sm2signature_asn1.c
 create mode 100644 drivers/crypto/ycc/sm2signature_asn1.h

diff --git a/drivers/crypto/ycc/Makefile b/drivers/crypto/ycc/Makefile
index d1f22a9..fb42eec 100644
--- a/drivers/crypto/ycc/Makefile
+++ b/drivers/crypto/ycc/Makefile
@@ -1,3 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_CRYPTO_DEV_YCC) += ycc.o
 ycc-objs := ycc_drv.o ycc_isr.o ycc_ring.o ycc_ske.o ycc_aead.o ycc_pke.o
+
+ifndef CONFIG_CRYPTO_SM2
+ycc-objs += sm2signature_asn1.o
+endif
diff --git a/drivers/crypto/ycc/sm2signature_asn1.c b/drivers/crypto/ycc/sm2signature_asn1.c
new file mode 100644
index 00000000..1fd15c1
--- /dev/null
+++ b/drivers/crypto/ycc/sm2signature_asn1.c
@@ -0,0 +1,38 @@
+/*
+ * Automatically generated by asn1_compiler.  Do not edit
+ *
+ * ASN.1 parser for sm2signature
+ */
+#include <linux/asn1_ber_bytecode.h>
+#include "sm2signature_asn1.h"
+
+enum sm2signature_actions {
+	ACT_sm2_get_signature_r = 0,
+	ACT_sm2_get_signature_s = 1,
+	NR__sm2signature_actions = 2
+};
+
+static const asn1_action_t sm2signature_action_table[NR__sm2signature_actions] = {
+	[0] = sm2_get_signature_r,
+	[1] = sm2_get_signature_s,
+};
+
+static const unsigned char sm2signature_machine[] = {
+	// Sm2Signature
+	[0] = ASN1_OP_MATCH,
+	[1] = _tag(UNIV, CONS, SEQ),
+	[2] =  ASN1_OP_MATCH_ACT,		// sig_r
+	[3] =  _tag(UNIV, PRIM, INT),
+	[4] =  _action(ACT_sm2_get_signature_r),
+	[5] =  ASN1_OP_MATCH_ACT,		// sig_s
+	[6] =  _tag(UNIV, PRIM, INT),
+	[7] =  _action(ACT_sm2_get_signature_s),
+	[8] = ASN1_OP_END_SEQ,
+	[9] = ASN1_OP_COMPLETE,
+};
+
+const struct asn1_decoder sm2signature_decoder = {
+	.machine = sm2signature_machine,
+	.machlen = sizeof(sm2signature_machine),
+	.actions = sm2signature_action_table,
+};
diff --git a/drivers/crypto/ycc/sm2signature_asn1.h b/drivers/crypto/ycc/sm2signature_asn1.h
new file mode 100644
index 00000000..192c9e1
--- /dev/null
+++ b/drivers/crypto/ycc/sm2signature_asn1.h
@@ -0,0 +1,13 @@
+/*
+ * Automatically generated by asn1_compiler.  Do not edit
+ *
+ * ASN.1 parser for sm2signature
+ */
+#include <linux/asn1_decoder.h>
+
+extern const struct asn1_decoder sm2signature_decoder;
+
+extern int sm2_get_signature_r(void *context, size_t hdrlen,
+		unsigned char tag, const void *value, size_t vlen);
+extern int sm2_get_signature_s(void *context, size_t hdrlen,
+		unsigned char tag, const void *value, size_t vlen);
diff --git a/drivers/crypto/ycc/ycc_algs.h b/drivers/crypto/ycc/ycc_algs.h
index 6a13230a..26323a8 100644
--- a/drivers/crypto/ycc/ycc_algs.h
+++ b/drivers/crypto/ycc/ycc_algs.h
@@ -77,6 +77,8 @@ enum ycc_cmd_id {
 	YCC_CMD_CCM_ENC,
 	YCC_CMD_CCM_DEC, /* 0x28 */
 
+	YCC_CMD_SM2_VERIFY = 0x47,
+
 	YCC_CMD_RSA_ENC = 0x83,
 	YCC_CMD_RSA_DEC,
 	YCC_CMD_RSA_CRT_DEC,
diff --git a/drivers/crypto/ycc/ycc_pke.c b/drivers/crypto/ycc/ycc_pke.c
index 3debd80..ad72d12 100644
--- a/drivers/crypto/ycc/ycc_pke.c
+++ b/drivers/crypto/ycc/ycc_pke.c
@@ -8,6 +8,8 @@
 #include <linux/dma-mapping.h>
 #include <linux/crypto.h>
 #include <linux/mpi.h>
+
+#include "sm2signature_asn1.h"
 #include "ycc_algs.h"
 
 static int ycc_rsa_done_callback(void *ptr, u16 state)
@@ -666,6 +668,224 @@ static void ycc_rsa_exit(struct crypto_akcipher *tfm)
 	crypto_free_akcipher(ctx->soft_tfm);
 }
 
+#define MPI_NBYTES(m)	((mpi_get_nbits(m) + 7) / 8)
+
+static int ycc_sm2_done_callback(void *ptr, u16 state)
+{
+	struct ycc_pke_req *sm2_req = (struct ycc_pke_req *)ptr;
+	struct ycc_pke_ctx *ctx = sm2_req->ctx;
+	struct akcipher_request *req = sm2_req->req;
+	struct device *dev = YCC_DEV(ctx);
+
+	dma_free_coherent(dev, 128, sm2_req->src_vaddr, sm2_req->src_paddr);
+
+	if (req->base.complete)
+		req->base.complete(&req->base, state == CMD_SUCCESS ? 0 : -EBADMSG);
+	return 0;
+}
+
+struct sm2_signature_ctx {
+	MPI sig_r;
+	MPI sig_s;
+};
+
+#ifndef CONFIG_CRYPTO_SM2
+int sm2_get_signature_r(void *context, size_t hdrlen, unsigned char tag,
+			const void *value, size_t vlen)
+{
+	struct sm2_signature_ctx *sig = context;
+
+	if (!value || !vlen)
+		return -EINVAL;
+
+	sig->sig_r = mpi_read_raw_data(value, vlen);
+	if (!sig->sig_r)
+		return -ENOMEM;
+
+	return 0;
+}
+
+int sm2_get_signature_s(void *context, size_t hdrlen, unsigned char tag,
+			const void *value, size_t vlen)
+{
+	struct sm2_signature_ctx *sig = context;
+
+	if (!value || !vlen)
+		return -EINVAL;
+
+	sig->sig_s = mpi_read_raw_data(value, vlen);
+	if (!sig->sig_s)
+		return -ENOMEM;
+
+	return 0;
+}
+#endif
+
+static int ycc_sm2_verify(struct akcipher_request *req)
+{
+	struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+	struct ycc_pke_req *sm2_req = akcipher_request_ctx(req);
+	struct ycc_pke_ctx *ctx = akcipher_tfm_ctx(tfm);
+	struct ycc_sm2_verify_cmd *sm2_verify_cmd;
+	struct ycc_dev *ydev = ctx->ring->ydev;
+	struct ycc_ring *ring = ctx->ring;
+	struct device *dev = YCC_DEV(ctx);
+	struct sm2_signature_ctx sig;
+	struct ycc_flags *aflags;
+	u8 buffer[80] = {0};
+	int ret;
+
+	/* Do software fallback */
+	if (!test_bit(YDEV_STATUS_READY, &ydev->status) || ctx->key_len) {
+		akcipher_request_set_tfm(req, ctx->soft_tfm);
+		ret = crypto_akcipher_verify(req);
+		akcipher_request_set_tfm(req, tfm);
+		return ret;
+	}
+
+	if (req->src_len > 72 || req->src_len < 70 || req->dst_len != 32)
+		return -EINVAL;
+
+	sm2_req->ctx = ctx;
+	sm2_req->req = req;
+
+	sg_copy_buffer(req->src, sg_nents(req->src), buffer, req->src_len, 0, 1);
+	sig.sig_r = NULL;
+	sig.sig_s = NULL;
+	ret = asn1_ber_decoder(&sm2signature_decoder, &sig, buffer, req->src_len);
+	if (ret)
+		return -EINVAL;
+
+	ret = mpi_print(GCRYMPI_FMT_USG, buffer, MPI_NBYTES(sig.sig_r),
+			(size_t *)NULL, sig.sig_r);
+	if (ret)
+		return -EINVAL;
+
+	ret = mpi_print(GCRYMPI_FMT_USG, buffer + MPI_NBYTES(sig.sig_r),
+			MPI_NBYTES(sig.sig_s), (size_t *)NULL, sig.sig_s);
+	if (ret)
+		return -EINVAL;
+
+	ret = -ENOMEM;
+	/* Alloc dma for src, as verify has no output */
+	sm2_req->src_vaddr = dma_alloc_coherent(dev, 128, &sm2_req->src_paddr,
+						GFP_ATOMIC);
+	if (!sm2_req->src_vaddr)
+		goto out;
+
+	sg_copy_buffer(req->src, sg_nents(req->src), sm2_req->src_vaddr,
+		       req->dst_len, req->src_len, 1);
+	memcpy(sm2_req->src_vaddr + 32, buffer, 64);
+
+	sm2_req->dst_vaddr = NULL;
+
+	aflags = kzalloc(sizeof(struct ycc_flags), GFP_ATOMIC);
+	if (!aflags)
+		goto free_src;
+
+	aflags->ptr = (void *)sm2_req;
+	aflags->ycc_done_callback = ycc_sm2_done_callback;
+
+	memset(&sm2_req->desc, 0, sizeof(sm2_req->desc));
+	sm2_req->desc.private_ptr = (u64)(void *)aflags;
+
+	sm2_verify_cmd         = &sm2_req->desc.cmd.sm2_verify_cmd;
+	sm2_verify_cmd->cmd_id = YCC_CMD_SM2_VERIFY;
+	sm2_verify_cmd->sptr   = sm2_req->src_paddr;
+	sm2_verify_cmd->keyptr = ctx->pub_key_paddr;
+
+	ret = ycc_enqueue(ring, (u8 *)&sm2_req->desc);
+	if (!ret)
+		return -EINPROGRESS;
+
+	kfree(aflags);
+free_src:
+	dma_free_coherent(dev, 128, sm2_req->src_vaddr, sm2_req->src_paddr);
+out:
+	return ret;
+}
+
+static unsigned int ycc_sm2_max_size(struct crypto_akcipher *tfm)
+{
+	return PAGE_SIZE;
+}
+
+static int ycc_sm2_setpubkey(struct crypto_akcipher *tfm, const void *key,
+			     unsigned int keylen)
+{
+	struct ycc_pke_ctx *ctx = akcipher_tfm_ctx(tfm);
+	struct device *dev = YCC_DEV(ctx);
+	int ret;
+
+	ret = crypto_akcipher_set_pub_key(ctx->soft_tfm, key, keylen);
+	if (ret)
+		return ret;
+
+	/* Always alloc 64 bytes for pub key */
+	ctx->pub_key_vaddr = dma_alloc_coherent(dev, 64, &ctx->pub_key_paddr,
+						GFP_KERNEL);
+	if (!ctx->pub_key_vaddr)
+		return -ENOMEM;
+
+	/*
+	 * Uncompressed key 65 bytes with 0x04 flag
+	 * Compressed key 33 bytes with 0x02 or 0x03 flag
+	 */
+	switch (keylen) {
+	case 65:
+		if (*(u8 *)key != 0x04)
+			return -EINVAL;
+		memcpy(ctx->pub_key_vaddr, key + 1, 64);
+		break;
+	case 64:
+		memcpy(ctx->pub_key_vaddr, key, 64);
+		break;
+	case 33:
+		return 0; /* TODO: use sw temporary */
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ycc_sm2_init(struct crypto_akcipher *tfm)
+{
+	struct ycc_pke_ctx *ctx = akcipher_tfm_ctx(tfm);
+	struct ycc_ring *ring;
+
+	ctx->soft_tfm = crypto_alloc_akcipher("sm2-generic", 0, 0);
+	if (IS_ERR(ctx->soft_tfm))
+		return PTR_ERR(ctx->soft_tfm);
+
+	/* Reserve enough space if soft request reqires additional space */
+	akcipher_set_reqsize(tfm, sizeof(struct ycc_pke_req) +
+			     crypto_akcipher_alg(ctx->soft_tfm)->reqsize);
+
+	ring = ycc_crypto_get_ring();
+	if (!ring) {
+		crypto_free_akcipher(ctx->soft_tfm);
+		return -ENODEV;
+	}
+
+	ctx->ring = ring;
+	return 0;
+}
+
+static void ycc_sm2_exit(struct crypto_akcipher *tfm)
+{
+	struct ycc_pke_ctx *ctx = akcipher_tfm_ctx(tfm);
+	struct device *dev = YCC_DEV(ctx);
+
+	if (ctx->ring)
+		ycc_crypto_free_ring(ctx->ring);
+
+	if (ctx->pub_key_vaddr)
+		dma_free_coherent(dev, 64, ctx->pub_key_vaddr, ctx->pub_key_paddr);
+
+	crypto_free_akcipher(ctx->soft_tfm);
+}
+
 static struct akcipher_alg ycc_rsa = {
 	.base = {
 		.cra_name = "rsa",
@@ -685,12 +905,42 @@ static void ycc_rsa_exit(struct crypto_akcipher *tfm)
 	.exit = ycc_rsa_exit,
 };
 
+static struct akcipher_alg ycc_sm2 = {
+	.base = {
+		.cra_name = "sm2",
+		.cra_driver_name = "sm2-ycc",
+		.cra_priority = 1000,
+		.cra_module = THIS_MODULE,
+		.cra_ctxsize = sizeof(struct ycc_pke_ctx),
+	},
+	.verify = ycc_sm2_verify,
+	.set_pub_key = ycc_sm2_setpubkey,
+	.max_size = ycc_sm2_max_size,
+	.init = ycc_sm2_init,
+	.exit = ycc_sm2_exit,
+};
+
 int ycc_pke_register(void)
 {
-	return crypto_register_akcipher(&ycc_rsa);
+	int ret;
+
+	ret = crypto_register_akcipher(&ycc_rsa);
+	if (ret) {
+		pr_err("Failed to register rsa\n");
+		return ret;
+	}
+
+	ret = crypto_register_akcipher(&ycc_sm2);
+	if (ret) {
+		crypto_unregister_akcipher(&ycc_rsa);
+		pr_err("Failed to register sm2\n");
+	}
+
+	return ret;
 }
 
 void ycc_pke_unregister(void)
 {
 	crypto_unregister_akcipher(&ycc_rsa);
+	crypto_unregister_akcipher(&ycc_sm2);
 }
diff --git a/drivers/crypto/ycc/ycc_ring.h b/drivers/crypto/ycc/ycc_ring.h
index c47fc18..6dafdc7 100644
--- a/drivers/crypto/ycc/ycc_ring.h
+++ b/drivers/crypto/ycc/ycc_ring.h
@@ -121,11 +121,19 @@ struct ycc_rsa_dec_cmd {
 	u64 dptr:48;
 } __packed;
 
+struct ycc_sm2_verify_cmd {
+	u8 cmd_id;
+	u64 sptr:48;
+	u16 key_id;
+	u64 keyptr:48;
+} __packed;
+
 union ycc_real_cmd {
 	struct ycc_skcipher_cmd ske_cmd;
 	struct ycc_aead_cmd aead_cmd;
 	struct ycc_rsa_enc_cmd rsa_enc_cmd;
 	struct ycc_rsa_dec_cmd rsa_dec_cmd;
+	struct ycc_sm2_verify_cmd sm2_verify_cmd;
 	u8 padding[32];
 };
 
-- 
1.8.3.1


  parent reply	other threads:[~2022-10-25  9:59 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-25  9:53 [PATCH v3 0/9] Drivers for Alibaba YCC (Yitian Cryptography Complex) cryptographic accelerator 'Guanjun'
2022-10-25  9:53 ` [PATCH v3 1/9] crypto/ycc: Add YCC (Yitian Cryptography Complex) accelerator driver 'Guanjun'
2022-10-25  9:53 ` [PATCH v3 2/9] crypto/ycc: Add ycc ring configuration 'Guanjun'
2022-10-25 13:30   ` kernel test robot
2022-10-26 11:04   ` kernel test robot
2022-10-25  9:53 ` [PATCH v3 3/9] crypto/ycc: Add irq support for ycc kernel rings 'Guanjun'
2022-10-25  9:53 ` [PATCH v3 4/9] crypto/ycc: Add device error handling support for ycc hw errors 'Guanjun'
2022-10-25 14:18   ` kernel test robot
2022-10-25  9:53 ` [PATCH v3 5/9] crypto/ycc: Add skcipher algorithm support 'Guanjun'
2022-10-25 15:06   ` kernel test robot
2022-10-26 20:41   ` kernel test robot
2022-10-25  9:53 ` [PATCH v3 6/9] crypto/ycc: Add aead " 'Guanjun'
2022-10-26 23:13   ` kernel test robot
2022-10-25  9:53 ` [PATCH v3 7/9] crypto/ycc: Add rsa " 'Guanjun'
2022-10-25  9:53 ` 'Guanjun' [this message]
2022-10-26 23:23   ` [PATCH v3 8/9] crypto/ycc: Add sm2 " kernel test robot
2022-10-25  9:53 ` [PATCH v3 9/9] MAINTAINERS: Add Yitian Cryptography Complex (YCC) driver maintainer entry 'Guanjun'
2022-10-26  9:03 ` [PATCH v3 0/9] Drivers for Alibaba YCC (Yitian Cryptography Complex) cryptographic accelerator guanjun

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1666691616-69983-9-git-send-email-guanjun@linux.alibaba.com \
    --to=guanjun@linux.alibaba.com \
    --cc=artie.ding@linux.alibaba.com \
    --cc=elliott@hpe.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=xuchun.shang@linux.alibaba.com \
    --cc=zelin.deng@linux.alibaba.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.