162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci /* Asymmetric algorithms supported by virtio crypto device 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: zhenwei pi <pizhenwei@bytedance.com> 562306a36Sopenharmony_ci * lei he <helei.sig11@bytedance.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2022 Bytedance CO., LTD. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <crypto/engine.h> 1162306a36Sopenharmony_ci#include <crypto/internal/akcipher.h> 1262306a36Sopenharmony_ci#include <crypto/internal/rsa.h> 1362306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/mpi.h> 1762306a36Sopenharmony_ci#include <linux/scatterlist.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/string.h> 2062306a36Sopenharmony_ci#include <uapi/linux/virtio_crypto.h> 2162306a36Sopenharmony_ci#include "virtio_crypto_common.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct virtio_crypto_rsa_ctx { 2462306a36Sopenharmony_ci MPI n; 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct virtio_crypto_akcipher_ctx { 2862306a36Sopenharmony_ci struct virtio_crypto *vcrypto; 2962306a36Sopenharmony_ci struct crypto_akcipher *tfm; 3062306a36Sopenharmony_ci bool session_valid; 3162306a36Sopenharmony_ci __u64 session_id; 3262306a36Sopenharmony_ci union { 3362306a36Sopenharmony_ci struct virtio_crypto_rsa_ctx rsa_ctx; 3462306a36Sopenharmony_ci }; 3562306a36Sopenharmony_ci}; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistruct virtio_crypto_akcipher_request { 3862306a36Sopenharmony_ci struct virtio_crypto_request base; 3962306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *akcipher_ctx; 4062306a36Sopenharmony_ci struct akcipher_request *akcipher_req; 4162306a36Sopenharmony_ci void *src_buf; 4262306a36Sopenharmony_ci void *dst_buf; 4362306a36Sopenharmony_ci uint32_t opcode; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct virtio_crypto_akcipher_algo { 4762306a36Sopenharmony_ci uint32_t algonum; 4862306a36Sopenharmony_ci uint32_t service; 4962306a36Sopenharmony_ci unsigned int active_devs; 5062306a36Sopenharmony_ci struct akcipher_engine_alg algo; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic DEFINE_MUTEX(algs_lock); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic void virtio_crypto_akcipher_finalize_req( 5662306a36Sopenharmony_ci struct virtio_crypto_akcipher_request *vc_akcipher_req, 5762306a36Sopenharmony_ci struct akcipher_request *req, int err) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci kfree(vc_akcipher_req->src_buf); 6062306a36Sopenharmony_ci kfree(vc_akcipher_req->dst_buf); 6162306a36Sopenharmony_ci vc_akcipher_req->src_buf = NULL; 6262306a36Sopenharmony_ci vc_akcipher_req->dst_buf = NULL; 6362306a36Sopenharmony_ci virtcrypto_clear_request(&vc_akcipher_req->base); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci crypto_finalize_akcipher_request(vc_akcipher_req->base.dataq->engine, req, err); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request *vc_req, int len) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct virtio_crypto_akcipher_request *vc_akcipher_req = 7162306a36Sopenharmony_ci container_of(vc_req, struct virtio_crypto_akcipher_request, base); 7262306a36Sopenharmony_ci struct akcipher_request *akcipher_req; 7362306a36Sopenharmony_ci int error; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci switch (vc_req->status) { 7662306a36Sopenharmony_ci case VIRTIO_CRYPTO_OK: 7762306a36Sopenharmony_ci error = 0; 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci case VIRTIO_CRYPTO_INVSESS: 8062306a36Sopenharmony_ci case VIRTIO_CRYPTO_ERR: 8162306a36Sopenharmony_ci error = -EINVAL; 8262306a36Sopenharmony_ci break; 8362306a36Sopenharmony_ci case VIRTIO_CRYPTO_BADMSG: 8462306a36Sopenharmony_ci error = -EBADMSG; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci case VIRTIO_CRYPTO_KEY_REJECTED: 8862306a36Sopenharmony_ci error = -EKEYREJECTED; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci default: 9262306a36Sopenharmony_ci error = -EIO; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci akcipher_req = vc_akcipher_req->akcipher_req; 9762306a36Sopenharmony_ci if (vc_akcipher_req->opcode != VIRTIO_CRYPTO_AKCIPHER_VERIFY) { 9862306a36Sopenharmony_ci /* actuall length maybe less than dst buffer */ 9962306a36Sopenharmony_ci akcipher_req->dst_len = len - sizeof(vc_req->status); 10062306a36Sopenharmony_ci sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst), 10162306a36Sopenharmony_ci vc_akcipher_req->dst_buf, akcipher_req->dst_len); 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci virtio_crypto_akcipher_finalize_req(vc_akcipher_req, akcipher_req, error); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher_ctx *ctx, 10762306a36Sopenharmony_ci struct virtio_crypto_ctrl_header *header, 10862306a36Sopenharmony_ci struct virtio_crypto_akcipher_session_para *para, 10962306a36Sopenharmony_ci const uint8_t *key, unsigned int keylen) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct scatterlist outhdr_sg, key_sg, inhdr_sg, *sgs[3]; 11262306a36Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 11362306a36Sopenharmony_ci uint8_t *pkey; 11462306a36Sopenharmony_ci int err; 11562306a36Sopenharmony_ci unsigned int num_out = 0, num_in = 0; 11662306a36Sopenharmony_ci struct virtio_crypto_op_ctrl_req *ctrl; 11762306a36Sopenharmony_ci struct virtio_crypto_session_input *input; 11862306a36Sopenharmony_ci struct virtio_crypto_ctrl_request *vc_ctrl_req; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci pkey = kmemdup(key, keylen, GFP_KERNEL); 12162306a36Sopenharmony_ci if (!pkey) 12262306a36Sopenharmony_ci return -ENOMEM; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci vc_ctrl_req = kzalloc(sizeof(*vc_ctrl_req), GFP_KERNEL); 12562306a36Sopenharmony_ci if (!vc_ctrl_req) { 12662306a36Sopenharmony_ci err = -ENOMEM; 12762306a36Sopenharmony_ci goto out; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci ctrl = &vc_ctrl_req->ctrl; 13162306a36Sopenharmony_ci memcpy(&ctrl->header, header, sizeof(ctrl->header)); 13262306a36Sopenharmony_ci memcpy(&ctrl->u.akcipher_create_session.para, para, sizeof(*para)); 13362306a36Sopenharmony_ci input = &vc_ctrl_req->input; 13462306a36Sopenharmony_ci input->status = cpu_to_le32(VIRTIO_CRYPTO_ERR); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci sg_init_one(&outhdr_sg, ctrl, sizeof(*ctrl)); 13762306a36Sopenharmony_ci sgs[num_out++] = &outhdr_sg; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci sg_init_one(&key_sg, pkey, keylen); 14062306a36Sopenharmony_ci sgs[num_out++] = &key_sg; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci sg_init_one(&inhdr_sg, input, sizeof(*input)); 14362306a36Sopenharmony_ci sgs[num_out + num_in++] = &inhdr_sg; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, num_out, num_in, vc_ctrl_req); 14662306a36Sopenharmony_ci if (err < 0) 14762306a36Sopenharmony_ci goto out; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (le32_to_cpu(input->status) != VIRTIO_CRYPTO_OK) { 15062306a36Sopenharmony_ci pr_err("virtio_crypto: Create session failed status: %u\n", 15162306a36Sopenharmony_ci le32_to_cpu(input->status)); 15262306a36Sopenharmony_ci err = -EINVAL; 15362306a36Sopenharmony_ci goto out; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ctx->session_id = le64_to_cpu(input->session_id); 15762306a36Sopenharmony_ci ctx->session_valid = true; 15862306a36Sopenharmony_ci err = 0; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ciout: 16162306a36Sopenharmony_ci kfree(vc_ctrl_req); 16262306a36Sopenharmony_ci kfree_sensitive(pkey); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci return err; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int virtio_crypto_alg_akcipher_close_session(struct virtio_crypto_akcipher_ctx *ctx) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct scatterlist outhdr_sg, inhdr_sg, *sgs[2]; 17062306a36Sopenharmony_ci struct virtio_crypto_destroy_session_req *destroy_session; 17162306a36Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 17262306a36Sopenharmony_ci unsigned int num_out = 0, num_in = 0; 17362306a36Sopenharmony_ci int err; 17462306a36Sopenharmony_ci struct virtio_crypto_op_ctrl_req *ctrl; 17562306a36Sopenharmony_ci struct virtio_crypto_inhdr *ctrl_status; 17662306a36Sopenharmony_ci struct virtio_crypto_ctrl_request *vc_ctrl_req; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (!ctx->session_valid) 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci vc_ctrl_req = kzalloc(sizeof(*vc_ctrl_req), GFP_KERNEL); 18262306a36Sopenharmony_ci if (!vc_ctrl_req) 18362306a36Sopenharmony_ci return -ENOMEM; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci ctrl_status = &vc_ctrl_req->ctrl_status; 18662306a36Sopenharmony_ci ctrl_status->status = VIRTIO_CRYPTO_ERR; 18762306a36Sopenharmony_ci ctrl = &vc_ctrl_req->ctrl; 18862306a36Sopenharmony_ci ctrl->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION); 18962306a36Sopenharmony_ci ctrl->header.queue_id = 0; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci destroy_session = &ctrl->u.destroy_session; 19262306a36Sopenharmony_ci destroy_session->session_id = cpu_to_le64(ctx->session_id); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci sg_init_one(&outhdr_sg, ctrl, sizeof(*ctrl)); 19562306a36Sopenharmony_ci sgs[num_out++] = &outhdr_sg; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci sg_init_one(&inhdr_sg, &ctrl_status->status, sizeof(ctrl_status->status)); 19862306a36Sopenharmony_ci sgs[num_out + num_in++] = &inhdr_sg; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, num_out, num_in, vc_ctrl_req); 20162306a36Sopenharmony_ci if (err < 0) 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (ctrl_status->status != VIRTIO_CRYPTO_OK) { 20562306a36Sopenharmony_ci pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n", 20662306a36Sopenharmony_ci ctrl_status->status, destroy_session->session_id); 20762306a36Sopenharmony_ci err = -EINVAL; 20862306a36Sopenharmony_ci goto out; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci err = 0; 21262306a36Sopenharmony_ci ctx->session_valid = false; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciout: 21562306a36Sopenharmony_ci kfree(vc_ctrl_req); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return err; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request *vc_akcipher_req, 22162306a36Sopenharmony_ci struct akcipher_request *req, struct data_queue *data_vq) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx; 22462306a36Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_akcipher_req->base; 22562306a36Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 22662306a36Sopenharmony_ci struct virtio_crypto_op_data_req *req_data = vc_req->req_data; 22762306a36Sopenharmony_ci struct scatterlist *sgs[4], outhdr_sg, inhdr_sg, srcdata_sg, dstdata_sg; 22862306a36Sopenharmony_ci void *src_buf = NULL, *dst_buf = NULL; 22962306a36Sopenharmony_ci unsigned int num_out = 0, num_in = 0; 23062306a36Sopenharmony_ci int node = dev_to_node(&vcrypto->vdev->dev); 23162306a36Sopenharmony_ci unsigned long flags; 23262306a36Sopenharmony_ci int ret = -ENOMEM; 23362306a36Sopenharmony_ci bool verify = vc_akcipher_req->opcode == VIRTIO_CRYPTO_AKCIPHER_VERIFY; 23462306a36Sopenharmony_ci unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* out header */ 23762306a36Sopenharmony_ci sg_init_one(&outhdr_sg, req_data, sizeof(*req_data)); 23862306a36Sopenharmony_ci sgs[num_out++] = &outhdr_sg; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* src data */ 24162306a36Sopenharmony_ci src_buf = kcalloc_node(src_len, 1, GFP_KERNEL, node); 24262306a36Sopenharmony_ci if (!src_buf) 24362306a36Sopenharmony_ci goto err; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (verify) { 24662306a36Sopenharmony_ci /* for verify operation, both src and dst data work as OUT direction */ 24762306a36Sopenharmony_ci sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len); 24862306a36Sopenharmony_ci sg_init_one(&srcdata_sg, src_buf, src_len); 24962306a36Sopenharmony_ci sgs[num_out++] = &srcdata_sg; 25062306a36Sopenharmony_ci } else { 25162306a36Sopenharmony_ci sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len); 25262306a36Sopenharmony_ci sg_init_one(&srcdata_sg, src_buf, src_len); 25362306a36Sopenharmony_ci sgs[num_out++] = &srcdata_sg; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* dst data */ 25662306a36Sopenharmony_ci dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node); 25762306a36Sopenharmony_ci if (!dst_buf) 25862306a36Sopenharmony_ci goto err; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci sg_init_one(&dstdata_sg, dst_buf, req->dst_len); 26162306a36Sopenharmony_ci sgs[num_out + num_in++] = &dstdata_sg; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci vc_akcipher_req->src_buf = src_buf; 26562306a36Sopenharmony_ci vc_akcipher_req->dst_buf = dst_buf; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* in header */ 26862306a36Sopenharmony_ci sg_init_one(&inhdr_sg, &vc_req->status, sizeof(vc_req->status)); 26962306a36Sopenharmony_ci sgs[num_out + num_in++] = &inhdr_sg; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci spin_lock_irqsave(&data_vq->lock, flags); 27262306a36Sopenharmony_ci ret = virtqueue_add_sgs(data_vq->vq, sgs, num_out, num_in, vc_req, GFP_ATOMIC); 27362306a36Sopenharmony_ci virtqueue_kick(data_vq->vq); 27462306a36Sopenharmony_ci spin_unlock_irqrestore(&data_vq->lock, flags); 27562306a36Sopenharmony_ci if (ret) 27662306a36Sopenharmony_ci goto err; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cierr: 28162306a36Sopenharmony_ci kfree(src_buf); 28262306a36Sopenharmony_ci kfree(dst_buf); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return -ENOMEM; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int virtio_crypto_rsa_do_req(struct crypto_engine *engine, void *vreq) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct akcipher_request *req = container_of(vreq, struct akcipher_request, base); 29062306a36Sopenharmony_ci struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req); 29162306a36Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_akcipher_req->base; 29262306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx; 29362306a36Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 29462306a36Sopenharmony_ci struct data_queue *data_vq = vc_req->dataq; 29562306a36Sopenharmony_ci struct virtio_crypto_op_header *header; 29662306a36Sopenharmony_ci struct virtio_crypto_akcipher_data_req *akcipher_req; 29762306a36Sopenharmony_ci int ret; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci vc_req->sgs = NULL; 30062306a36Sopenharmony_ci vc_req->req_data = kzalloc_node(sizeof(*vc_req->req_data), 30162306a36Sopenharmony_ci GFP_KERNEL, dev_to_node(&vcrypto->vdev->dev)); 30262306a36Sopenharmony_ci if (!vc_req->req_data) 30362306a36Sopenharmony_ci return -ENOMEM; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* build request header */ 30662306a36Sopenharmony_ci header = &vc_req->req_data->header; 30762306a36Sopenharmony_ci header->opcode = cpu_to_le32(vc_akcipher_req->opcode); 30862306a36Sopenharmony_ci header->algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA); 30962306a36Sopenharmony_ci header->session_id = cpu_to_le64(ctx->session_id); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* build request akcipher data */ 31262306a36Sopenharmony_ci akcipher_req = &vc_req->req_data->u.akcipher_req; 31362306a36Sopenharmony_ci akcipher_req->para.src_data_len = cpu_to_le32(req->src_len); 31462306a36Sopenharmony_ci akcipher_req->para.dst_data_len = cpu_to_le32(req->dst_len); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ret = __virtio_crypto_akcipher_do_req(vc_akcipher_req, req, data_vq); 31762306a36Sopenharmony_ci if (ret < 0) { 31862306a36Sopenharmony_ci kfree_sensitive(vc_req->req_data); 31962306a36Sopenharmony_ci vc_req->req_data = NULL; 32062306a36Sopenharmony_ci return ret; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int virtio_crypto_rsa_req(struct akcipher_request *req, uint32_t opcode) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct crypto_akcipher *atfm = crypto_akcipher_reqtfm(req); 32962306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(atfm); 33062306a36Sopenharmony_ci struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req); 33162306a36Sopenharmony_ci struct virtio_crypto_request *vc_req = &vc_akcipher_req->base; 33262306a36Sopenharmony_ci struct virtio_crypto *vcrypto = ctx->vcrypto; 33362306a36Sopenharmony_ci /* Use the first data virtqueue as default */ 33462306a36Sopenharmony_ci struct data_queue *data_vq = &vcrypto->data_vq[0]; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci vc_req->dataq = data_vq; 33762306a36Sopenharmony_ci vc_req->alg_cb = virtio_crypto_dataq_akcipher_callback; 33862306a36Sopenharmony_ci vc_akcipher_req->akcipher_ctx = ctx; 33962306a36Sopenharmony_ci vc_akcipher_req->akcipher_req = req; 34062306a36Sopenharmony_ci vc_akcipher_req->opcode = opcode; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci return crypto_transfer_akcipher_request_to_engine(data_vq->engine, req); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int virtio_crypto_rsa_encrypt(struct akcipher_request *req) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_ENCRYPT); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic int virtio_crypto_rsa_decrypt(struct akcipher_request *req) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_DECRYPT); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int virtio_crypto_rsa_sign(struct akcipher_request *req) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_SIGN); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic int virtio_crypto_rsa_verify(struct akcipher_request *req) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_VERIFY); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm, 36662306a36Sopenharmony_ci const void *key, 36762306a36Sopenharmony_ci unsigned int keylen, 36862306a36Sopenharmony_ci bool private, 36962306a36Sopenharmony_ci int padding_algo, 37062306a36Sopenharmony_ci int hash_algo) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); 37362306a36Sopenharmony_ci struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx; 37462306a36Sopenharmony_ci struct virtio_crypto *vcrypto; 37562306a36Sopenharmony_ci struct virtio_crypto_ctrl_header header; 37662306a36Sopenharmony_ci struct virtio_crypto_akcipher_session_para para; 37762306a36Sopenharmony_ci struct rsa_key rsa_key = {0}; 37862306a36Sopenharmony_ci int node = virtio_crypto_get_current_node(); 37962306a36Sopenharmony_ci uint32_t keytype; 38062306a36Sopenharmony_ci int ret; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* mpi_free will test n, just free it. */ 38362306a36Sopenharmony_ci mpi_free(rsa_ctx->n); 38462306a36Sopenharmony_ci rsa_ctx->n = NULL; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (private) { 38762306a36Sopenharmony_ci keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE; 38862306a36Sopenharmony_ci ret = rsa_parse_priv_key(&rsa_key, key, keylen); 38962306a36Sopenharmony_ci } else { 39062306a36Sopenharmony_ci keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC; 39162306a36Sopenharmony_ci ret = rsa_parse_pub_key(&rsa_key, key, keylen); 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (ret) 39562306a36Sopenharmony_ci return ret; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci rsa_ctx->n = mpi_read_raw_data(rsa_key.n, rsa_key.n_sz); 39862306a36Sopenharmony_ci if (!rsa_ctx->n) 39962306a36Sopenharmony_ci return -ENOMEM; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (!ctx->vcrypto) { 40262306a36Sopenharmony_ci vcrypto = virtcrypto_get_dev_node(node, VIRTIO_CRYPTO_SERVICE_AKCIPHER, 40362306a36Sopenharmony_ci VIRTIO_CRYPTO_AKCIPHER_RSA); 40462306a36Sopenharmony_ci if (!vcrypto) { 40562306a36Sopenharmony_ci pr_err("virtio_crypto: Could not find a virtio device in the system or unsupported algo\n"); 40662306a36Sopenharmony_ci return -ENODEV; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ctx->vcrypto = vcrypto; 41062306a36Sopenharmony_ci } else { 41162306a36Sopenharmony_ci virtio_crypto_alg_akcipher_close_session(ctx); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* set ctrl header */ 41562306a36Sopenharmony_ci header.opcode = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION); 41662306a36Sopenharmony_ci header.algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA); 41762306a36Sopenharmony_ci header.queue_id = 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* set RSA para */ 42062306a36Sopenharmony_ci para.algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA); 42162306a36Sopenharmony_ci para.keytype = cpu_to_le32(keytype); 42262306a36Sopenharmony_ci para.keylen = cpu_to_le32(keylen); 42362306a36Sopenharmony_ci para.u.rsa.padding_algo = cpu_to_le32(padding_algo); 42462306a36Sopenharmony_ci para.u.rsa.hash_algo = cpu_to_le32(hash_algo); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return virtio_crypto_alg_akcipher_init_session(ctx, &header, ¶, key, keylen); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic int virtio_crypto_rsa_raw_set_priv_key(struct crypto_akcipher *tfm, 43062306a36Sopenharmony_ci const void *key, 43162306a36Sopenharmony_ci unsigned int keylen) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci return virtio_crypto_rsa_set_key(tfm, key, keylen, 1, 43462306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_RAW_PADDING, 43562306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_NO_HASH); 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int virtio_crypto_p1pad_rsa_sha1_set_priv_key(struct crypto_akcipher *tfm, 44062306a36Sopenharmony_ci const void *key, 44162306a36Sopenharmony_ci unsigned int keylen) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci return virtio_crypto_rsa_set_key(tfm, key, keylen, 1, 44462306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_PKCS1_PADDING, 44562306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_SHA1); 44662306a36Sopenharmony_ci} 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_cistatic int virtio_crypto_rsa_raw_set_pub_key(struct crypto_akcipher *tfm, 44962306a36Sopenharmony_ci const void *key, 45062306a36Sopenharmony_ci unsigned int keylen) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci return virtio_crypto_rsa_set_key(tfm, key, keylen, 0, 45362306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_RAW_PADDING, 45462306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_NO_HASH); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int virtio_crypto_p1pad_rsa_sha1_set_pub_key(struct crypto_akcipher *tfm, 45862306a36Sopenharmony_ci const void *key, 45962306a36Sopenharmony_ci unsigned int keylen) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci return virtio_crypto_rsa_set_key(tfm, key, keylen, 0, 46262306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_PKCS1_PADDING, 46362306a36Sopenharmony_ci VIRTIO_CRYPTO_RSA_SHA1); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic unsigned int virtio_crypto_rsa_max_size(struct crypto_akcipher *tfm) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); 46962306a36Sopenharmony_ci struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci return mpi_get_size(rsa_ctx->n); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int virtio_crypto_rsa_init_tfm(struct crypto_akcipher *tfm) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ctx->tfm = tfm; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci akcipher_set_reqsize(tfm, 48162306a36Sopenharmony_ci sizeof(struct virtio_crypto_akcipher_request)); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return 0; 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic void virtio_crypto_rsa_exit_tfm(struct crypto_akcipher *tfm) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm); 48962306a36Sopenharmony_ci struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci virtio_crypto_alg_akcipher_close_session(ctx); 49262306a36Sopenharmony_ci virtcrypto_dev_put(ctx->vcrypto); 49362306a36Sopenharmony_ci mpi_free(rsa_ctx->n); 49462306a36Sopenharmony_ci rsa_ctx->n = NULL; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = { 49862306a36Sopenharmony_ci { 49962306a36Sopenharmony_ci .algonum = VIRTIO_CRYPTO_AKCIPHER_RSA, 50062306a36Sopenharmony_ci .service = VIRTIO_CRYPTO_SERVICE_AKCIPHER, 50162306a36Sopenharmony_ci .algo.base = { 50262306a36Sopenharmony_ci .encrypt = virtio_crypto_rsa_encrypt, 50362306a36Sopenharmony_ci .decrypt = virtio_crypto_rsa_decrypt, 50462306a36Sopenharmony_ci .set_pub_key = virtio_crypto_rsa_raw_set_pub_key, 50562306a36Sopenharmony_ci .set_priv_key = virtio_crypto_rsa_raw_set_priv_key, 50662306a36Sopenharmony_ci .max_size = virtio_crypto_rsa_max_size, 50762306a36Sopenharmony_ci .init = virtio_crypto_rsa_init_tfm, 50862306a36Sopenharmony_ci .exit = virtio_crypto_rsa_exit_tfm, 50962306a36Sopenharmony_ci .base = { 51062306a36Sopenharmony_ci .cra_name = "rsa", 51162306a36Sopenharmony_ci .cra_driver_name = "virtio-crypto-rsa", 51262306a36Sopenharmony_ci .cra_priority = 150, 51362306a36Sopenharmony_ci .cra_module = THIS_MODULE, 51462306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx), 51562306a36Sopenharmony_ci }, 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci .algo.op = { 51862306a36Sopenharmony_ci .do_one_request = virtio_crypto_rsa_do_req, 51962306a36Sopenharmony_ci }, 52062306a36Sopenharmony_ci }, 52162306a36Sopenharmony_ci { 52262306a36Sopenharmony_ci .algonum = VIRTIO_CRYPTO_AKCIPHER_RSA, 52362306a36Sopenharmony_ci .service = VIRTIO_CRYPTO_SERVICE_AKCIPHER, 52462306a36Sopenharmony_ci .algo.base = { 52562306a36Sopenharmony_ci .encrypt = virtio_crypto_rsa_encrypt, 52662306a36Sopenharmony_ci .decrypt = virtio_crypto_rsa_decrypt, 52762306a36Sopenharmony_ci .sign = virtio_crypto_rsa_sign, 52862306a36Sopenharmony_ci .verify = virtio_crypto_rsa_verify, 52962306a36Sopenharmony_ci .set_pub_key = virtio_crypto_p1pad_rsa_sha1_set_pub_key, 53062306a36Sopenharmony_ci .set_priv_key = virtio_crypto_p1pad_rsa_sha1_set_priv_key, 53162306a36Sopenharmony_ci .max_size = virtio_crypto_rsa_max_size, 53262306a36Sopenharmony_ci .init = virtio_crypto_rsa_init_tfm, 53362306a36Sopenharmony_ci .exit = virtio_crypto_rsa_exit_tfm, 53462306a36Sopenharmony_ci .base = { 53562306a36Sopenharmony_ci .cra_name = "pkcs1pad(rsa,sha1)", 53662306a36Sopenharmony_ci .cra_driver_name = "virtio-pkcs1-rsa-with-sha1", 53762306a36Sopenharmony_ci .cra_priority = 150, 53862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 53962306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx), 54062306a36Sopenharmony_ci }, 54162306a36Sopenharmony_ci }, 54262306a36Sopenharmony_ci .algo.op = { 54362306a36Sopenharmony_ci .do_one_request = virtio_crypto_rsa_do_req, 54462306a36Sopenharmony_ci }, 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci}; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ciint virtio_crypto_akcipher_algs_register(struct virtio_crypto *vcrypto) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci int ret = 0; 55162306a36Sopenharmony_ci int i = 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci mutex_lock(&algs_lock); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(virtio_crypto_akcipher_algs); i++) { 55662306a36Sopenharmony_ci uint32_t service = virtio_crypto_akcipher_algs[i].service; 55762306a36Sopenharmony_ci uint32_t algonum = virtio_crypto_akcipher_algs[i].algonum; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!virtcrypto_algo_is_supported(vcrypto, service, algonum)) 56062306a36Sopenharmony_ci continue; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (virtio_crypto_akcipher_algs[i].active_devs == 0) { 56362306a36Sopenharmony_ci ret = crypto_engine_register_akcipher(&virtio_crypto_akcipher_algs[i].algo); 56462306a36Sopenharmony_ci if (ret) 56562306a36Sopenharmony_ci goto unlock; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci virtio_crypto_akcipher_algs[i].active_devs++; 56962306a36Sopenharmony_ci dev_info(&vcrypto->vdev->dev, "Registered akcipher algo %s\n", 57062306a36Sopenharmony_ci virtio_crypto_akcipher_algs[i].algo.base.base.cra_name); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ciunlock: 57462306a36Sopenharmony_ci mutex_unlock(&algs_lock); 57562306a36Sopenharmony_ci return ret; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_civoid virtio_crypto_akcipher_algs_unregister(struct virtio_crypto *vcrypto) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci int i = 0; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci mutex_lock(&algs_lock); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(virtio_crypto_akcipher_algs); i++) { 58562306a36Sopenharmony_ci uint32_t service = virtio_crypto_akcipher_algs[i].service; 58662306a36Sopenharmony_ci uint32_t algonum = virtio_crypto_akcipher_algs[i].algonum; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (virtio_crypto_akcipher_algs[i].active_devs == 0 || 58962306a36Sopenharmony_ci !virtcrypto_algo_is_supported(vcrypto, service, algonum)) 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (virtio_crypto_akcipher_algs[i].active_devs == 1) 59362306a36Sopenharmony_ci crypto_engine_unregister_akcipher(&virtio_crypto_akcipher_algs[i].algo); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci virtio_crypto_akcipher_algs[i].active_devs--; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci mutex_unlock(&algs_lock); 59962306a36Sopenharmony_ci} 600