From patchwork Thu Sep 8 03:42:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gonglei (Arei)" X-Patchwork-Id: 9320341 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2CAEF60231 for ; Thu, 8 Sep 2016 03:44:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1554029554 for ; Thu, 8 Sep 2016 03:44:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 094E429556; Thu, 8 Sep 2016 03:44:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 1FA3D29554 for ; Thu, 8 Sep 2016 03:44:28 +0000 (UTC) Received: from localhost ([::1]:44741 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bhqGJ-00029v-94 for patchwork-qemu-devel@patchwork.kernel.org; Wed, 07 Sep 2016 23:44:27 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:55942) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bhqFe-00025y-TJ for qemu-devel@nongnu.org; Wed, 07 Sep 2016 23:43:53 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bhqFb-0005VR-EO for qemu-devel@nongnu.org; Wed, 07 Sep 2016 23:43:46 -0400 Received: from szxga03-in.huawei.com ([119.145.14.66]:5666) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bhqFZ-0005Ux-Uu for qemu-devel@nongnu.org; Wed, 07 Sep 2016 23:43:43 -0400 Received: from 172.24.1.60 (EHLO szxeml432-hub.china.huawei.com) ([172.24.1.60]) by szxrg03-dlp.huawei.com (MOS 4.4.3-GA FastPath queued) with ESMTP id CHM27370; Thu, 08 Sep 2016 11:43:05 +0800 (CST) Received: from localhost (10.177.18.62) by szxeml432-hub.china.huawei.com (10.82.67.209) with Microsoft SMTP Server id 14.3.235.1; Thu, 8 Sep 2016 11:42:54 +0800 From: Gonglei To: , Date: Thu, 8 Sep 2016 11:42:27 +0800 Message-ID: <1473306156-176628-6-git-send-email-arei.gonglei@huawei.com> X-Mailer: git-send-email 2.6.3.windows.1 In-Reply-To: <1473306156-176628-1-git-send-email-arei.gonglei@huawei.com> References: <1473306156-176628-1-git-send-email-arei.gonglei@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.177.18.62] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020206.57D0DE49.0163, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2013-05-26 15:14:31, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: d9465343273a0da3e2355c24cc9855d8 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] X-Received-From: 119.145.14.66 Subject: [Qemu-devel] [PATCH v1 05/14] crypto: add cryptodev-linux as a cryptodev backend X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: weidong.huang@huawei.com, mst@redhat.com, john.griffin@intel.com, jianjay.zhou@huawei.com, Varun.Sethi@freescale.com, denglingli@chinamobile.com, hanweidong@huawei.com, agraf@suse.de, Gonglei , nmorey@kalray.eu, vincent.jardin@6wind.com, Ola.Liljedahl@arm.com, luonengjun@huawei.com, xin.zeng@intel.com, peter.huangpeng@huawei.com, liang.j.ma@intel.com, stefanha@redhat.com, cornelia.huck@de.ibm.com, Jani.Kokkonen@huawei.com, brian.a.keating@intel.com, claudio.fontana@huawei.com, mike.caraman@nxp.com Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Cryptodev-linux is a device that allows access to Linux kernel cryptographic drivers; thus allowing of userspace applications to take advantage of hardware accelerators. Cryptodev-linux is implemented as a standalone module that requires no dependencies other than a stock linux kernel. The Cryptodev-linux project website is: http://cryptodev-linux.org/ Meanwile, I introdue the virtio_crypto.h which follows virtio-crypto specification bacause cryptodev-linux.c include it. Signed-off-by: Gonglei --- configure | 16 + crypto/Makefile.objs | 1 + crypto/crypto.c | 8 +- crypto/cryptodev-linux.c | 419 +++++++++++++++++++++++ include/crypto/crypto-clients.h | 39 +++ include/standard-headers/linux/virtio_crypto.h | 448 +++++++++++++++++++++++++ qapi-schema.json | 17 +- qemu-options.hx | 18 +- 8 files changed, 963 insertions(+), 3 deletions(-) create mode 100644 crypto/cryptodev-linux.c create mode 100644 include/crypto/crypto-clients.h create mode 100644 include/standard-headers/linux/virtio_crypto.h diff --git a/configure b/configure index 5a9bda1..0fbead7 100755 --- a/configure +++ b/configure @@ -320,6 +320,7 @@ vhdx="" numa="" tcmalloc="no" jemalloc="no" +cryptodev_linux="no" # parse CC options first for opt do @@ -3616,6 +3617,16 @@ EOF fi ########################################## +# cryptodev-linux header probe +cat > $TMPC << EOF +#include +int main(void) { return 0; } +EOF +if compile_prog "" "" ; then + cryptodev_linux="yes" +fi + +########################################## # signalfd probe signalfd="no" cat > $TMPC << EOF @@ -4920,6 +4931,7 @@ echo "NUMA host support $numa" echo "tcmalloc support $tcmalloc" echo "jemalloc support $jemalloc" echo "avx2 optimization $avx2_opt" +echo "cryptodev-linux support $cryptodev_linux" if test "$sdl_too_old" = "yes"; then echo "-> Your SDL version is too old - please upgrade to have SDL support" @@ -5321,6 +5333,10 @@ if test "$avx2_opt" = "yes" ; then echo "CONFIG_AVX2_OPT=y" >> $config_host_mak fi +if test "$cryptodev_linux" = "yes" ; then + echo "CONFIG_CRYPTODEV_LINUX=y" >> $config_host_mak +fi + if test "$lzo" = "yes" ; then echo "CONFIG_LZO=y" >> $config_host_mak fi diff --git a/crypto/Makefile.objs b/crypto/Makefile.objs index 652b429..1f2ec24 100644 --- a/crypto/Makefile.objs +++ b/crypto/Makefile.objs @@ -28,6 +28,7 @@ crypto-obj-y += block-qcow.o crypto-obj-y += block-luks.o crypto-obj-y += crypto.o crypto-obj-y += crypto-queue.o +crypto-obj-$(CONFIG_CRYPTODEV_LINUX) += cryptodev-linux.o # Let the userspace emulators avoid linking gnutls/etc crypto-aes-obj-y = aes.o diff --git a/crypto/crypto.c b/crypto/crypto.c index 958a959..1d3d1d3 100644 --- a/crypto/crypto.c +++ b/crypto/crypto.c @@ -34,6 +34,7 @@ #include "crypto/crypto.h" #include "qemu/config-file.h" #include "monitor/monitor.h" +#include "crypto/crypto-clients.h" static QTAILQ_HEAD(, CryptoClientState) crypto_clients; @@ -81,7 +82,12 @@ int crypto_init_clients(void) static int (* const crypto_client_init_fun[CRYPTO_CLIENT_OPTIONS_KIND__MAX])( const CryptoClientOptions *opts, const char *name, - CryptoClientState *peer, Error **errp); + CryptoClientState *peer, Error **errp) = { +#ifdef CONFIG_CRYPTODEV_LINUX + [CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX] = + crypto_init_cryptodev_linux, +#endif +}; static int crypto_client_init1(const void *object, Error **errp) { diff --git a/crypto/cryptodev-linux.c b/crypto/cryptodev-linux.c new file mode 100644 index 0000000..ae2dcdb --- /dev/null +++ b/crypto/cryptodev-linux.c @@ -0,0 +1,419 @@ +/* + * cryptodev-linux backend support + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Gonglei + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#include +#include +#include + +#include "qemu/osdep.h" +#include "sysemu/sysemu.h" +#include "qapi/error.h" +#include "qemu/iov.h" +#include "qapi-visit.h" +#include "qapi/opts-visitor.h" +#include "qemu/error-report.h" + +#include "crypto/crypto.h" +#include "crypto/crypto-clients.h" +#include "standard-headers/linux/virtio_crypto.h" + + +#define CRYPTO_CHARDEV_PATH "/dev/crypto" + + +typedef struct CryptodevLinuxSession { + struct session_op *sess; + uint8_t direction; /* encryption or decryption */ + uint8_t type; /* cipher? hash? aead? */ + QTAILQ_ENTRY(CryptodevLinuxSession) next; +} CryptodevLinuxSession; + +typedef struct CryptodevLinuxState { + CryptoClientState cc; + int fd; + bool read_poll; + bool write_poll; + bool enabled; + QTAILQ_HEAD(, CryptodevLinuxSession) sessions; +} CryptodevLinuxState; + +static int +cryptodev_linux_open(int *gfd, Error **errp) +{ + int fd = -1; + + /* Open the crypto device */ + fd = open(CRYPTO_CHARDEV_PATH, O_RDWR, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "Cannot open %s", + CRYPTO_CHARDEV_PATH); + return -1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(fd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + error_setg_errno(errp, errno, + "Failed to fcntl(F_SETFD) %s", + CRYPTO_CHARDEV_PATH); + close(fd); + return -1; + } + + *gfd = fd; + + return 0; +} + +static int +cryptodev_linux_handle_cipher_sess(CryptodevLinuxState *s, + CryptoSymSessionInfo *session_info, + struct session_op *sess, + uint8_t *direction) +{ + switch (session_info->cipher_alg) { + case VIRTIO_CRYPTO_CIPHER_AES_CBC: + sess->cipher = CRYPTO_AES_CBC; + break; + default: + error_report("Unsupported cipher alg: %u", + session_info->cipher_alg); + return -1; + } + /* Get crypto session for assinged algorithm */ + sess->keylen = session_info->key_len; + sess->key = session_info->cipher_key; + *direction = session_info->direction; + return 0; +} + +static int +cryptodev_linux_handle_hash_sess(CryptodevLinuxState *s, + CryptoSymSessionInfo *session_info, + struct session_op *sess) +{ + switch (session_info->hash_alg) { + case VIRTIO_CRYPTO_HASH_SHA1: + sess->mac = CRYPTO_SHA1_HMAC; + break; + default: + error_report("Unsupported hash alg: %u", + session_info->hash_alg); + return -1; + } + + sess->mackeylen = session_info->auth_key_len; + sess->mackey = session_info->auth_key; + return 0; +} + +static int +cryptodev_linux_handle_chaining_sess(CryptodevLinuxState *s, + CryptoSymSessionInfo *session_info, + struct session_op *sess, + uint8_t *direction) +{ + int ret; + + ret = cryptodev_linux_handle_cipher_sess(s, session_info, + sess, direction); + if (ret == 0) { + ret = cryptodev_linux_handle_hash_sess(s, + session_info, sess); + } + return ret; +} + +static int +cryptodev_linux_create_session(CryptoClientState *cc, + CryptoSymSessionInfo *session_info, + uint64_t *session_id) +{ + CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc); + int fd = s->fd; + int ret = -1; + CryptodevLinuxSession *session = NULL; + uint8_t direction = 0; + struct session_op *sess; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + sess = g_new0(struct session_op, 1); + /* Setup session Parameters */ + switch (session_info->op_type) { + case VIRTIO_CRYPTO_SYM_OP_CIPHER: + ret = cryptodev_linux_handle_cipher_sess(s, session_info, + sess, &direction); + if (ret < 0) { + goto err; + } + break; + case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING: + ret = cryptodev_linux_handle_chaining_sess(s, session_info, + sess, &direction); + if (ret < 0) { + goto err; + } + break; + default: + error_report("Unsupported type: %u", session_info->op_type); + goto err; + } + + if (ioctl(fd, CIOCGSESSION, sess)) { + perror("ioctl(CIOCGSESSION)"); + ret = -1; + goto err; + } + +#ifdef CIOCGSESSINFO + siop.ses = sess->ses; + if (ioctl(fd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + ret = -1; + goto err; + } + printf("got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); +#endif + + *session_id = sess->ses; + + session = g_new0(CryptodevLinuxSession, 1); + session->sess = sess; + session->type = session_info->op_type; + switch (direction) { + case VIRTIO_CRYPTO_OP_ENCRYPT: + session->direction = COP_ENCRYPT; + break; + case VIRTIO_CRYPTO_OP_DECRYPT: + session->direction = COP_DECRYPT; + break; + default: + error_report("Unsupported direction: %u", direction); + goto err; + } + + QTAILQ_INSERT_TAIL(&s->sessions, session, next); + + return 0; +err: + g_free(sess); + g_free(session); + return ret; +} + +static CryptodevLinuxSession * +cryptodev_linux_find_session(CryptodevLinuxState *s, + uint64_t session_id) +{ + CryptodevLinuxSession *session, *tmp; + + QTAILQ_FOREACH_SAFE(session, &s->sessions, next, tmp) { + if (session->sess->ses == session_id) { + return session; + } + } + + return NULL; +} + +static int +cryptodev_linux_close_session(CryptoClientState *cc, + uint64_t session_id) +{ + CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc); + int fd = s->fd; + CryptodevLinuxSession *session; + + session = cryptodev_linux_find_session(s, session_id); + if (session == NULL) { + error_report("Cannot find the session: %" PRIu64 "", + session_id); + return -1; + } + + if (ioctl(fd, CIOCFSESSION, &session_id)) { + perror("ioctl(CIOCFSESSION)"); + return -1; + } + + QTAILQ_REMOVE(&s->sessions, session, next); + g_free(session->sess); + g_free(session); + return 0; +} + +static int +cryptodev_linux_handle_cipher_op(CryptoSymOpInfo *op_info, + CryptodevLinuxSession *session, + int fd) +{ + struct crypt_op cryp; + + cryp.ses = op_info->session_id; + cryp.len = op_info->src_len; + cryp.src = op_info->src; + cryp.dst = op_info->dst; + cryp.iv = op_info->iv; + cryp.op = session->direction; + + if (ioctl(fd, CIOCCRYPT, &cryp)) { + perror("ioctl(CIOCCRYPT)"); + return -1; + } + + return 1; +} + +static int +cryptodev_linux_handle_chaining_op(CryptoSymOpInfo *op_info, + CryptodevLinuxSession *session, + int fd) +{ + struct crypt_auth_op cao; + + cao.ses = op_info->session_id; + cao.len = op_info->src_len; + cao.src = op_info->src; + cao.dst = op_info->dst; + cao.iv = op_info->iv; + cao.op = session->direction; + + if (op_info->aad_len > 0) { + cao.auth_len = op_info->aad_len; + cao.auth_src = op_info->aad_data; + } + + /* We only support TLS mode at present, the hash result is + stored at the end of cipher text, the frontend driver + should allocate enough memory. */ + cao.flags = COP_FLAG_AEAD_TLS_TYPE; + + if (ioctl(fd, CIOCAUTHCRYPT, &cao)) { + perror("ioctl(CIOCCRYPT)"); + return -1; + } + + return 1; +} + + +static int +cryptodev_linux_do_sym_op(CryptoClientState *cc, + CryptoSymOpInfo *op_info) +{ + CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc); + CryptodevLinuxSession *session; + + session = cryptodev_linux_find_session(s, op_info->session_id); + if (session == NULL) { + error_report("Cannot find the session: %" PRIu64 "", + op_info->session_id); + return -VIRTIO_CRYPTO_OP_INVSESS; + } + + switch (session->type) { + case VIRTIO_CRYPTO_SYM_OP_CIPHER: + return cryptodev_linux_handle_cipher_op(op_info, session, s->fd); + case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING: + return cryptodev_linux_handle_chaining_op(op_info, session, s->fd); + default: + error_report("Unsupported type: %u", session->type); + return -1; + } +} + +static void +cryptodev_linux_cleanup(CryptoClientState *cc) +{ + CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc); + CryptodevLinuxSession *session; + uint64_t session_id; + + QTAILQ_FOREACH(session, &s->sessions, next) { + session_id = session->sess->ses; + if (ioctl(s->fd, CIOCFSESSION, &session_id)) { + perror("ioctl(CIOCFSESSION)"); + } + g_free(session->sess); + g_free(session); + } + + close(s->fd); + s->fd = -1; + s->enabled = false; +} + +static void +cryptodev_linux_poll(CryptoClientState *cc, bool enable) +{ + +} + +static CryptoClientInfo crypto_cryptodev_info = { + .type = CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX, + .size = sizeof(CryptodevLinuxState), + .create_session = cryptodev_linux_create_session, + .close_session = cryptodev_linux_close_session, + .do_sym_op = cryptodev_linux_do_sym_op, + .cleanup = cryptodev_linux_cleanup, + .poll = cryptodev_linux_poll, +}; + +int crypto_init_cryptodev_linux(const CryptoClientOptions *opts, + const char *name, + CryptoClientState *peer, Error **errp) +{ + const CryptodevLinuxOptions *cryptodev; + int fd, ret; + CryptoClientState *cc; + CryptodevLinuxState *s; + + assert(opts->type == CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX); + + cryptodev = opts->u.cryptodev_linux.data; + if (cryptodev->has_fd) { + if (cryptodev->fd < 0) { + error_setg(errp, "Invaild fd: %" PRId64 "", cryptodev->fd); + return -1; + } else { + fd = cryptodev->fd; + } + } else { + ret = cryptodev_linux_open(&fd, errp); + if (ret < 0) { + return -1; + } + } + + cc = new_crypto_client(&crypto_cryptodev_info, peer, + "cryptodev-linux", name); + + cc->crypto_services = 1u << VIRTIO_CRYPTO_SERVICE_CIPHER | + 1u << VIRTIO_CRYPTO_SERVICE_HASH | + 1u << VIRTIO_CRYPTO_SERVICE_AEAD; + cc->cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC; + cc->hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1; + + /* the cryptodev backend is ready for work */ + cc->ready = true; + s = DO_UPCAST(CryptodevLinuxState, cc, cc); + + s->fd = fd; + s->enabled = true; + QTAILQ_INIT(&s->sessions); + + return 0; +} diff --git a/include/crypto/crypto-clients.h b/include/crypto/crypto-clients.h new file mode 100644 index 0000000..dea5748 --- /dev/null +++ b/include/crypto/crypto-clients.h @@ -0,0 +1,39 @@ +/* + * Crypto clients header + * + * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * Authors: + * Gonglei + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef QEMU_CRYPTO_CLIENTS_H +#define QEMU_CRYPTO_CLIENTS_H + +#include "crypto/crypto.h" +#include "qapi-types.h" + +#ifdef CONFIG_CRYPTODEV_LINUX +int crypto_init_cryptodev_linux(const CryptoClientOptions *opts, + const char *name, + CryptoClientState *peer, Error **errp); +#endif + +#endif /* QEMU_CRYPTO_CLIENTS_H */ diff --git a/include/standard-headers/linux/virtio_crypto.h b/include/standard-headers/linux/virtio_crypto.h new file mode 100644 index 0000000..443b2a8 --- /dev/null +++ b/include/standard-headers/linux/virtio_crypto.h @@ -0,0 +1,448 @@ +#ifndef _VIRTIO_CRYPTO_H +#define _VIRTIO_CRYPTO_H + +#include "standard-headers/linux/types.h" +#include "standard-headers/linux/virtio_config.h" +#include "standard-headers/linux/virtio_types.h" + + +#define VIRTIO_CRYPTO_SERVICE_CIPHER (0) +#define VIRTIO_CRYPTO_SERVICE_HASH (1) +#define VIRTIO_CRYPTO_SERVICE_MAC (2) +#define VIRTIO_CRYPTO_SERVICE_AEAD (3) + +#define VIRTIO_CRYPTO_OPCODE(service, op) ((service << 8) | (op)) + +struct virtio_crypto_ctrl_header{ +#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x02) +#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x03) +#define VIRTIO_CRYPTO_HASH_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x02) +#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x03) +#define VIRTIO_CRYPTO_MAC_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x02) +#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x03) +#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02) +#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03) + __virtio32 opcode; + __virtio32 algo; + __virtio32 flag; + /* data virtqueue id */ + __virtio32 queue_id; +}; + +struct virtio_crypto_cipher_session_para { +#define VIRTIO_CRYPTO_NO_CIPHER 0 +#define VIRTIO_CRYPTO_CIPHER_ARC4 1 +#define VIRTIO_CRYPTO_CIPHER_AES_ECB 2 +#define VIRTIO_CRYPTO_CIPHER_AES_CBC 3 +#define VIRTIO_CRYPTO_CIPHER_AES_CTR 4 +#define VIRTIO_CRYPTO_CIPHER_DES_ECB 5 +#define VIRTIO_CRYPTO_CIPHER_DES_CBC 6 +#define VIRTIO_CRYPTO_CIPHER_3DES_ECB 7 +#define VIRTIO_CRYPTO_CIPHER_3DES_CBC 8 +#define VIRTIO_CRYPTO_CIPHER_3DES_CTR 9 +#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8 10 +#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2 11 +#define VIRTIO_CRYPTO_CIPHER_AES_F8 12 +#define VIRTIO_CRYPTO_CIPHER_AES_XTS 13 +#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3 14 + __virtio32 algo; + /* length of key */ + __virtio32 keylen; + +#define VIRTIO_CRYPTO_OP_ENCRYPT 1 +#define VIRTIO_CRYPTO_OP_DECRYPT 2 + /* encrypt or decrypt */ + __virtio32 op; + __virtio32 padding; +}; + +struct virtio_crypto_session_input { + // Device-writable part + __virtio64 session_id; + __virtio32 status; + __virtio32 padding; +}; + +struct virtio_crypto_cipher_session_output { + __virtio64 key_addr; /* guest key phycial address */ +}; + +struct virtio_crypto_cipher_session_req { + struct virtio_crypto_cipher_session_para para; + struct virtio_crypto_cipher_session_output out; + struct virtio_crypto_session_input input; +}; + +struct virtio_crypto_hash_session_para { +#define VIRTIO_CRYPTO_NO_HASH 0 +#define VIRTIO_CRYPTO_HASH_MD5 1 +#define VIRTIO_CRYPTO_HASH_SHA1 2 +#define VIRTIO_CRYPTO_HASH_SHA_224 3 +#define VIRTIO_CRYPTO_HASH_SHA_256 4 +#define VIRTIO_CRYPTO_HASH_SHA_384 5 +#define VIRTIO_CRYPTO_HASH_SHA_512 6 +#define VIRTIO_CRYPTO_HASH_SHA3_224 7 +#define VIRTIO_CRYPTO_HASH_SHA3_256 8 +#define VIRTIO_CRYPTO_HASH_SHA3_384 9 +#define VIRTIO_CRYPTO_HASH_SHA3_512 10 +#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128 11 +#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256 12 + __virtio32 algo; + /* hash result length */ + __virtio32 hash_result_len; +}; + +struct virtio_crypto_hash_create_session_req { + struct virtio_crypto_hash_session_para para; + struct virtio_crypto_session_input input; +}; + +struct virtio_crypto_mac_session_para { +#define VIRTIO_CRYPTO_NO_MAC 0 +#define VIRTIO_CRYPTO_MAC_HMAC_MD5 1 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA1 2 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224 3 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256 4 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384 5 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512 6 +#define VIRTIO_CRYPTO_MAC_CMAC_3DES 25 +#define VIRTIO_CRYPTO_MAC_CMAC_AES 26 +#define VIRTIO_CRYPTO_MAC_KASUMI_F9 27 +#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2 28 +#define VIRTIO_CRYPTO_MAC_GMAC_AES 41 +#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH 42 +#define VIRTIO_CRYPTO_MAC_CBCMAC_AES 49 +#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 50 +#define VIRTIO_CRYPTO_MAC_XCBC_AES 53 + __virtio32 algo; + /* hash result length */ + __virtio32 hash_result_len; + /* length of authenticated key */ + __virtio32 auth_key_len; + __virtio32 padding; +}; + +struct virtio_crypto_mac_session_output { + __virtio64 auth_key_addr; /* guest key phyical address */ +}; + +struct virtio_crypto_mac_create_session_req { + struct virtio_crypto_mac_session_para para; + struct virtio_crypto_mac_session_output out; + struct virtio_crypto_session_input input; +}; + +struct virtio_crypto_aead_session_para { +#define VIRTIO_CRYPTO_NO_AEAD 0 +#define VIRTIO_CRYPTO_AEAD_GCM 1 +#define VIRTIO_CRYPTO_AEAD_CCM 2 +#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305 3 + __virtio32 algo; + /* length of key */ + __virtio32 key_len; + /* digest result length */ + __virtio32 digest_result_len; + /* length of the additional authenticated data (AAD) in bytes */ + __virtio32 aad_len; + /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */ + __virtio32 op; + __virtio32 padding; +}; + +struct virtio_crypto_aead_session_output { + __virtio64 key_addr; /* guest key phycial address */ +}; + +struct virtio_crypto_aead_create_session_req { + struct virtio_crypto_aead_session_para para; + struct virtio_crypto_aead_session_output out; + struct virtio_crypto_session_input input; +}; + +struct virtio_crypto_alg_chain_session_para { +#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1 +#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2 + __virtio32 alg_chain_order; +/* Plain hash */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN 1 +/* Authenticated hash (mac) */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH 2 +/* Nested hash */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED 3 + __virtio32 hash_mode; + struct virtio_crypto_cipher_session_para cipher_param; + union { + struct virtio_crypto_hash_session_para hash_param; + struct virtio_crypto_mac_session_para mac_param; + } u; + /* length of the additional authenticated data (AAD) in bytes */ + __virtio32 aad_len; + __virtio32 padding; +}; + +struct virtio_crypto_alg_chain_session_output { + struct virtio_crypto_cipher_session_output cipher; + struct virtio_crypto_mac_session_output mac; +}; + +struct virtio_crypto_alg_chain_session_req { + struct virtio_crypto_alg_chain_session_para para; + struct virtio_crypto_alg_chain_session_output out; + struct virtio_crypto_session_input input; +}; + +struct virtio_crypto_sym_create_session_req { + union { + struct virtio_crypto_cipher_session_req cipher; + struct virtio_crypto_alg_chain_session_req chain; + } u; + + // Device-readable part + +/* No operation */ +#define VIRTIO_CRYPTO_SYM_OP_NONE 0 +/* Cipher only operation on the data */ +#define VIRTIO_CRYPTO_SYM_OP_CIPHER 1 +/* Chain any cipher with any hash or mac operation. The order + depends on the value of alg_chain_order param */ +#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING 2 + __virtio32 op_type; + __virtio32 padding; +}; + +struct virtio_crypto_destroy_session_req { + // Device-readable part + __virtio64 session_id; + // Device-writable part + __virtio32 status; + __virtio32 padding; +}; + +/* The request of the control viritqueue's packet */ +struct virtio_crypto_op_ctrl_req { + struct virtio_crypto_ctrl_header header; + + union { + struct virtio_crypto_sym_create_session_req sym_create_session; + struct virtio_crypto_hash_create_session_req hash_create_session; + struct virtio_crypto_mac_create_session_req mac_create_session; + struct virtio_crypto_aead_create_session_req aead_create_session; + struct virtio_crypto_destroy_session_req destroy_session; + } u; +}; + +struct virtio_crypto_op_header { +#define VIRTIO_CRYPTO_CIPHER_ENCRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x00) +#define VIRTIO_CRYPTO_CIPHER_DECRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x01) +#define VIRTIO_CRYPTO_HASH \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x00) +#define VIRTIO_CRYPTO_MAC \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x00) +#define VIRTIO_CRYPTO_AEAD_ENCRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00) +#define VIRTIO_CRYPTO_AEAD_DECRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01) + __virtio32 opcode; + /* algo should be service-specific algorithms */ + __virtio32 algo; + /* session_id should be service-specific algorithms */ + __virtio64 session_id; + /* control flag to control the request */ + __virtio32 flag; + __virtio32 padding; +}; + +struct virtio_crypto_sym_input { + /* destination data guest address, it's useless for plain HASH and MAC */ + __virtio64 dst_data_addr; + /* digest result guest address, it's useless for plain cipher algos */ + __virtio64 digest_result_addr; + + __virtio32 status; + __virtio32 padding; +}; + +struct virtio_crypto_cipher_para { + __virtio32 iv_len; + /* length of source data */ + __virtio32 src_data_len; + /* length of dst data */ + __virtio32 dst_data_len; + __virtio32 padding; +}; + +struct virtio_crypto_cipher_input { + struct virtio_crypto_sym_input input; +}; + +struct virtio_crypto_cipher_output { + __virtio64 iv_addr; /* iv guest address */ + __virtio64 src_data_addr; /* source data guest address */ +}; + +struct virtio_crypto_hash_input { + struct virtio_crypto_sym_input input; +}; + +struct virtio_crypto_hash_output { + /* source data guest address */ + __virtio64 src_data_addr; + /* length of source data */ + __virtio32 src_data_len; + __virtio32 padding; +}; + +struct virtio_crypto_mac_input { + struct virtio_crypto_sym_input input; +}; + +struct virtio_crypto_mac_output { + struct virtio_crypto_hash_output hash_output; +}; + +struct virtio_crypto_aead_para { + __virtio32 iv_len; + /* length of additional auth data */ + __virtio32 aad_len; + /* length of source data */ + __virtio32 src_data_len; + /* length of dst data */ + __virtio32 dst_data_len; +}; + +struct virtio_crypto_aead_input { + struct virtio_crypto_sym_input input; +}; + +struct virtio_crypto_aead_output { + __virtio64 iv_addr; /* iv guest address */ + __virtio64 src_data_addr; /* source data guest address */ + __virtio64 add_data_addr; /* additional auth data guest address */ +}; + +struct virtio_crypto_cipher_data_req { + // Device-readable part + struct virtio_crypto_cipher_para para; + struct virtio_crypto_cipher_output odata; + // Device-writable part + struct virtio_crypto_cipher_input idata; +}; + +struct virtio_crypto_hash_data_req { + // Device-readable part + struct virtio_crypto_hash_output odata; + // Device-writable part + struct virtio_crypto_hash_input idata; +}; + +struct virtio_crypto_mac_data_req { + // Device-readable part + struct virtio_crypto_mac_output odata; + // Device-writable part + struct virtio_crypto_mac_input idata; +}; + +struct virtio_crypto_alg_chain_data_para { + struct virtio_crypto_cipher_para cipher; +}; + +struct virtio_crypto_alg_chain_data_output { + struct virtio_crypto_cipher_output cipher; + + // Device-readable part + __virtio64 aad_data_addr; /* additional auth data guest address */ + __virtio32 aad_len; /* length of additional auth data */ + __virtio32 padding; +}; + +struct virtio_crypto_alg_chain_data_input { + struct virtio_crypto_sym_input input; +}; + +struct virtio_crypto_alg_chain_data_req { + // Device-readable part + struct virtio_crypto_alg_chain_data_para para; + struct virtio_crypto_alg_chain_data_output odata; + // Device-writable part + struct virtio_crypto_alg_chain_data_input idata; +}; + +struct virtio_crypto_sym_data_req { + union { + struct virtio_crypto_cipher_data_req cipher; + struct virtio_crypto_alg_chain_data_req chain; + } u; + + // Device-readable part + + /* See above VIRTIO_CRYPTO_SYM_OP_* */ + __virtio32 op_type; + __virtio32 padding; +}; + +struct virtio_crypto_aead_data_req { + // Device-readable part + struct virtio_crypto_aead_para para; + struct virtio_crypto_aead_output odata; + // Device-writable part + struct virtio_crypto_aead_input idata; +}; + +/* The request of the data viritqueue's packet */ +struct virtio_crypto_op_data_req { + struct virtio_crypto_op_header header; + + union { + struct virtio_crypto_sym_data_req sym_req; + struct virtio_crypto_hash_data_req hash_req; + struct virtio_crypto_mac_data_req mac_req; + struct virtio_crypto_aead_data_req aead_req; + } u; +}; + +#define VIRTIO_CRYPTO_OP_OK 0 +#define VIRTIO_CRYPTO_OP_ERR 1 +#define VIRTIO_CRYPTO_OP_BADMSG 2 +#define VIRTIO_CRYPTO_OP_NOTSUPP 3 +#define VIRTIO_CRYPTO_OP_INVSESS 4 /* Invaild session id */ + +/* The accelerator hardware is ready */ +#define VIRTIO_CRYPTO_S_HW_READY (1 << 0) +#define VIRTIO_CRYPTO_S_STARTED (1 << 1) + +struct virtio_crypto_config { + /* See VIRTIO_CRYPTO_OP_* above */ + __virtio32 status; + + /* + * Maximum number of data queue legal values are between 1 and 0x8000 + */ + __virtio32 max_dataqueues; + + /* Specifies the services mask which the devcie support, + see VIRTIO_CRYPTO_SERVICE_* above */ + __virtio32 crypto_services; + + /* Detailed algorithms mask */ + __virtio32 cipher_algo_l; + __virtio32 cipher_algo_h; + __virtio32 hash_algo; + __virtio32 mac_algo_l; + __virtio32 mac_algo_h; + __virtio32 asym_algo; + __virtio32 kdf_algo; + __virtio32 aead_algo; + __virtio32 primitive_algo; +}; + +#endif diff --git a/qapi-schema.json b/qapi-schema.json index 1b411b6..0330964 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -4603,6 +4603,20 @@ '*vectors': 'uint32' } } ## +# @CryptodevLinuxOptions +# +# Cryptodev-linux cryptodev backend. Cryptodev-linux is a device that +# allows access to Linux kernel cryptographic drivers; thus allowing +# of userspace applications to take advantage of hardware accelerators. +# +# @fd: #optional file descriptor of an already opened cryptodev chardev +# +# Since 2.7 +## +{ 'struct': 'CryptodevLinuxOptions', + 'data': { + '*fd': 'int' } } +## # @CryptoClientOptions # # A discriminated record of crypto device traits. @@ -4611,7 +4625,8 @@ # ## { 'union': 'CryptoClientOptions', - 'data': {'legacy-hw': 'CryptoLegacyHWOptions'} } + 'data': {'legacy-hw': 'CryptoLegacyHWOptions', + 'cryptodev-linux': 'CryptodevLinuxOptions'} } ## # @Cryptodev diff --git a/qemu-options.hx b/qemu-options.hx index a64ce25..0f7c662 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3969,9 +3969,25 @@ contents of @code{iv.b64} to the second secret ETEXI DEF("cryptodev", HAS_ARG, QEMU_OPTION_cryptodev, - "", + "-cryptodev cryptodev-linux,id=str[,fd=h]\n" + " configure a cryptodev-linux cryptodev backend with ID 'str'\n" + " use 'fd=h' to connect to an already opened '/dev/crypto' fd\n", QEMU_ARCH_ALL) +STEXI +@item -cryptodev cryptodev-linux,id=@var{id}[,fd=@var{h}] +configure a cryptodev backend with ID @var{id}. + +Example: +@example +#launch a QEMU instance with one virtio-crypto device, +#which connected a cryptodev-linux backend device. +qemu-system-x86_64 linux.img -cryptodev cryptodev-linux,id=cryptodev0 \ + -device virtio-crypto-pci,cryptodev=cryptodev0 + +@end example +ETEXI + HXCOMM This is the last statement. Insert new options before this line! STEXI @end table