mirror of https://github.com/xemu-project/xemu.git
cryptodev: introduce a new cryptodev backend
The new cryptodev backend named cryptodev-builtin, which realized by QEMU cipher APIs. These APIs can be backed by either nettle or gcrypt. Signed-off-by: Gonglei <arei.gonglei@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
5551e3a88e
commit
1653a5f3fc
|
@ -11,3 +11,4 @@ common-obj-y += hostmem.o hostmem-ram.o
|
|||
common-obj-$(CONFIG_LINUX) += hostmem-file.o
|
||||
|
||||
common-obj-y += cryptodev.o
|
||||
common-obj-y += cryptodev-builtin.o
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* QEMU Cryptodev backend for QEMU cipher APIs
|
||||
*
|
||||
* Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
|
||||
*
|
||||
* Authors:
|
||||
* Gonglei <arei.gonglei@huawei.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/cryptodev.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/error.h"
|
||||
#include "standard-headers/linux/virtio_crypto.h"
|
||||
#include "crypto/cipher.h"
|
||||
|
||||
|
||||
/**
|
||||
* @TYPE_CRYPTODEV_BACKEND_BUILTIN:
|
||||
* name of backend that uses QEMU cipher API
|
||||
*/
|
||||
#define TYPE_CRYPTODEV_BACKEND_BUILTIN "cryptodev-backend-builtin"
|
||||
|
||||
#define CRYPTODEV_BACKEND_BUILTIN(obj) \
|
||||
OBJECT_CHECK(CryptoDevBackendBuiltin, \
|
||||
(obj), TYPE_CRYPTODEV_BACKEND_BUILTIN)
|
||||
|
||||
typedef struct CryptoDevBackendBuiltin
|
||||
CryptoDevBackendBuiltin;
|
||||
|
||||
typedef struct CryptoDevBackendBuiltinSession {
|
||||
QCryptoCipher *cipher;
|
||||
uint8_t direction; /* encryption or decryption */
|
||||
uint8_t type; /* cipher? hash? aead? */
|
||||
QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
|
||||
} CryptoDevBackendBuiltinSession;
|
||||
|
||||
/* Max number of symmetric sessions */
|
||||
#define MAX_NUM_SESSIONS 256
|
||||
|
||||
#define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512
|
||||
#define CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN 64
|
||||
|
||||
struct CryptoDevBackendBuiltin {
|
||||
CryptoDevBackend parent_obj;
|
||||
|
||||
CryptoDevBackendBuiltinSession *sessions[MAX_NUM_SESSIONS];
|
||||
};
|
||||
|
||||
static void cryptodev_builtin_init(
|
||||
CryptoDevBackend *backend, Error **errp)
|
||||
{
|
||||
/* Only support one queue */
|
||||
int queues = backend->conf.peers.queues;
|
||||
CryptoDevBackendClient *cc;
|
||||
|
||||
if (queues != 1) {
|
||||
error_setg(errp,
|
||||
"Only support one queue in cryptdov-builtin backend");
|
||||
return;
|
||||
}
|
||||
|
||||
cc = cryptodev_backend_new_client(
|
||||
"cryptodev-builtin", NULL);
|
||||
cc->info_str = g_strdup_printf("cryptodev-builtin0");
|
||||
cc->queue_index = 0;
|
||||
backend->conf.peers.ccs[0] = cc;
|
||||
|
||||
backend->conf.crypto_services =
|
||||
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
|
||||
1u << VIRTIO_CRYPTO_SERVICE_HASH |
|
||||
1u << VIRTIO_CRYPTO_SERVICE_MAC;
|
||||
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
|
||||
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
|
||||
/*
|
||||
* Set the Maximum length of crypto request.
|
||||
* Why this value? Just avoid to overflow when
|
||||
* memory allocation for each crypto request.
|
||||
*/
|
||||
backend->conf.max_size = LONG_MAX - sizeof(CryptoDevBackendSymOpInfo);
|
||||
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
|
||||
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;
|
||||
}
|
||||
|
||||
static int
|
||||
cryptodev_builtin_get_unused_session_index(
|
||||
CryptoDevBackendBuiltin *builtin)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_NUM_SESSIONS; i++) {
|
||||
if (builtin->sessions[i] == NULL) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
cryptodev_builtin_get_aes_algo(uint32_t key_len, Error **errp)
|
||||
{
|
||||
int algo;
|
||||
|
||||
if (key_len == 128 / 8) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_128;
|
||||
} else if (key_len == 192 / 8) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_192;
|
||||
} else if (key_len == 256 / 8) {
|
||||
algo = QCRYPTO_CIPHER_ALG_AES_256;
|
||||
} else {
|
||||
error_setg(errp, "Unsupported key length :%u", key_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return algo;
|
||||
}
|
||||
|
||||
static int cryptodev_builtin_create_cipher_session(
|
||||
CryptoDevBackendBuiltin *builtin,
|
||||
CryptoDevBackendSymSessionInfo *sess_info,
|
||||
Error **errp)
|
||||
{
|
||||
int algo;
|
||||
int mode;
|
||||
QCryptoCipher *cipher;
|
||||
int index;
|
||||
CryptoDevBackendBuiltinSession *sess;
|
||||
|
||||
if (sess_info->op_type != VIRTIO_CRYPTO_SYM_OP_CIPHER) {
|
||||
error_setg(errp, "Unsupported optype :%u", sess_info->op_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
index = cryptodev_builtin_get_unused_session_index(builtin);
|
||||
if (index < 0) {
|
||||
error_setg(errp, "Total number of sessions created exceeds %u",
|
||||
MAX_NUM_SESSIONS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (sess_info->cipher_alg) {
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_ECB:
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_CBC:
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_CBC;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_AES_CTR:
|
||||
algo = cryptodev_builtin_get_aes_algo(sess_info->key_len,
|
||||
errp);
|
||||
if (algo < 0) {
|
||||
return -1;
|
||||
}
|
||||
mode = QCRYPTO_CIPHER_MODE_CTR;
|
||||
break;
|
||||
case VIRTIO_CRYPTO_CIPHER_DES_ECB:
|
||||
algo = QCRYPTO_CIPHER_ALG_DES_RFB;
|
||||
mode = QCRYPTO_CIPHER_MODE_ECB;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Unsupported cipher alg :%u",
|
||||
sess_info->cipher_alg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cipher = qcrypto_cipher_new(algo, mode,
|
||||
sess_info->cipher_key,
|
||||
sess_info->key_len,
|
||||
errp);
|
||||
if (!cipher) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sess = g_new0(CryptoDevBackendBuiltinSession, 1);
|
||||
sess->cipher = cipher;
|
||||
sess->direction = sess_info->direction;
|
||||
sess->type = sess_info->op_type;
|
||||
|
||||
builtin->sessions[index] = sess;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int64_t cryptodev_builtin_sym_create_session(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendSymSessionInfo *sess_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
int64_t session_id = -1;
|
||||
int ret;
|
||||
|
||||
switch (sess_info->op_code) {
|
||||
case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
|
||||
ret = cryptodev_builtin_create_cipher_session(
|
||||
builtin, sess_info, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else {
|
||||
session_id = ret;
|
||||
}
|
||||
break;
|
||||
case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
|
||||
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
|
||||
default:
|
||||
error_setg(errp, "Unsupported opcode :%" PRIu32 "",
|
||||
sess_info->op_code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return session_id;
|
||||
}
|
||||
|
||||
static int cryptodev_builtin_sym_close_session(
|
||||
CryptoDevBackend *backend,
|
||||
uint64_t session_id,
|
||||
uint32_t queue_index, Error **errp)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
|
||||
if (session_id >= MAX_NUM_SESSIONS ||
|
||||
builtin->sessions[session_id] == NULL) {
|
||||
error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
|
||||
session_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qcrypto_cipher_free(builtin->sessions[session_id]->cipher);
|
||||
g_free(builtin->sessions[session_id]);
|
||||
builtin->sessions[session_id] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cryptodev_builtin_sym_operation(
|
||||
CryptoDevBackend *backend,
|
||||
CryptoDevBackendSymOpInfo *op_info,
|
||||
uint32_t queue_index, Error **errp)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
CryptoDevBackendBuiltinSession *sess;
|
||||
int ret;
|
||||
|
||||
if (op_info->session_id >= MAX_NUM_SESSIONS ||
|
||||
builtin->sessions[op_info->session_id] == NULL) {
|
||||
error_setg(errp, "Cannot find a valid session id: %" PRIu64 "",
|
||||
op_info->session_id);
|
||||
return -VIRTIO_CRYPTO_INVSESS;
|
||||
}
|
||||
|
||||
if (op_info->op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
|
||||
error_setg(errp,
|
||||
"Algorithm chain is unsupported for cryptdoev-builtin");
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
|
||||
sess = builtin->sessions[op_info->session_id];
|
||||
|
||||
ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
|
||||
op_info->iv_len, errp);
|
||||
if (ret < 0) {
|
||||
return -VIRTIO_CRYPTO_ERR;
|
||||
}
|
||||
|
||||
if (sess->direction == VIRTIO_CRYPTO_OP_ENCRYPT) {
|
||||
ret = qcrypto_cipher_encrypt(sess->cipher, op_info->src,
|
||||
op_info->dst, op_info->src_len, errp);
|
||||
if (ret < 0) {
|
||||
return -VIRTIO_CRYPTO_ERR;
|
||||
}
|
||||
} else {
|
||||
ret = qcrypto_cipher_decrypt(sess->cipher, op_info->src,
|
||||
op_info->dst, op_info->src_len, errp);
|
||||
if (ret < 0) {
|
||||
return -VIRTIO_CRYPTO_ERR;
|
||||
}
|
||||
}
|
||||
return VIRTIO_CRYPTO_OK;
|
||||
}
|
||||
|
||||
static void cryptodev_builtin_cleanup(
|
||||
CryptoDevBackend *backend,
|
||||
Error **errp)
|
||||
{
|
||||
CryptoDevBackendBuiltin *builtin =
|
||||
CRYPTODEV_BACKEND_BUILTIN(backend);
|
||||
size_t i;
|
||||
int queues = backend->conf.peers.queues;
|
||||
CryptoDevBackendClient *cc;
|
||||
|
||||
for (i = 0; i < MAX_NUM_SESSIONS; i++) {
|
||||
if (builtin->sessions[i] != NULL) {
|
||||
cryptodev_builtin_sym_close_session(
|
||||
backend, i, 0, errp);
|
||||
}
|
||||
}
|
||||
|
||||
assert(queues == 1);
|
||||
|
||||
for (i = 0; i < queues; i++) {
|
||||
cc = backend->conf.peers.ccs[i];
|
||||
if (cc) {
|
||||
cryptodev_backend_free_client(cc);
|
||||
backend->conf.peers.ccs[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cryptodev_builtin_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc);
|
||||
|
||||
bc->init = cryptodev_builtin_init;
|
||||
bc->cleanup = cryptodev_builtin_cleanup;
|
||||
bc->create_session = cryptodev_builtin_sym_create_session;
|
||||
bc->close_session = cryptodev_builtin_sym_close_session;
|
||||
bc->do_sym_op = cryptodev_builtin_sym_operation;
|
||||
}
|
||||
|
||||
static const TypeInfo cryptodev_builtin_info = {
|
||||
.name = TYPE_CRYPTODEV_BACKEND_BUILTIN,
|
||||
.parent = TYPE_CRYPTODEV_BACKEND,
|
||||
.class_init = cryptodev_builtin_class_init,
|
||||
.instance_size = sizeof(CryptoDevBackendBuiltin),
|
||||
};
|
||||
|
||||
static void
|
||||
cryptodev_builtin_register_types(void)
|
||||
{
|
||||
type_register_static(&cryptodev_builtin_info);
|
||||
}
|
||||
|
||||
type_init(cryptodev_builtin_register_types);
|
|
@ -3948,6 +3948,24 @@ secondary:
|
|||
If you want to know the detail of above command line, you can read
|
||||
the colo-compare git log.
|
||||
|
||||
@item -object cryptodev-backend-builtin,id=@var{id}[,queues=@var{queues}]
|
||||
|
||||
Creates a cryptodev backend which executes crypto opreation from
|
||||
the QEMU cipher APIS. The @var{id} parameter is
|
||||
a unique ID that will be used to reference this cryptodev backend from
|
||||
the @option{virtio-crypto} device. The @var{queues} parameter is optional,
|
||||
which specify the queue number of cryptodev backend, the default of
|
||||
@var{queues} is 1.
|
||||
|
||||
@example
|
||||
|
||||
# qemu-system-x86_64 \
|
||||
[...] \
|
||||
-object cryptodev-backend-builtin,id=cryptodev0 \
|
||||
-device virtio-crypto-pci,id=crypto0,cryptodev=cryptodev0 \
|
||||
[...]
|
||||
@end example
|
||||
|
||||
@item -object secret,id=@var{id},data=@var{string},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}]
|
||||
@item -object secret,id=@var{id},file=@var{filename},format=@var{raw|base64}[,keyid=@var{secretid},iv=@var{string}]
|
||||
|
||||
|
|
Loading…
Reference in New Issue