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, ¶, 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