Realize the Symmetric algos session creation handler, including plain cipher and chainning algorithms.
Signed-off-by: Gonglei <arei.gong...@huawei.com> --- hw/virtio/virtio-crypto.c | 172 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index b7a7b41..b3ad974 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -26,8 +26,180 @@ static void virtio_crypto_process(VirtIOCrypto *vcrypto) { } +static inline int virtio_crypto_vq2q(int queue_index) +{ + return queue_index; +} + +static void +virtio_crypto_cipher_session_helper(VirtIODevice *vdev, + CryptoSymSessionInfo *info, + struct virtio_crypto_cipher_session_para *cipher_para, + struct virtio_crypto_cipher_session_output *cipher_out) +{ + hwaddr key_gpa; + void *key_hva; + hwaddr len; + + info->cipher_alg = virtio_ldl_p(vdev, &cipher_para->algo); + info->key_len = virtio_ldl_p(vdev, &cipher_para->keylen); + info->direction = virtio_ldl_p(vdev, &cipher_para->op); + len = info->key_len; + /* get cipher key */ + if (len > 0) { + DPRINTF("keylen=%" PRIu32 "\n", info->key_len); + key_gpa = virtio_ldq_p(vdev, &cipher_out->key_addr); + + key_hva = cpu_physical_memory_map(key_gpa, &len, 0); + + info->cipher_key = g_malloc(info->key_len); + memcpy(info->cipher_key, key_hva, info->key_len); + cpu_physical_memory_unmap(key_hva, len, 0, len); + } +} + +static int64_t +virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto, + struct virtio_crypto_sym_create_session_req *sess_req, + uint32_t queue_id, + uint64_t *session_id) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto); + CryptoSymSessionInfo info; + int ret; + CryptoClientState *cc; + int queue_index;; + uint32_t op_type; + hwaddr auth_key_gpa; + void *auth_key_hva; + struct virtio_crypto_session_input *input; + hwaddr len; + + op_type = virtio_ldl_p(vdev, &sess_req->op_type); + info.op_type = op_type; + + if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { + virtio_crypto_cipher_session_helper(vdev, &info, + &sess_req->u.cipher.para, + &sess_req->u.cipher.out); + input = &sess_req->u.cipher.input; + } else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) { + /* cipher part */ + virtio_crypto_cipher_session_helper(vdev, &info, + &sess_req->u.chain.para.cipher_param, + &sess_req->u.chain.out.cipher); + input = &sess_req->u.chain.input; + /* hash part */ + info.alg_chain_order = virtio_ldl_p(vdev, + &sess_req->u.chain.para.alg_chain_order); + info.add_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.aad_len); + info.hash_mode = virtio_ldl_p(vdev, &sess_req->u.chain.para.hash_mode); + if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) { + info.hash_alg = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.mac_param.algo); + len = info.auth_key_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.mac_param.auth_key_len); + info.hash_result_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.mac_param.hash_result_len); + /* get auth key */ + if (len > 0) { + DPRINTF("keylen=%" PRIu32 "\n", info.auth_key_len); + auth_key_gpa = virtio_ldq_p(vdev, + &sess_req->u.chain.out.mac.auth_key_addr); + auth_key_hva = cpu_physical_memory_map(auth_key_gpa, + &len, false); + info.auth_key = g_malloc(len); + memcpy(info.auth_key, auth_key_hva, len); + cpu_physical_memory_unmap(auth_key_hva, len, false, len); + } + } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) { + info.hash_alg = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.hash_param.algo); + info.hash_result_len = virtio_ldl_p(vdev, + &sess_req->u.chain.para.u.hash_param.hash_result_len); + } else { + /* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */ + error_report("unsupported hash mode"); + goto err; + } + } else { + /* VIRTIO_CRYPTO_SYM_OP_NONE */ + error_report("unsupported cipher type"); + goto err; + } + + queue_index = virtio_crypto_vq2q(queue_id); + cc = qemu_get_crypto_subqueue(vcrypto->crypto, queue_index); + ret = qemu_crypto_create_session(cc, &info, session_id); + if (ret == 0) { + DPRINTF("create session_id=%" PRIu64 "\n", *session_id); + /* Set the result, notify the frontend driver soon */ + virtio_stl_p(vdev, &input->status, VIRTIO_CRYPTO_OP_OK); + virtio_stq_p(vdev, &input->session_id, *session_id); + return 0; + } + +err: + virtio_stl_p(vdev, &input->status, VIRTIO_CRYPTO_OP_ERR); + return -1; +} + static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) { + VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); + struct virtio_crypto_op_ctrl_req ctrl; + VirtQueueElement *elem; + size_t s; + struct iovec *iov; + unsigned int iov_cnt; + uint32_t queue_id; + uint32_t opcode; + uint64_t session_id = 0; + + for (;;) { + elem = virtqueue_pop(vq, sizeof(VirtQueueElement)); + if (!elem) { + break; + } + if (elem->in_num < 1 || + iov_size(elem->in_sg, elem->in_num) < sizeof(ctrl)) { + error_report("virtio-crypto ctrl missing headers"); + exit(1); + } + + iov_cnt = elem->in_num; + iov = elem->in_sg; + s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl)); + assert(s == sizeof(ctrl)); + opcode = virtio_ldl_p(vdev, &ctrl.header.opcode); + queue_id = virtio_ldl_p(vdev, &ctrl.header.queue_id); + + switch (opcode) { + case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION: + virtio_crypto_create_sym_session(vcrypto, + &ctrl.u.sym_create_session, + queue_id, + &session_id); + + break; + case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION: + case VIRTIO_CRYPTO_HASH_CREATE_SESSION: + case VIRTIO_CRYPTO_HASH_DESTROY_SESSION: + case VIRTIO_CRYPTO_MAC_CREATE_SESSION: + case VIRTIO_CRYPTO_MAC_DESTROY_SESSION: + case VIRTIO_CRYPTO_AEAD_CREATE_SESSION: + case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION: + default: + error_report("virtio-crypto unsupported ctrl opcode: %u", + opcode); + exit(1); + } + + virtqueue_push(vq, elem, sizeof(ctrl)); + virtio_notify(vdev, vq); + g_free(elem); + } } static void virtio_crypto_handle_dataq_bh(VirtIODevice *vdev, VirtQueue *vq) -- 1.7.12.4