From: Xuchun Shang <xuchun.shang@xxxxxxxxxxxxxxxxx> Only support verification through sm2 at present. Signed-off-by: Xuchun Shang <xuchun.shang@xxxxxxxxxxxxxxxxx> --- drivers/crypto/ycc/Makefile | 3 +- 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 | 250 ++++++++++++++++++++++++++++++++- drivers/crypto/ycc/ycc_ring.h | 8 ++ 6 files changed, 312 insertions(+), 2 deletions(-) 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 89d6d6f..4f95c7f 100644 --- a/drivers/crypto/ycc/Makefile +++ b/drivers/crypto/ycc/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-(CONFIG_CRYPTO_DEV_YCC) += ycc.o -ycc-objs := ycc_drv.o ycc_isr.o ycc_cdev.o ycc_ring.o ycc_ske.o ycc_aead.o ycc_pke.o +ycc-objs := ycc_drv.o ycc_isr.o ycc_cdev.o ycc_ring.o ycc_ske.o ycc_aead.o \ + ycc_pke.o sm2signature_asn1.o 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..41d27d6 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,222 @@ 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; +}; + +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; +} + +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 +903,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