18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci /* Asymmetric algorithms supported by virtio crypto device
38c2ecf20Sopenharmony_ci  *
48c2ecf20Sopenharmony_ci  * Authors: zhenwei pi <pizhenwei@bytedance.com>
58c2ecf20Sopenharmony_ci  *          lei he <helei.sig11@bytedance.com>
68c2ecf20Sopenharmony_ci  *
78c2ecf20Sopenharmony_ci  * Copyright 2022 Bytedance CO., LTD.
88c2ecf20Sopenharmony_ci  */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/mpi.h>
118c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
128c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
138c2ecf20Sopenharmony_ci#include <crypto/internal/akcipher.h>
148c2ecf20Sopenharmony_ci#include <crypto/internal/rsa.h>
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
178c2ecf20Sopenharmony_ci#include <linux/atomic.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <uapi/linux/virtio_crypto.h>
208c2ecf20Sopenharmony_ci#include "virtio_crypto_common.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct virtio_crypto_rsa_ctx {
238c2ecf20Sopenharmony_ci	MPI n;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct virtio_crypto_akcipher_ctx {
278c2ecf20Sopenharmony_ci	struct crypto_engine_ctx enginectx;
288c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto;
298c2ecf20Sopenharmony_ci	struct crypto_akcipher *tfm;
308c2ecf20Sopenharmony_ci	bool session_valid;
318c2ecf20Sopenharmony_ci	__u64 session_id;
328c2ecf20Sopenharmony_ci	union {
338c2ecf20Sopenharmony_ci		struct virtio_crypto_rsa_ctx rsa_ctx;
348c2ecf20Sopenharmony_ci	};
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct virtio_crypto_akcipher_request {
388c2ecf20Sopenharmony_ci	struct virtio_crypto_request base;
398c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *akcipher_ctx;
408c2ecf20Sopenharmony_ci	struct akcipher_request *akcipher_req;
418c2ecf20Sopenharmony_ci	void *src_buf;
428c2ecf20Sopenharmony_ci	void *dst_buf;
438c2ecf20Sopenharmony_ci	uint32_t opcode;
448c2ecf20Sopenharmony_ci};
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistruct virtio_crypto_akcipher_algo {
478c2ecf20Sopenharmony_ci	uint32_t algonum;
488c2ecf20Sopenharmony_ci	uint32_t service;
498c2ecf20Sopenharmony_ci	unsigned int active_devs;
508c2ecf20Sopenharmony_ci	struct akcipher_alg algo;
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(algs_lock);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void virtio_crypto_akcipher_finalize_req(
568c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_request *vc_akcipher_req,
578c2ecf20Sopenharmony_ci	struct akcipher_request *req, int err)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	kfree(vc_akcipher_req->src_buf);
608c2ecf20Sopenharmony_ci	kfree(vc_akcipher_req->dst_buf);
618c2ecf20Sopenharmony_ci	vc_akcipher_req->src_buf = NULL;
628c2ecf20Sopenharmony_ci	vc_akcipher_req->dst_buf = NULL;
638c2ecf20Sopenharmony_ci	virtcrypto_clear_request(&vc_akcipher_req->base);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	crypto_finalize_akcipher_request(vc_akcipher_req->base.dataq->engine, req, err);
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic void virtio_crypto_dataq_akcipher_callback(struct virtio_crypto_request *vc_req, int len)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_request *vc_akcipher_req =
718c2ecf20Sopenharmony_ci		container_of(vc_req, struct virtio_crypto_akcipher_request, base);
728c2ecf20Sopenharmony_ci	struct akcipher_request *akcipher_req;
738c2ecf20Sopenharmony_ci	int error;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	switch (vc_req->status) {
768c2ecf20Sopenharmony_ci	case VIRTIO_CRYPTO_OK:
778c2ecf20Sopenharmony_ci		error = 0;
788c2ecf20Sopenharmony_ci		break;
798c2ecf20Sopenharmony_ci	case VIRTIO_CRYPTO_INVSESS:
808c2ecf20Sopenharmony_ci	case VIRTIO_CRYPTO_ERR:
818c2ecf20Sopenharmony_ci		error = -EINVAL;
828c2ecf20Sopenharmony_ci		break;
838c2ecf20Sopenharmony_ci	case VIRTIO_CRYPTO_BADMSG:
848c2ecf20Sopenharmony_ci		error = -EBADMSG;
858c2ecf20Sopenharmony_ci		break;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	case VIRTIO_CRYPTO_KEY_REJECTED:
888c2ecf20Sopenharmony_ci		error = -EKEYREJECTED;
898c2ecf20Sopenharmony_ci		break;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	default:
928c2ecf20Sopenharmony_ci		error = -EIO;
938c2ecf20Sopenharmony_ci		break;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	akcipher_req = vc_akcipher_req->akcipher_req;
978c2ecf20Sopenharmony_ci	if (vc_akcipher_req->opcode != VIRTIO_CRYPTO_AKCIPHER_VERIFY)
988c2ecf20Sopenharmony_ci		sg_copy_from_buffer(akcipher_req->dst, sg_nents(akcipher_req->dst),
998c2ecf20Sopenharmony_ci				    vc_akcipher_req->dst_buf, akcipher_req->dst_len);
1008c2ecf20Sopenharmony_ci	virtio_crypto_akcipher_finalize_req(vc_akcipher_req, akcipher_req, error);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int virtio_crypto_alg_akcipher_init_session(struct virtio_crypto_akcipher_ctx *ctx,
1048c2ecf20Sopenharmony_ci		struct virtio_crypto_ctrl_header *header, void *para,
1058c2ecf20Sopenharmony_ci		const uint8_t *key, unsigned int keylen)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct scatterlist outhdr_sg, key_sg, inhdr_sg, *sgs[3];
1088c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto = ctx->vcrypto;
1098c2ecf20Sopenharmony_ci	uint8_t *pkey;
1108c2ecf20Sopenharmony_ci	int err;
1118c2ecf20Sopenharmony_ci	unsigned int num_out = 0, num_in = 0;
1128c2ecf20Sopenharmony_ci	struct virtio_crypto_op_ctrl_req *ctrl;
1138c2ecf20Sopenharmony_ci	struct virtio_crypto_session_input *input;
1148c2ecf20Sopenharmony_ci	struct virtio_crypto_ctrl_request *vc_ctrl_req;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	pkey = kmemdup(key, keylen, GFP_ATOMIC);
1178c2ecf20Sopenharmony_ci	if (!pkey)
1188c2ecf20Sopenharmony_ci		return -ENOMEM;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	vc_ctrl_req = kzalloc(sizeof(*vc_ctrl_req), GFP_KERNEL);
1218c2ecf20Sopenharmony_ci	if (!vc_ctrl_req) {
1228c2ecf20Sopenharmony_ci		err = -ENOMEM;
1238c2ecf20Sopenharmony_ci		goto out;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	ctrl = &vc_ctrl_req->ctrl;
1278c2ecf20Sopenharmony_ci	memcpy(&ctrl->header, header, sizeof(ctrl->header));
1288c2ecf20Sopenharmony_ci	memcpy(&ctrl->u, para, sizeof(ctrl->u));
1298c2ecf20Sopenharmony_ci	input = &vc_ctrl_req->input;
1308c2ecf20Sopenharmony_ci	input->status = cpu_to_le32(VIRTIO_CRYPTO_ERR);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	sg_init_one(&outhdr_sg, ctrl, sizeof(*ctrl));
1338c2ecf20Sopenharmony_ci	sgs[num_out++] = &outhdr_sg;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	sg_init_one(&key_sg, pkey, keylen);
1368c2ecf20Sopenharmony_ci	sgs[num_out++] = &key_sg;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	sg_init_one(&inhdr_sg, input, sizeof(*input));
1398c2ecf20Sopenharmony_ci	sgs[num_out + num_in++] = &inhdr_sg;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, num_out, num_in, vc_ctrl_req);
1428c2ecf20Sopenharmony_ci	if (err < 0)
1438c2ecf20Sopenharmony_ci		goto out;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (le32_to_cpu(input->status) != VIRTIO_CRYPTO_OK) {
1468c2ecf20Sopenharmony_ci		pr_err("virtio_crypto: Create session failed status: %u\n",
1478c2ecf20Sopenharmony_ci			le32_to_cpu(input->status));
1488c2ecf20Sopenharmony_ci		err = -EINVAL;
1498c2ecf20Sopenharmony_ci		goto out;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	ctx->session_id = le64_to_cpu(input->session_id);
1538c2ecf20Sopenharmony_ci	ctx->session_valid = true;
1548c2ecf20Sopenharmony_ci	err = 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ciout:
1578c2ecf20Sopenharmony_ci	kfree(vc_ctrl_req);
1588c2ecf20Sopenharmony_ci	kfree_sensitive(pkey);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return err;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int virtio_crypto_alg_akcipher_close_session(struct virtio_crypto_akcipher_ctx *ctx)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct scatterlist outhdr_sg, inhdr_sg, *sgs[2];
1668c2ecf20Sopenharmony_ci	struct virtio_crypto_destroy_session_req *destroy_session;
1678c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto = ctx->vcrypto;
1688c2ecf20Sopenharmony_ci	unsigned int num_out = 0, num_in = 0;
1698c2ecf20Sopenharmony_ci	int err;
1708c2ecf20Sopenharmony_ci	struct virtio_crypto_op_ctrl_req *ctrl;
1718c2ecf20Sopenharmony_ci	struct virtio_crypto_inhdr *ctrl_status;
1728c2ecf20Sopenharmony_ci	struct virtio_crypto_ctrl_request *vc_ctrl_req;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (!ctx->session_valid)
1758c2ecf20Sopenharmony_ci		return 0;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	vc_ctrl_req = kzalloc(sizeof(*vc_ctrl_req), GFP_KERNEL);
1788c2ecf20Sopenharmony_ci	if (!vc_ctrl_req)
1798c2ecf20Sopenharmony_ci		return -ENOMEM;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	ctrl_status = &vc_ctrl_req->ctrl_status;
1828c2ecf20Sopenharmony_ci	ctrl_status->status = VIRTIO_CRYPTO_ERR;
1838c2ecf20Sopenharmony_ci	ctrl = &vc_ctrl_req->ctrl;
1848c2ecf20Sopenharmony_ci	ctrl->header.opcode = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION);
1858c2ecf20Sopenharmony_ci	ctrl->header.queue_id = 0;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	destroy_session = &ctrl->u.destroy_session;
1888c2ecf20Sopenharmony_ci	destroy_session->session_id = cpu_to_le64(ctx->session_id);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	sg_init_one(&outhdr_sg, ctrl, sizeof(*ctrl));
1918c2ecf20Sopenharmony_ci	sgs[num_out++] = &outhdr_sg;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	sg_init_one(&inhdr_sg, &ctrl_status->status, sizeof(ctrl_status->status));
1948c2ecf20Sopenharmony_ci	sgs[num_out + num_in++] = &inhdr_sg;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	err = virtio_crypto_ctrl_vq_request(vcrypto, sgs, num_out, num_in, vc_ctrl_req);
1978c2ecf20Sopenharmony_ci	if (err < 0)
1988c2ecf20Sopenharmony_ci		goto out;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (ctrl_status->status != VIRTIO_CRYPTO_OK) {
2018c2ecf20Sopenharmony_ci		pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n",
2028c2ecf20Sopenharmony_ci			ctrl_status->status, destroy_session->session_id);
2038c2ecf20Sopenharmony_ci		err = -EINVAL;
2048c2ecf20Sopenharmony_ci		goto out;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	err = 0;
2088c2ecf20Sopenharmony_ci	ctx->session_valid = false;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ciout:
2118c2ecf20Sopenharmony_ci	kfree(vc_ctrl_req);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return err;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int __virtio_crypto_akcipher_do_req(struct virtio_crypto_akcipher_request *vc_akcipher_req,
2178c2ecf20Sopenharmony_ci		struct akcipher_request *req, struct data_queue *data_vq)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx;
2208c2ecf20Sopenharmony_ci	struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;
2218c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto = ctx->vcrypto;
2228c2ecf20Sopenharmony_ci	struct virtio_crypto_op_data_req *req_data = vc_req->req_data;
2238c2ecf20Sopenharmony_ci	struct scatterlist *sgs[4], outhdr_sg, inhdr_sg, srcdata_sg, dstdata_sg;
2248c2ecf20Sopenharmony_ci	void *src_buf = NULL, *dst_buf = NULL;
2258c2ecf20Sopenharmony_ci	unsigned int num_out = 0, num_in = 0;
2268c2ecf20Sopenharmony_ci	int node = dev_to_node(&vcrypto->vdev->dev);
2278c2ecf20Sopenharmony_ci	unsigned long flags;
2288c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
2298c2ecf20Sopenharmony_ci	bool verify = vc_akcipher_req->opcode == VIRTIO_CRYPTO_AKCIPHER_VERIFY;
2308c2ecf20Sopenharmony_ci	unsigned int src_len = verify ? req->src_len + req->dst_len : req->src_len;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* out header */
2338c2ecf20Sopenharmony_ci	sg_init_one(&outhdr_sg, req_data, sizeof(*req_data));
2348c2ecf20Sopenharmony_ci	sgs[num_out++] = &outhdr_sg;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	/* src data */
2378c2ecf20Sopenharmony_ci	src_buf = kcalloc_node(src_len, 1, GFP_KERNEL, node);
2388c2ecf20Sopenharmony_ci	if (!src_buf)
2398c2ecf20Sopenharmony_ci		goto err;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	if (verify) {
2428c2ecf20Sopenharmony_ci		/* for verify operation, both src and dst data work as OUT direction */
2438c2ecf20Sopenharmony_ci		sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len);
2448c2ecf20Sopenharmony_ci		sg_init_one(&srcdata_sg, src_buf, src_len);
2458c2ecf20Sopenharmony_ci		sgs[num_out++] = &srcdata_sg;
2468c2ecf20Sopenharmony_ci	} else {
2478c2ecf20Sopenharmony_ci		sg_copy_to_buffer(req->src, sg_nents(req->src), src_buf, src_len);
2488c2ecf20Sopenharmony_ci		sg_init_one(&srcdata_sg, src_buf, src_len);
2498c2ecf20Sopenharmony_ci		sgs[num_out++] = &srcdata_sg;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		/* dst data */
2528c2ecf20Sopenharmony_ci		dst_buf = kcalloc_node(req->dst_len, 1, GFP_KERNEL, node);
2538c2ecf20Sopenharmony_ci		if (!dst_buf)
2548c2ecf20Sopenharmony_ci			goto err;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci		sg_init_one(&dstdata_sg, dst_buf, req->dst_len);
2578c2ecf20Sopenharmony_ci		sgs[num_out + num_in++] = &dstdata_sg;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	vc_akcipher_req->src_buf = src_buf;
2618c2ecf20Sopenharmony_ci	vc_akcipher_req->dst_buf = dst_buf;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* in header */
2648c2ecf20Sopenharmony_ci	sg_init_one(&inhdr_sg, &vc_req->status, sizeof(vc_req->status));
2658c2ecf20Sopenharmony_ci	sgs[num_out + num_in++] = &inhdr_sg;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	spin_lock_irqsave(&data_vq->lock, flags);
2688c2ecf20Sopenharmony_ci	ret = virtqueue_add_sgs(data_vq->vq, sgs, num_out, num_in, vc_req, GFP_ATOMIC);
2698c2ecf20Sopenharmony_ci	virtqueue_kick(data_vq->vq);
2708c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&data_vq->lock, flags);
2718c2ecf20Sopenharmony_ci	if (ret)
2728c2ecf20Sopenharmony_ci		goto err;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return 0;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cierr:
2778c2ecf20Sopenharmony_ci	kfree(src_buf);
2788c2ecf20Sopenharmony_ci	kfree(dst_buf);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return -ENOMEM;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_do_req(struct crypto_engine *engine, void *vreq)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct akcipher_request *req = container_of(vreq, struct akcipher_request, base);
2868c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req);
2878c2ecf20Sopenharmony_ci	struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;
2888c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = vc_akcipher_req->akcipher_ctx;
2898c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto = ctx->vcrypto;
2908c2ecf20Sopenharmony_ci	struct data_queue *data_vq = vc_req->dataq;
2918c2ecf20Sopenharmony_ci	struct virtio_crypto_op_header *header;
2928c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_data_req *akcipher_req;
2938c2ecf20Sopenharmony_ci	int ret;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	vc_req->sgs = NULL;
2968c2ecf20Sopenharmony_ci	vc_req->req_data = kzalloc_node(sizeof(*vc_req->req_data),
2978c2ecf20Sopenharmony_ci		GFP_KERNEL, dev_to_node(&vcrypto->vdev->dev));
2988c2ecf20Sopenharmony_ci	if (!vc_req->req_data)
2998c2ecf20Sopenharmony_ci		return -ENOMEM;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* build request header */
3028c2ecf20Sopenharmony_ci	header = &vc_req->req_data->header;
3038c2ecf20Sopenharmony_ci	header->opcode = cpu_to_le32(vc_akcipher_req->opcode);
3048c2ecf20Sopenharmony_ci	header->algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA);
3058c2ecf20Sopenharmony_ci	header->session_id = cpu_to_le64(ctx->session_id);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	/* build request akcipher data */
3088c2ecf20Sopenharmony_ci	akcipher_req = &vc_req->req_data->u.akcipher_req;
3098c2ecf20Sopenharmony_ci	akcipher_req->para.src_data_len = cpu_to_le32(req->src_len);
3108c2ecf20Sopenharmony_ci	akcipher_req->para.dst_data_len = cpu_to_le32(req->dst_len);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	ret = __virtio_crypto_akcipher_do_req(vc_akcipher_req, req, data_vq);
3138c2ecf20Sopenharmony_ci	if (ret < 0) {
3148c2ecf20Sopenharmony_ci		kfree_sensitive(vc_req->req_data);
3158c2ecf20Sopenharmony_ci		vc_req->req_data = NULL;
3168c2ecf20Sopenharmony_ci		return ret;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_req(struct akcipher_request *req, uint32_t opcode)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct crypto_akcipher *atfm = crypto_akcipher_reqtfm(req);
3258c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(atfm);
3268c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_request *vc_akcipher_req = akcipher_request_ctx(req);
3278c2ecf20Sopenharmony_ci	struct virtio_crypto_request *vc_req = &vc_akcipher_req->base;
3288c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto = ctx->vcrypto;
3298c2ecf20Sopenharmony_ci	/* Use the first data virtqueue as default */
3308c2ecf20Sopenharmony_ci	struct data_queue *data_vq = &vcrypto->data_vq[0];
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	vc_req->dataq = data_vq;
3338c2ecf20Sopenharmony_ci	vc_req->alg_cb = virtio_crypto_dataq_akcipher_callback;
3348c2ecf20Sopenharmony_ci	vc_akcipher_req->akcipher_ctx = ctx;
3358c2ecf20Sopenharmony_ci	vc_akcipher_req->akcipher_req = req;
3368c2ecf20Sopenharmony_ci	vc_akcipher_req->opcode = opcode;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return crypto_transfer_akcipher_request_to_engine(data_vq->engine, req);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_encrypt(struct akcipher_request *req)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_ENCRYPT);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_decrypt(struct akcipher_request *req)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_DECRYPT);
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_sign(struct akcipher_request *req)
3528c2ecf20Sopenharmony_ci{
3538c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_SIGN);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_verify(struct akcipher_request *req)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_req(req, VIRTIO_CRYPTO_AKCIPHER_VERIFY);
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_set_key(struct crypto_akcipher *tfm,
3628c2ecf20Sopenharmony_ci				     const void *key,
3638c2ecf20Sopenharmony_ci				     unsigned int keylen,
3648c2ecf20Sopenharmony_ci				     bool private,
3658c2ecf20Sopenharmony_ci				     int padding_algo,
3668c2ecf20Sopenharmony_ci				     int hash_algo)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
3698c2ecf20Sopenharmony_ci	struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx;
3708c2ecf20Sopenharmony_ci	struct virtio_crypto *vcrypto;
3718c2ecf20Sopenharmony_ci	struct virtio_crypto_ctrl_header header;
3728c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_session_para para;
3738c2ecf20Sopenharmony_ci	struct rsa_key rsa_key = {0};
3748c2ecf20Sopenharmony_ci	int node = virtio_crypto_get_current_node();
3758c2ecf20Sopenharmony_ci	uint32_t keytype;
3768c2ecf20Sopenharmony_ci	int ret;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* mpi_free will test n, just free it. */
3798c2ecf20Sopenharmony_ci	mpi_free(rsa_ctx->n);
3808c2ecf20Sopenharmony_ci	rsa_ctx->n = NULL;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (private) {
3838c2ecf20Sopenharmony_ci		keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
3848c2ecf20Sopenharmony_ci		ret = rsa_parse_priv_key(&rsa_key, key, keylen);
3858c2ecf20Sopenharmony_ci	} else {
3868c2ecf20Sopenharmony_ci		keytype = VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
3878c2ecf20Sopenharmony_ci		ret = rsa_parse_pub_key(&rsa_key, key, keylen);
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	if (ret)
3918c2ecf20Sopenharmony_ci		return ret;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	rsa_ctx->n = mpi_read_raw_data(rsa_key.n, rsa_key.n_sz);
3948c2ecf20Sopenharmony_ci	if (!rsa_ctx->n)
3958c2ecf20Sopenharmony_ci		return -ENOMEM;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (!ctx->vcrypto) {
3988c2ecf20Sopenharmony_ci		vcrypto = virtcrypto_get_dev_node(node, VIRTIO_CRYPTO_SERVICE_AKCIPHER,
3998c2ecf20Sopenharmony_ci						VIRTIO_CRYPTO_AKCIPHER_RSA);
4008c2ecf20Sopenharmony_ci		if (!vcrypto) {
4018c2ecf20Sopenharmony_ci			pr_err("virtio_crypto: Could not find a virtio device in the system or unsupported algo\n");
4028c2ecf20Sopenharmony_ci			return -ENODEV;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		ctx->vcrypto = vcrypto;
4068c2ecf20Sopenharmony_ci	} else {
4078c2ecf20Sopenharmony_ci		virtio_crypto_alg_akcipher_close_session(ctx);
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* set ctrl header */
4118c2ecf20Sopenharmony_ci	header.opcode =	cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION);
4128c2ecf20Sopenharmony_ci	header.algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA);
4138c2ecf20Sopenharmony_ci	header.queue_id = 0;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* set RSA para */
4168c2ecf20Sopenharmony_ci	para.algo = cpu_to_le32(VIRTIO_CRYPTO_AKCIPHER_RSA);
4178c2ecf20Sopenharmony_ci	para.keytype = cpu_to_le32(keytype);
4188c2ecf20Sopenharmony_ci	para.keylen = cpu_to_le32(keylen);
4198c2ecf20Sopenharmony_ci	para.u.rsa.padding_algo = cpu_to_le32(padding_algo);
4208c2ecf20Sopenharmony_ci	para.u.rsa.hash_algo = cpu_to_le32(hash_algo);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return virtio_crypto_alg_akcipher_init_session(ctx, &header, &para, key, keylen);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_raw_set_priv_key(struct crypto_akcipher *tfm,
4268c2ecf20Sopenharmony_ci					      const void *key,
4278c2ecf20Sopenharmony_ci					      unsigned int keylen)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_set_key(tfm, key, keylen, 1,
4308c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_RAW_PADDING,
4318c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_NO_HASH);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int virtio_crypto_p1pad_rsa_sha1_set_priv_key(struct crypto_akcipher *tfm,
4368c2ecf20Sopenharmony_ci						     const void *key,
4378c2ecf20Sopenharmony_ci						     unsigned int keylen)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_set_key(tfm, key, keylen, 1,
4408c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_PKCS1_PADDING,
4418c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_SHA1);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_raw_set_pub_key(struct crypto_akcipher *tfm,
4458c2ecf20Sopenharmony_ci					     const void *key,
4468c2ecf20Sopenharmony_ci					     unsigned int keylen)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_set_key(tfm, key, keylen, 0,
4498c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_RAW_PADDING,
4508c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_NO_HASH);
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic int virtio_crypto_p1pad_rsa_sha1_set_pub_key(struct crypto_akcipher *tfm,
4548c2ecf20Sopenharmony_ci						    const void *key,
4558c2ecf20Sopenharmony_ci						    unsigned int keylen)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	return virtio_crypto_rsa_set_key(tfm, key, keylen, 0,
4588c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_PKCS1_PADDING,
4598c2ecf20Sopenharmony_ci					 VIRTIO_CRYPTO_RSA_SHA1);
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic unsigned int virtio_crypto_rsa_max_size(struct crypto_akcipher *tfm)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
4658c2ecf20Sopenharmony_ci	struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return mpi_get_size(rsa_ctx->n);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int virtio_crypto_rsa_init_tfm(struct crypto_akcipher *tfm)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	ctx->tfm = tfm;
4758c2ecf20Sopenharmony_ci	ctx->enginectx.op.do_one_request = virtio_crypto_rsa_do_req;
4768c2ecf20Sopenharmony_ci	ctx->enginectx.op.prepare_request = NULL;
4778c2ecf20Sopenharmony_ci	ctx->enginectx.op.unprepare_request = NULL;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic void virtio_crypto_rsa_exit_tfm(struct crypto_akcipher *tfm)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct virtio_crypto_akcipher_ctx *ctx = akcipher_tfm_ctx(tfm);
4858c2ecf20Sopenharmony_ci	struct virtio_crypto_rsa_ctx *rsa_ctx = &ctx->rsa_ctx;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	virtio_crypto_alg_akcipher_close_session(ctx);
4888c2ecf20Sopenharmony_ci	virtcrypto_dev_put(ctx->vcrypto);
4898c2ecf20Sopenharmony_ci	mpi_free(rsa_ctx->n);
4908c2ecf20Sopenharmony_ci	rsa_ctx->n = NULL;
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic struct virtio_crypto_akcipher_algo virtio_crypto_akcipher_algs[] = {
4948c2ecf20Sopenharmony_ci	{
4958c2ecf20Sopenharmony_ci		.algonum = VIRTIO_CRYPTO_AKCIPHER_RSA,
4968c2ecf20Sopenharmony_ci		.service = VIRTIO_CRYPTO_SERVICE_AKCIPHER,
4978c2ecf20Sopenharmony_ci		.algo = {
4988c2ecf20Sopenharmony_ci			.encrypt = virtio_crypto_rsa_encrypt,
4998c2ecf20Sopenharmony_ci			.decrypt = virtio_crypto_rsa_decrypt,
5008c2ecf20Sopenharmony_ci			.set_pub_key = virtio_crypto_rsa_raw_set_pub_key,
5018c2ecf20Sopenharmony_ci			.set_priv_key = virtio_crypto_rsa_raw_set_priv_key,
5028c2ecf20Sopenharmony_ci			.max_size = virtio_crypto_rsa_max_size,
5038c2ecf20Sopenharmony_ci			.init = virtio_crypto_rsa_init_tfm,
5048c2ecf20Sopenharmony_ci			.exit = virtio_crypto_rsa_exit_tfm,
5058c2ecf20Sopenharmony_ci			.reqsize = sizeof(struct virtio_crypto_akcipher_request),
5068c2ecf20Sopenharmony_ci			.base = {
5078c2ecf20Sopenharmony_ci				.cra_name = "rsa",
5088c2ecf20Sopenharmony_ci				.cra_driver_name = "virtio-crypto-rsa",
5098c2ecf20Sopenharmony_ci				.cra_priority = 150,
5108c2ecf20Sopenharmony_ci				.cra_module = THIS_MODULE,
5118c2ecf20Sopenharmony_ci				.cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
5128c2ecf20Sopenharmony_ci			},
5138c2ecf20Sopenharmony_ci		},
5148c2ecf20Sopenharmony_ci	},
5158c2ecf20Sopenharmony_ci	{
5168c2ecf20Sopenharmony_ci		.algonum = VIRTIO_CRYPTO_AKCIPHER_RSA,
5178c2ecf20Sopenharmony_ci		.service = VIRTIO_CRYPTO_SERVICE_AKCIPHER,
5188c2ecf20Sopenharmony_ci		.algo = {
5198c2ecf20Sopenharmony_ci			.encrypt = virtio_crypto_rsa_encrypt,
5208c2ecf20Sopenharmony_ci			.decrypt = virtio_crypto_rsa_decrypt,
5218c2ecf20Sopenharmony_ci			.sign = virtio_crypto_rsa_sign,
5228c2ecf20Sopenharmony_ci			.verify = virtio_crypto_rsa_verify,
5238c2ecf20Sopenharmony_ci			.set_pub_key = virtio_crypto_p1pad_rsa_sha1_set_pub_key,
5248c2ecf20Sopenharmony_ci			.set_priv_key = virtio_crypto_p1pad_rsa_sha1_set_priv_key,
5258c2ecf20Sopenharmony_ci			.max_size = virtio_crypto_rsa_max_size,
5268c2ecf20Sopenharmony_ci			.init = virtio_crypto_rsa_init_tfm,
5278c2ecf20Sopenharmony_ci			.exit = virtio_crypto_rsa_exit_tfm,
5288c2ecf20Sopenharmony_ci			.reqsize = sizeof(struct virtio_crypto_akcipher_request),
5298c2ecf20Sopenharmony_ci			.base = {
5308c2ecf20Sopenharmony_ci				.cra_name = "pkcs1pad(rsa,sha1)",
5318c2ecf20Sopenharmony_ci				.cra_driver_name = "virtio-pkcs1-rsa-with-sha1",
5328c2ecf20Sopenharmony_ci				.cra_priority = 150,
5338c2ecf20Sopenharmony_ci				.cra_module = THIS_MODULE,
5348c2ecf20Sopenharmony_ci				.cra_ctxsize = sizeof(struct virtio_crypto_akcipher_ctx),
5358c2ecf20Sopenharmony_ci			},
5368c2ecf20Sopenharmony_ci		},
5378c2ecf20Sopenharmony_ci	},
5388c2ecf20Sopenharmony_ci};
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ciint virtio_crypto_akcipher_algs_register(struct virtio_crypto *vcrypto)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	int ret = 0;
5438c2ecf20Sopenharmony_ci	int i = 0;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	mutex_lock(&algs_lock);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(virtio_crypto_akcipher_algs); i++) {
5488c2ecf20Sopenharmony_ci		uint32_t service = virtio_crypto_akcipher_algs[i].service;
5498c2ecf20Sopenharmony_ci		uint32_t algonum = virtio_crypto_akcipher_algs[i].algonum;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci		if (!virtcrypto_algo_is_supported(vcrypto, service, algonum))
5528c2ecf20Sopenharmony_ci			continue;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci		if (virtio_crypto_akcipher_algs[i].active_devs == 0) {
5558c2ecf20Sopenharmony_ci			ret = crypto_register_akcipher(&virtio_crypto_akcipher_algs[i].algo);
5568c2ecf20Sopenharmony_ci			if (ret)
5578c2ecf20Sopenharmony_ci				goto unlock;
5588c2ecf20Sopenharmony_ci		}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci		virtio_crypto_akcipher_algs[i].active_devs++;
5618c2ecf20Sopenharmony_ci		dev_info(&vcrypto->vdev->dev, "Registered akcipher algo %s\n",
5628c2ecf20Sopenharmony_ci			 virtio_crypto_akcipher_algs[i].algo.base.cra_name);
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ciunlock:
5668c2ecf20Sopenharmony_ci	mutex_unlock(&algs_lock);
5678c2ecf20Sopenharmony_ci	return ret;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_civoid virtio_crypto_akcipher_algs_unregister(struct virtio_crypto *vcrypto)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	int i = 0;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	mutex_lock(&algs_lock);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(virtio_crypto_akcipher_algs); i++) {
5778c2ecf20Sopenharmony_ci		uint32_t service = virtio_crypto_akcipher_algs[i].service;
5788c2ecf20Sopenharmony_ci		uint32_t algonum = virtio_crypto_akcipher_algs[i].algonum;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		if (virtio_crypto_akcipher_algs[i].active_devs == 0 ||
5818c2ecf20Sopenharmony_ci		    !virtcrypto_algo_is_supported(vcrypto, service, algonum))
5828c2ecf20Sopenharmony_ci			continue;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		if (virtio_crypto_akcipher_algs[i].active_devs == 1)
5858c2ecf20Sopenharmony_ci			crypto_unregister_akcipher(&virtio_crypto_akcipher_algs[i].algo);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		virtio_crypto_akcipher_algs[i].active_devs--;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	mutex_unlock(&algs_lock);
5918c2ecf20Sopenharmony_ci}
592