2022-03-23 12:58:50

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v3 0/6] Support akcipher for virtio-crypto

v2 -> v3:
- Introduce akcipher types to qapi
- Add test/benchmark suite for akcipher class
- Seperate 'virtio_crypto: Support virtio crypto asym operation' into:
- crypto: Introduce akcipher crypto class
- virtio-crypto: Introduce RSA algorithm

v1 -> v2:
- Update virtio_crypto.h from v2 version of related kernel patch.

v1:
- Support akcipher for virtio-crypto.
- Introduce akcipher class.
- Introduce ASN1 decoder into QEMU.
- Implement RSA backend by nettle/hogweed.

Lei He (3):
crypto-akcipher: Introduce akcipher types to qapi
crypto: Implement RSA algorithm by hogweed
tests/crypto: Add test suite for crypto akcipher

Zhenwei Pi (3):
virtio-crypto: header update
crypto: Introduce akcipher crypto class
virtio-crypto: Introduce RSA algorithm

backends/cryptodev-builtin.c | 319 +++++++-
backends/cryptodev-vhost-user.c | 34 +-
backends/cryptodev.c | 32 +-
crypto/akcipher-nettle.c | 523 +++++++++++++
crypto/akcipher.c | 81 ++
crypto/asn1_decoder.c | 185 +++++
crypto/asn1_decoder.h | 42 +
crypto/meson.build | 4 +
hw/virtio/virtio-crypto.c | 326 ++++++--
include/crypto/akcipher.h | 155 ++++
include/hw/virtio/virtio-crypto.h | 5 +-
.../standard-headers/linux/virtio_crypto.h | 82 +-
include/sysemu/cryptodev.h | 88 ++-
meson.build | 11 +
qapi/crypto.json | 86 +++
tests/bench/benchmark-crypto-akcipher.c | 163 ++++
tests/bench/meson.build | 6 +
tests/bench/test_akcipher_keys.inc | 277 +++++++
tests/unit/meson.build | 1 +
tests/unit/test-crypto-akcipher.c | 715 ++++++++++++++++++
20 files changed, 2990 insertions(+), 145 deletions(-)
create mode 100644 crypto/akcipher-nettle.c
create mode 100644 crypto/akcipher.c
create mode 100644 crypto/asn1_decoder.c
create mode 100644 crypto/asn1_decoder.h
create mode 100644 include/crypto/akcipher.h
create mode 100644 tests/bench/benchmark-crypto-akcipher.c
create mode 100644 tests/bench/test_akcipher_keys.inc
create mode 100644 tests/unit/test-crypto-akcipher.c

--
2.25.1


2022-03-23 14:10:39

by Philippe Mathieu-Daudé

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto

Cc'ing Daniel & Laurent.

On 23/3/22 03:49, zhenwei pi wrote:
> v2 -> v3:
> - Introduce akcipher types to qapi
> - Add test/benchmark suite for akcipher class
> - Seperate 'virtio_crypto: Support virtio crypto asym operation' into:
> - crypto: Introduce akcipher crypto class
> - virtio-crypto: Introduce RSA algorithm
>
> v1 -> v2:
> - Update virtio_crypto.h from v2 version of related kernel patch.
>
> v1:
> - Support akcipher for virtio-crypto.
> - Introduce akcipher class.
> - Introduce ASN1 decoder into QEMU.
> - Implement RSA backend by nettle/hogweed.
>
> Lei He (3):
> crypto-akcipher: Introduce akcipher types to qapi
> crypto: Implement RSA algorithm by hogweed
> tests/crypto: Add test suite for crypto akcipher
>
> Zhenwei Pi (3):
> virtio-crypto: header update
> crypto: Introduce akcipher crypto class
> virtio-crypto: Introduce RSA algorithm
>
> backends/cryptodev-builtin.c | 319 +++++++-
> backends/cryptodev-vhost-user.c | 34 +-
> backends/cryptodev.c | 32 +-
> crypto/akcipher-nettle.c | 523 +++++++++++++
> crypto/akcipher.c | 81 ++
> crypto/asn1_decoder.c | 185 +++++
> crypto/asn1_decoder.h | 42 +
> crypto/meson.build | 4 +
> hw/virtio/virtio-crypto.c | 326 ++++++--
> include/crypto/akcipher.h | 155 ++++
> include/hw/virtio/virtio-crypto.h | 5 +-
> .../standard-headers/linux/virtio_crypto.h | 82 +-
> include/sysemu/cryptodev.h | 88 ++-
> meson.build | 11 +
> qapi/crypto.json | 86 +++
> tests/bench/benchmark-crypto-akcipher.c | 163 ++++
> tests/bench/meson.build | 6 +
> tests/bench/test_akcipher_keys.inc | 277 +++++++
> tests/unit/meson.build | 1 +
> tests/unit/test-crypto-akcipher.c | 715 ++++++++++++++++++
> 20 files changed, 2990 insertions(+), 145 deletions(-)
> create mode 100644 crypto/akcipher-nettle.c
> create mode 100644 crypto/akcipher.c
> create mode 100644 crypto/asn1_decoder.c
> create mode 100644 crypto/asn1_decoder.h
> create mode 100644 include/crypto/akcipher.h
> create mode 100644 tests/bench/benchmark-crypto-akcipher.c
> create mode 100644 tests/bench/test_akcipher_keys.inc
> create mode 100644 tests/unit/test-crypto-akcipher.c
>

2022-03-23 14:52:48

by Eric Biggers

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> v2 -> v3:
> - Introduce akcipher types to qapi
> - Add test/benchmark suite for akcipher class
> - Seperate 'virtio_crypto: Support virtio crypto asym operation' into:
> - crypto: Introduce akcipher crypto class
> - virtio-crypto: Introduce RSA algorithm
>
> v1 -> v2:
> - Update virtio_crypto.h from v2 version of related kernel patch.
>
> v1:
> - Support akcipher for virtio-crypto.
> - Introduce akcipher class.
> - Introduce ASN1 decoder into QEMU.
> - Implement RSA backend by nettle/hogweed.
>
> Lei He (3):
> crypto-akcipher: Introduce akcipher types to qapi
> crypto: Implement RSA algorithm by hogweed
> tests/crypto: Add test suite for crypto akcipher
>
> Zhenwei Pi (3):
> virtio-crypto: header update
> crypto: Introduce akcipher crypto class
> virtio-crypto: Introduce RSA algorithm

You forgot to describe the point of this patchset and what its use case is.
Like any other Linux kernel patchset, that needs to be in the cover letter.

- Eric

2022-03-23 16:33:02

by Michael S. Tsirkin

[permalink] [raw]
Subject: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto

On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
> v2 -> v3:
> - Introduce akcipher types to qapi
> - Add test/benchmark suite for akcipher class
> - Seperate 'virtio_crypto: Support virtio crypto asym operation' into:
> - crypto: Introduce akcipher crypto class
> - virtio-crypto: Introduce RSA algorithm

Thanks!
I tagged this but qemu is in freeze. If possible pls ping or
repost after the release to help make sure I don't lose it.

> v1 -> v2:
> - Update virtio_crypto.h from v2 version of related kernel patch.
>
> v1:
> - Support akcipher for virtio-crypto.
> - Introduce akcipher class.
> - Introduce ASN1 decoder into QEMU.
> - Implement RSA backend by nettle/hogweed.
>
> Lei He (3):
> crypto-akcipher: Introduce akcipher types to qapi
> crypto: Implement RSA algorithm by hogweed
> tests/crypto: Add test suite for crypto akcipher
>
> Zhenwei Pi (3):
> virtio-crypto: header update
> crypto: Introduce akcipher crypto class
> virtio-crypto: Introduce RSA algorithm
>
> backends/cryptodev-builtin.c | 319 +++++++-
> backends/cryptodev-vhost-user.c | 34 +-
> backends/cryptodev.c | 32 +-
> crypto/akcipher-nettle.c | 523 +++++++++++++
> crypto/akcipher.c | 81 ++
> crypto/asn1_decoder.c | 185 +++++
> crypto/asn1_decoder.h | 42 +
> crypto/meson.build | 4 +
> hw/virtio/virtio-crypto.c | 326 ++++++--
> include/crypto/akcipher.h | 155 ++++
> include/hw/virtio/virtio-crypto.h | 5 +-
> .../standard-headers/linux/virtio_crypto.h | 82 +-
> include/sysemu/cryptodev.h | 88 ++-
> meson.build | 11 +
> qapi/crypto.json | 86 +++
> tests/bench/benchmark-crypto-akcipher.c | 163 ++++
> tests/bench/meson.build | 6 +
> tests/bench/test_akcipher_keys.inc | 277 +++++++
> tests/unit/meson.build | 1 +
> tests/unit/test-crypto-akcipher.c | 715 ++++++++++++++++++
> 20 files changed, 2990 insertions(+), 145 deletions(-)
> create mode 100644 crypto/akcipher-nettle.c
> create mode 100644 crypto/akcipher.c
> create mode 100644 crypto/asn1_decoder.c
> create mode 100644 crypto/asn1_decoder.h
> create mode 100644 include/crypto/akcipher.h
> create mode 100644 tests/bench/benchmark-crypto-akcipher.c
> create mode 100644 tests/bench/test_akcipher_keys.inc
> create mode 100644 tests/unit/test-crypto-akcipher.c
>
> --
> 2.25.1

2022-03-23 22:55:05

by zhenwei pi

[permalink] [raw]
Subject: Re: Re: [PATCH v3 0/6] Support akcipher for virtio-crypto

On 3/23/22 20:36, Michael S. Tsirkin wrote:
> On Wed, Mar 23, 2022 at 10:49:06AM +0800, zhenwei pi wrote:
>> v2 -> v3:
>> - Introduce akcipher types to qapi
>> - Add test/benchmark suite for akcipher class
>> - Seperate 'virtio_crypto: Support virtio crypto asym operation' into:
>> - crypto: Introduce akcipher crypto class
>> - virtio-crypto: Introduce RSA algorithm
>
> Thanks!
> I tagged this but qemu is in freeze. If possible pls ping or
> repost after the release to help make sure I don't lose it.
>
Hi,

Daniel has started to review this patchset, according to Daniel's
important suggestion, I'll rework this feature and post the next version
later.

Thanks a lot!

--
zhenwei pi

2022-03-24 02:02:42

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v3 6/6] virtio-crypto: Introduce RSA algorithm

There are two parts in this patch:
1, support akcipher service by cryptodev-builtin driver
2, virtio-crypto driver supports akcipher service

Then virtio-crypto gets request from guest side, and forwards the
request to builtin driver to handle it.

Test with a guest linux:
1, The self-test framework of crypto layer works fine in guest kernel
2, Test with Linux guest(with asym support), the following script
test(note that pkey_XXX is supported only in a newer version of keyutils):
- both public key & private key
- create/close session
- encrypt/decrypt/sign/verify basic driver operation
- also test with kernel crypto layer(pkey add/query)

All the cases work fine.

Run script in guest:
rm -rf *.der *.pem *.pfx
modprobe pkcs8_key_parser # if CONFIG_PKCS8_PRIVATE_KEY_PARSER=m
rm -rf /tmp/data
dd if=/dev/random of=/tmp/data count=1 bs=226

openssl req -nodes -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -subj "/C=CN/ST=BJ/L=HD/O=qemu/OU=dev/CN=qemu/[email protected]"
openssl pkcs8 -in key.pem -topk8 -nocrypt -outform DER -out key.der
openssl x509 -in cert.pem -inform PEM -outform DER -out cert.der

PRIV_KEY_ID=`cat key.der | keyctl padd asymmetric test_priv_key @s`
echo "priv key id = "$PRIV_KEY_ID
PUB_KEY_ID=`cat cert.der | keyctl padd asymmetric test_pub_key @s`
echo "pub key id = "$PUB_KEY_ID

keyctl pkey_query $PRIV_KEY_ID 0
keyctl pkey_query $PUB_KEY_ID 0

echo "Enc with priv key..."
keyctl pkey_encrypt $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.priv
echo "Dec with pub key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.priv enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Sign with priv key..."
keyctl pkey_sign $PRIV_KEY_ID 0 /tmp/data enc=pkcs1 hash=sha1 > /tmp/sig
echo "Verify with pub key..."
keyctl pkey_verify $PRIV_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

echo "Enc with pub key..."
keyctl pkey_encrypt $PUB_KEY_ID 0 /tmp/data enc=pkcs1 >/tmp/enc.pub
echo "Dec with priv key..."
keyctl pkey_decrypt $PRIV_KEY_ID 0 /tmp/enc.pub enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec

echo "Verify with pub key..."
keyctl pkey_verify $PUB_KEY_ID 0 /tmp/data /tmp/sig enc=pkcs1 hash=sha1

Co-developed-by: lei he <[email protected]
Signed-off-by: zhenwei pi <[email protected]>
Signed-off-by: lei he <[email protected]
---
backends/cryptodev-builtin.c | 319 +++++++++++++++++++++++++----
backends/cryptodev-vhost-user.c | 34 +++-
backends/cryptodev.c | 32 ++-
hw/virtio/virtio-crypto.c | 326 ++++++++++++++++++++++++------
include/hw/virtio/virtio-crypto.h | 5 +-
include/sysemu/cryptodev.h | 88 ++++++--
6 files changed, 660 insertions(+), 144 deletions(-)

diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c
index 0671bf9f3e..bae12c7068 100644
--- a/backends/cryptodev-builtin.c
+++ b/backends/cryptodev-builtin.c
@@ -26,6 +26,7 @@
#include "qapi/error.h"
#include "standard-headers/linux/virtio_crypto.h"
#include "crypto/cipher.h"
+#include "crypto/akcipher.h"
#include "qom/object.h"


@@ -41,11 +42,12 @@ OBJECT_DECLARE_SIMPLE_TYPE(CryptoDevBackendBuiltin, CRYPTODEV_BACKEND_BUILTIN)
typedef struct CryptoDevBackendBuiltinSession {
QCryptoCipher *cipher;
uint8_t direction; /* encryption or decryption */
- uint8_t type; /* cipher? hash? aead? */
+ uint8_t type; /* cipher? hash? aead? akcipher? */
+ QCryptoAkcipher *akcipher;
QTAILQ_ENTRY(CryptoDevBackendBuiltinSession) next;
} CryptoDevBackendBuiltinSession;

-/* Max number of symmetric sessions */
+/* Max number of symmetric/asymmetric sessions */
#define MAX_NUM_SESSIONS 256

#define CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN 512
@@ -80,15 +82,17 @@ static void cryptodev_builtin_init(
backend->conf.crypto_services =
1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
1u << VIRTIO_CRYPTO_SERVICE_HASH |
- 1u << VIRTIO_CRYPTO_SERVICE_MAC;
+ 1u << VIRTIO_CRYPTO_SERVICE_MAC |
+ 1u << VIRTIO_CRYPTO_SERVICE_AKCIPHER;
backend->conf.cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
backend->conf.hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+ backend->conf.akcipher_algo = 1u << VIRTIO_CRYPTO_AKCIPHER_RSA;
/*
* 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_size = LONG_MAX - sizeof(CryptoDevBackendOpInfo);
backend->conf.max_cipher_key_len = CRYPTODEV_BUITLIN_MAX_CIPHER_KEY_LEN;
backend->conf.max_auth_key_len = CRYPTODEV_BUITLIN_MAX_AUTH_KEY_LEN;

@@ -148,6 +152,100 @@ err:
return -1;
}

+static int cryptodev_builtin_get_rsa_hash_algo(
+ int virtio_rsa_hash, Error **errp)
+{
+ switch (virtio_rsa_hash) {
+ case VIRTIO_CRYPTO_RSA_MD2:
+ return QCRYPTO_RSA_HASH_ALG_MD2;
+
+ case VIRTIO_CRYPTO_RSA_MD3:
+ return QCRYPTO_RSA_HASH_ALG_MD3;
+
+ case VIRTIO_CRYPTO_RSA_MD4:
+ return QCRYPTO_RSA_HASH_ALG_MD4;
+
+ case VIRTIO_CRYPTO_RSA_MD5:
+ return QCRYPTO_RSA_HASH_ALG_MD5;
+
+ case VIRTIO_CRYPTO_RSA_SHA1:
+ return QCRYPTO_RSA_HASH_ALG_SHA1;
+
+ case VIRTIO_CRYPTO_RSA_SHA256:
+ return QCRYPTO_RSA_HASH_ALG_SHA256;
+
+ case VIRTIO_CRYPTO_RSA_SHA384:
+ return QCRYPTO_RSA_HASH_ALG_SHA384;
+
+ case VIRTIO_CRYPTO_RSA_SHA512:
+ return QCRYPTO_RSA_HASH_ALG_SHA512;
+
+ case VIRTIO_CRYPTO_RSA_SHA224:
+ return QCRYPTO_RSA_HASH_ALG_SHA224;
+
+ default:
+ error_setg(errp, "Unsupported rsa hash algo: %d", virtio_rsa_hash);
+ return -1;
+ }
+}
+
+static int cryptodev_builtin_set_rsa_options(
+ int virtio_padding_algo,
+ int virtio_hash_algo,
+ QCryptoRsaOptions *opt,
+ Error **errp)
+{
+ if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_PKCS1_PADDING) {
+ opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_PKCS1;
+ opt->hash_algo =
+ cryptodev_builtin_get_rsa_hash_algo(virtio_hash_algo, errp);
+ if (opt->hash_algo < 0) {
+ return -1;
+ }
+ return 0;
+ }
+
+ if (virtio_padding_algo == VIRTIO_CRYPTO_RSA_RAW_PADDING) {
+ opt->padding_algo = QCRYPTO_RSA_PADDING_ALG_RAW;
+ return 0;
+ }
+
+ error_setg(errp, "Unsupported rsa padding algo: %d", virtio_padding_algo);
+ return -1;
+}
+
+static int cryptodev_builtin_set_ecdsa_options(int virtio_curve_id,
+ QCryptoEcdsaOptions *opt, Error **errp)
+{
+ switch (virtio_curve_id) {
+ case VIRTIO_CRYPTO_CURVE_NIST_P192:
+ opt->curve_id = QCRYPTO_CURVE_ID_NIST_P192;
+ break;
+
+ case VIRTIO_CRYPTO_CURVE_NIST_P224:
+ opt->curve_id = QCRYPTO_CURVE_ID_NIST_P224;
+ break;
+
+ case VIRTIO_CRYPTO_CURVE_NIST_P256:
+ opt->curve_id = QCRYPTO_CURVE_ID_NIST_P256;
+ break;
+
+ case VIRTIO_CRYPTO_CURVE_NIST_P384:
+ opt->curve_id = QCRYPTO_CURVE_ID_NIST_P384;
+ break;
+
+ case VIRTIO_CRYPTO_CURVE_NIST_P521:
+ opt->curve_id = QCRYPTO_CURVE_ID_NIST_P521;
+ break;
+
+ default:
+ error_setg(errp, "Unsupported curve id: %d", virtio_curve_id);
+ return -1;
+ }
+
+ return 0;
+}
+
static int cryptodev_builtin_create_cipher_session(
CryptoDevBackendBuiltin *builtin,
CryptoDevBackendSymSessionInfo *sess_info,
@@ -240,26 +338,100 @@ static int cryptodev_builtin_create_cipher_session(
return index;
}

-static int64_t cryptodev_builtin_sym_create_session(
+static int cryptodev_builtin_create_akcipher_session(
+ CryptoDevBackendBuiltin *builtin,
+ CryptoDevBackendAsymSessionInfo *sess_info,
+ Error **errp)
+{
+ CryptoDevBackendBuiltinSession *sess;
+ QCryptoAkcipher *akcipher;
+ int index;
+ QCryptoAkcipherAlgorithm alg;
+ QCryptoAkcipherKeyType type;
+ QCryptoRsaOptions rsa_opt;
+ QCryptoEcdsaOptions ecdsa_opt;
+ void *opt;
+
+ switch (sess_info->algo) {
+ case VIRTIO_CRYPTO_AKCIPHER_RSA:
+ alg = QCRYPTO_AKCIPHER_ALG_RSA;
+ if (cryptodev_builtin_set_rsa_options(sess_info->u.rsa.padding_algo,
+ sess_info->u.rsa.hash_algo, &rsa_opt, errp) != 0) {
+ return -1;
+ }
+ opt = (void *)&rsa_opt;
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+ alg = QCRYPTO_AKCIPHER_ALG_ECDSA;
+ if (cryptodev_builtin_set_ecdsa_options(sess_info->u.ecdsa.curve_id,
+ &ecdsa_opt, errp) != 0) {
+ return -1;
+ }
+ opt = (void *)&ecdsa_opt;
+ break;
+
+ default:
+ error_setg(errp, "Unsupported akcipher alg %u", sess_info->algo);
+ return -1;
+ }
+
+ switch (sess_info->keytype) {
+ case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
+ type = QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC;
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
+ type = QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE;
+ break;
+
+ default:
+ error_setg(errp, "Unsupported akcipher keytype %u", sess_info->keytype);
+ 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;
+ }
+
+ akcipher = qcrypto_akcipher_new(alg, type, sess_info->key,
+ sess_info->keylen, opt, errp);
+ if (!akcipher) {
+ return -1;
+ }
+
+ sess = g_new0(CryptoDevBackendBuiltinSession, 1);
+ sess->akcipher = akcipher;
+
+ builtin->sessions[index] = sess;
+
+ return index;
+}
+
+static int64_t cryptodev_builtin_create_session(
CryptoDevBackend *backend,
- CryptoDevBackendSymSessionInfo *sess_info,
+ CryptoDevBackendSessionInfo *sess_info,
uint32_t queue_index, Error **errp)
{
CryptoDevBackendBuiltin *builtin =
CRYPTODEV_BACKEND_BUILTIN(backend);
- int64_t session_id = -1;
- int ret;
+ CryptoDevBackendSymSessionInfo *sym_sess_info;
+ CryptoDevBackendAsymSessionInfo *asym_sess_info;

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;
+ sym_sess_info = &sess_info->u.sym_sess_info;
+ return cryptodev_builtin_create_cipher_session(
+ builtin, sym_sess_info, errp);
+
+ case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+ asym_sess_info = &sess_info->u.asym_sess_info;
+ return cryptodev_builtin_create_akcipher_session(
+ builtin, asym_sess_info, errp);
+
case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
default:
@@ -268,10 +440,10 @@ static int64_t cryptodev_builtin_sym_create_session(
return -1;
}

- return session_id;
+ return -1;
}

-static int cryptodev_builtin_sym_close_session(
+static int cryptodev_builtin_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
uint32_t queue_index, Error **errp)
@@ -288,30 +460,17 @@ static int cryptodev_builtin_sym_close_session(
}

static int cryptodev_builtin_sym_operation(
- CryptoDevBackend *backend,
- CryptoDevBackendSymOpInfo *op_info,
- uint32_t queue_index, Error **errp)
+ CryptoDevBackendBuiltinSession *sess,
+ CryptoDevBackendSymOpInfo *op_info, 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];
-
if (op_info->iv_len > 0) {
ret = qcrypto_cipher_setiv(sess->cipher, op_info->iv,
op_info->iv_len, errp);
@@ -333,9 +492,95 @@ static int cryptodev_builtin_sym_operation(
return -VIRTIO_CRYPTO_ERR;
}
}
+
+ return VIRTIO_CRYPTO_OK;
+}
+
+static int cryptodev_builtin_asym_operation(
+ CryptoDevBackendBuiltinSession *sess, uint32_t op_code,
+ CryptoDevBackendAsymOpInfo *op_info, Error **errp)
+{
+ int ret;
+
+ switch (op_code) {
+ case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+ ret = qcrypto_akcipher_encrypt(sess->akcipher,
+ op_info->src, op_info->src_len,
+ op_info->dst, op_info->dst_len, errp);
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+ ret = qcrypto_akcipher_decrypt(sess->akcipher,
+ op_info->src, op_info->src_len,
+ op_info->dst, op_info->dst_len, errp);
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+ ret = qcrypto_akcipher_sign(sess->akcipher,
+ op_info->src, op_info->src_len,
+ op_info->dst, op_info->dst_len, errp);
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+ ret = qcrypto_akcipher_verify(sess->akcipher,
+ op_info->src, op_info->src_len,
+ op_info->dst, op_info->dst_len, errp);
+ break;
+
+ default:
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ if (ret < 0) {
+ if (op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+ return -VIRTIO_CRYPTO_KEY_REJECTED;
+ }
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ /* Buffer is too short */
+ if (unlikely(ret > op_info->dst_len)) {
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ op_info->dst_len = ret;
+
return VIRTIO_CRYPTO_OK;
}

+static int cryptodev_builtin_operation(
+ CryptoDevBackend *backend,
+ CryptoDevBackendOpInfo *op_info,
+ uint32_t queue_index, Error **errp)
+{
+ CryptoDevBackendBuiltin *builtin =
+ CRYPTODEV_BACKEND_BUILTIN(backend);
+ CryptoDevBackendBuiltinSession *sess;
+ CryptoDevBackendSymOpInfo *sym_op_info;
+ CryptoDevBackendAsymOpInfo *asym_op_info;
+ enum CryptoDevBackendAlgType algtype = op_info->algtype;
+ int ret = -VIRTIO_CRYPTO_ERR;
+
+ 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;
+ }
+
+ sess = builtin->sessions[op_info->session_id];
+ if (algtype == CRYPTODEV_BACKEND_ALG_SYM) {
+ sym_op_info = op_info->u.sym_op_info;
+ ret = cryptodev_builtin_sym_operation(sess, sym_op_info, errp);
+ } else if (algtype == CRYPTODEV_BACKEND_ALG_ASYM) {
+ asym_op_info = op_info->u.asym_op_info;
+ ret = cryptodev_builtin_asym_operation(sess, op_info->op_code,
+ asym_op_info, errp);
+ }
+
+ return ret;
+}
+
static void cryptodev_builtin_cleanup(
CryptoDevBackend *backend,
Error **errp)
@@ -348,7 +593,7 @@ static void cryptodev_builtin_cleanup(

for (i = 0; i < MAX_NUM_SESSIONS; i++) {
if (builtin->sessions[i] != NULL) {
- cryptodev_builtin_sym_close_session(backend, i, 0, &error_abort);
+ cryptodev_builtin_close_session(backend, i, 0, &error_abort);
}
}

@@ -370,9 +615,9 @@ cryptodev_builtin_class_init(ObjectClass *oc, void *data)

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;
+ bc->create_session = cryptodev_builtin_create_session;
+ bc->close_session = cryptodev_builtin_close_session;
+ bc->do_op = cryptodev_builtin_operation;
}

static const TypeInfo cryptodev_builtin_info = {
diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c
index bedb452474..5443a59153 100644
--- a/backends/cryptodev-vhost-user.c
+++ b/backends/cryptodev-vhost-user.c
@@ -259,7 +259,33 @@ static int64_t cryptodev_vhost_user_sym_create_session(
return -1;
}

-static int cryptodev_vhost_user_sym_close_session(
+static int64_t cryptodev_vhost_user_create_session(
+ CryptoDevBackend *backend,
+ CryptoDevBackendSessionInfo *sess_info,
+ uint32_t queue_index, Error **errp)
+{
+ uint32_t op_code = sess_info->op_code;
+ CryptoDevBackendSymSessionInfo *sym_sess_info;
+
+ switch (op_code) {
+ case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
+ case VIRTIO_CRYPTO_HASH_CREATE_SESSION:
+ case VIRTIO_CRYPTO_MAC_CREATE_SESSION:
+ case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
+ sym_sess_info = &sess_info->u.sym_sess_info;
+ return cryptodev_vhost_user_sym_create_session(backend, sym_sess_info,
+ queue_index, errp);
+ default:
+ error_setg(errp, "Unsupported opcode :%" PRIu32 "",
+ sess_info->op_code);
+ return -1;
+
+ }
+
+ return -1;
+}
+
+static int cryptodev_vhost_user_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
uint32_t queue_index, Error **errp)
@@ -351,9 +377,9 @@ cryptodev_vhost_user_class_init(ObjectClass *oc, void *data)

bc->init = cryptodev_vhost_user_init;
bc->cleanup = cryptodev_vhost_user_cleanup;
- bc->create_session = cryptodev_vhost_user_sym_create_session;
- bc->close_session = cryptodev_vhost_user_sym_close_session;
- bc->do_sym_op = NULL;
+ bc->create_session = cryptodev_vhost_user_create_session;
+ bc->close_session = cryptodev_vhost_user_close_session;
+ bc->do_op = NULL;

object_class_property_add_str(oc, "chardev",
cryptodev_vhost_user_get_chardev,
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
index 2b105e433c..33eb4e1a70 100644
--- a/backends/cryptodev.c
+++ b/backends/cryptodev.c
@@ -72,9 +72,9 @@ void cryptodev_backend_cleanup(
}
}

-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
CryptoDevBackend *backend,
- CryptoDevBackendSymSessionInfo *sess_info,
+ CryptoDevBackendSessionInfo *sess_info,
uint32_t queue_index, Error **errp)
{
CryptoDevBackendClass *bc =
@@ -87,7 +87,7 @@ int64_t cryptodev_backend_sym_create_session(
return -1;
}

-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
uint32_t queue_index, Error **errp)
@@ -102,16 +102,16 @@ int cryptodev_backend_sym_close_session(
return -1;
}

-static int cryptodev_backend_sym_operation(
+static int cryptodev_backend_operation(
CryptoDevBackend *backend,
- CryptoDevBackendSymOpInfo *op_info,
+ CryptoDevBackendOpInfo *op_info,
uint32_t queue_index, Error **errp)
{
CryptoDevBackendClass *bc =
CRYPTODEV_BACKEND_GET_CLASS(backend);

- if (bc->do_sym_op) {
- return bc->do_sym_op(backend, op_info, queue_index, errp);
+ if (bc->do_op) {
+ return bc->do_op(backend, op_info, queue_index, errp);
}

return -VIRTIO_CRYPTO_ERR;
@@ -123,20 +123,18 @@ int cryptodev_backend_crypto_operation(
uint32_t queue_index, Error **errp)
{
VirtIOCryptoReq *req = opaque;
+ CryptoDevBackendOpInfo *op_info = &req->op_info;
+ enum CryptoDevBackendAlgType algtype = req->flags;

- if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
- CryptoDevBackendSymOpInfo *op_info;
- op_info = req->u.sym_op_info;
-
- return cryptodev_backend_sym_operation(backend,
- op_info, queue_index, errp);
- } else {
+ if ((algtype != CRYPTODEV_BACKEND_ALG_SYM)
+ && (algtype != CRYPTODEV_BACKEND_ALG_ASYM)) {
error_setg(errp, "Unsupported cryptodev alg type: %" PRIu32 "",
- req->flags);
- return -VIRTIO_CRYPTO_NOTSUPP;
+ algtype);
+
+ return -VIRTIO_CRYPTO_NOTSUPP;
}

- return -VIRTIO_CRYPTO_ERR;
+ return cryptodev_backend_operation(backend, op_info, queue_index, errp);
}

static void
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index dcd80b904d..fc1ca90202 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -83,7 +83,8 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
struct iovec *iov, unsigned int out_num)
{
VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
- CryptoDevBackendSymSessionInfo info;
+ CryptoDevBackendSessionInfo info;
+ CryptoDevBackendSymSessionInfo *sym_info;
int64_t session_id;
int queue_index;
uint32_t op_type;
@@ -92,11 +93,13 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,

memset(&info, 0, sizeof(info));
op_type = ldl_le_p(&sess_req->op_type);
- info.op_type = op_type;
info.op_code = opcode;

+ sym_info = &info.u.sym_sess_info;
+ sym_info->op_type = op_type;
+
if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
- ret = virtio_crypto_cipher_session_helper(vdev, &info,
+ ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
&sess_req->u.cipher.para,
&iov, &out_num);
if (ret < 0) {
@@ -105,47 +108,47 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
} else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
size_t s;
/* cipher part */
- ret = virtio_crypto_cipher_session_helper(vdev, &info,
+ ret = virtio_crypto_cipher_session_helper(vdev, sym_info,
&sess_req->u.chain.para.cipher_param,
&iov, &out_num);
if (ret < 0) {
goto err;
}
/* hash part */
- info.alg_chain_order = ldl_le_p(
+ sym_info->alg_chain_order = ldl_le_p(
&sess_req->u.chain.para.alg_chain_order);
- info.add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
- info.hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
- if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
- info.hash_alg = ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
- info.auth_key_len = ldl_le_p(
+ sym_info->add_len = ldl_le_p(&sess_req->u.chain.para.aad_len);
+ sym_info->hash_mode = ldl_le_p(&sess_req->u.chain.para.hash_mode);
+ if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH) {
+ sym_info->hash_alg =
+ ldl_le_p(&sess_req->u.chain.para.u.mac_param.algo);
+ sym_info->auth_key_len = ldl_le_p(
&sess_req->u.chain.para.u.mac_param.auth_key_len);
- info.hash_result_len = ldl_le_p(
+ sym_info->hash_result_len = ldl_le_p(
&sess_req->u.chain.para.u.mac_param.hash_result_len);
- if (info.auth_key_len > vcrypto->conf.max_auth_key_len) {
+ if (sym_info->auth_key_len > vcrypto->conf.max_auth_key_len) {
error_report("virtio-crypto length of auth key is too big: %u",
- info.auth_key_len);
+ sym_info->auth_key_len);
ret = -VIRTIO_CRYPTO_ERR;
goto err;
}
/* get auth key */
- if (info.auth_key_len > 0) {
- DPRINTF("auth_keylen=%" PRIu32 "\n", info.auth_key_len);
- info.auth_key = g_malloc(info.auth_key_len);
- s = iov_to_buf(iov, out_num, 0, info.auth_key,
- info.auth_key_len);
- if (unlikely(s != info.auth_key_len)) {
+ if (sym_info->auth_key_len > 0) {
+ sym_info->auth_key = g_malloc(sym_info->auth_key_len);
+ s = iov_to_buf(iov, out_num, 0, sym_info->auth_key,
+ sym_info->auth_key_len);
+ if (unlikely(s != sym_info->auth_key_len)) {
virtio_error(vdev,
"virtio-crypto authenticated key incorrect");
ret = -EFAULT;
goto err;
}
- iov_discard_front(&iov, &out_num, info.auth_key_len);
+ iov_discard_front(&iov, &out_num, sym_info->auth_key_len);
}
- } else if (info.hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
- info.hash_alg = ldl_le_p(
+ } else if (sym_info->hash_mode == VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN) {
+ sym_info->hash_alg = ldl_le_p(
&sess_req->u.chain.para.u.hash_param.algo);
- info.hash_result_len = ldl_le_p(
+ sym_info->hash_result_len = ldl_le_p(
&sess_req->u.chain.para.u.hash_param.hash_result_len);
} else {
/* VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED */
@@ -161,13 +164,10 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
}

queue_index = virtio_crypto_vq2q(queue_id);
- session_id = cryptodev_backend_sym_create_session(
+ session_id = cryptodev_backend_create_session(
vcrypto->cryptodev,
&info, queue_index, &local_err);
if (session_id >= 0) {
- DPRINTF("create session_id=%" PRIu64 " successfully\n",
- session_id);
-
ret = session_id;
} else {
if (local_err) {
@@ -177,11 +177,82 @@ virtio_crypto_create_sym_session(VirtIOCrypto *vcrypto,
}

err:
- g_free(info.cipher_key);
- g_free(info.auth_key);
+ g_free(sym_info->cipher_key);
+ g_free(sym_info->auth_key);
return ret;
}

+static int64_t
+virtio_crypto_create_asym_session(VirtIOCrypto *vcrypto,
+ struct virtio_crypto_akcipher_create_session_req *sess_req,
+ uint32_t queue_id, uint32_t opcode,
+ struct iovec *iov, unsigned int out_num)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+ CryptoDevBackendSessionInfo info = {0};
+ CryptoDevBackendAsymSessionInfo *asym_info;
+ int64_t session_id;
+ int queue_index;
+ uint32_t algo, keytype, keylen;
+ uint8_t *key = NULL;
+ Error *local_err = NULL;
+
+ algo = ldl_le_p(&sess_req->para.algo);
+ keytype = ldl_le_p(&sess_req->para.keytype);
+ keylen = ldl_le_p(&sess_req->para.keylen);
+
+ if ((keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC)
+ && (keytype != VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE)) {
+ error_report("unsupported asym keytype: %d", keytype);
+ return -VIRTIO_CRYPTO_NOTSUPP;
+ }
+
+ if (keylen) {
+ key = g_malloc(keylen);
+ if (iov_to_buf(iov, out_num, 0, key, keylen) != keylen) {
+ virtio_error(vdev, "virtio-crypto asym key incorrect");
+ g_free(key);
+ return -EFAULT;
+ }
+ iov_discard_front(&iov, &out_num, keylen);
+ }
+
+ info.op_code = opcode;
+ asym_info = &info.u.asym_sess_info;
+ asym_info->algo = algo;
+ asym_info->keytype = keytype;
+ asym_info->keylen = keylen;
+ asym_info->key = key;
+ switch (asym_info->algo) {
+ case VIRTIO_CRYPTO_AKCIPHER_RSA:
+ asym_info->u.rsa.padding_algo =
+ ldl_le_p(&sess_req->para.u.rsa.padding_algo);
+ asym_info->u.rsa.hash_algo =
+ ldl_le_p(&sess_req->para.u.rsa.hash_algo);
+ break;
+
+ case VIRTIO_CRYPTO_AKCIPHER_ECDSA:
+ asym_info->u.ecdsa.curve_id =
+ ldl_le_p(&sess_req->para.u.ecdsa.curve_id);
+ break;
+
+ default:
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ queue_index = virtio_crypto_vq2q(queue_id);
+ session_id = cryptodev_backend_create_session(vcrypto->cryptodev, &info,
+ queue_index, &local_err);
+ if (session_id < 0) {
+ if (local_err) {
+ error_report_err(local_err);
+ }
+ return -VIRTIO_CRYPTO_ERR;
+ }
+
+ return session_id;
+}
+
static uint8_t
virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
struct virtio_crypto_destroy_session_req *close_sess_req,
@@ -193,9 +264,8 @@ virtio_crypto_handle_close_session(VirtIOCrypto *vcrypto,
Error *local_err = NULL;

session_id = ldq_le_p(&close_sess_req->session_id);
- DPRINTF("close session, id=%" PRIu64 "\n", session_id);

- ret = cryptodev_backend_sym_close_session(
+ ret = cryptodev_backend_close_session(
vcrypto->cryptodev, session_id, queue_id, &local_err);
if (ret == 0) {
status = VIRTIO_CRYPTO_OK;
@@ -260,13 +330,22 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
opcode = ldl_le_p(&ctrl.header.opcode);
queue_id = ldl_le_p(&ctrl.header.queue_id);

+ memset(&input, 0, sizeof(input));
switch (opcode) {
case VIRTIO_CRYPTO_CIPHER_CREATE_SESSION:
- memset(&input, 0, sizeof(input));
session_id = virtio_crypto_create_sym_session(vcrypto,
&ctrl.u.sym_create_session,
queue_id, opcode,
out_iov, out_num);
+ goto check_session;
+
+ case VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION:
+ session_id = virtio_crypto_create_asym_session(vcrypto,
+ &ctrl.u.akcipher_create_session,
+ queue_id, opcode,
+ out_iov, out_num);
+
+check_session:
/* Serious errors, need to reset virtio crypto device */
if (session_id == -EFAULT) {
virtqueue_detach_element(vq, elem, 0);
@@ -290,10 +369,12 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
virtqueue_push(vq, elem, sizeof(input));
virtio_notify(vdev, vq);
break;
+
case VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION:
case VIRTIO_CRYPTO_HASH_DESTROY_SESSION:
case VIRTIO_CRYPTO_MAC_DESTROY_SESSION:
case VIRTIO_CRYPTO_AEAD_DESTROY_SESSION:
+ case VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION:
status = virtio_crypto_handle_close_session(vcrypto,
&ctrl.u.destroy_session, queue_id);
/* The status only occupy one byte, we can directly use it */
@@ -311,7 +392,6 @@ static void virtio_crypto_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
case VIRTIO_CRYPTO_AEAD_CREATE_SESSION:
default:
error_report("virtio-crypto unsupported ctrl opcode: %d", opcode);
- memset(&input, 0, sizeof(input));
stl_le_p(&input.status, VIRTIO_CRYPTO_NOTSUPP);
s = iov_from_buf(in_iov, in_num, 0, &input, sizeof(input));
if (unlikely(s != sizeof(input))) {
@@ -339,28 +419,37 @@ static void virtio_crypto_init_request(VirtIOCrypto *vcrypto, VirtQueue *vq,
req->in_num = 0;
req->in_len = 0;
req->flags = CRYPTODEV_BACKEND_ALG__MAX;
- req->u.sym_op_info = NULL;
+ memset(&req->op_info, 0x00, sizeof(req->op_info));
}

static void virtio_crypto_free_request(VirtIOCryptoReq *req)
{
- if (req) {
- if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
- size_t max_len;
- CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info;
-
- max_len = op_info->iv_len +
- op_info->aad_len +
- op_info->src_len +
- op_info->dst_len +
- op_info->digest_result_len;
-
- /* Zeroize and free request data structure */
- memset(op_info, 0, sizeof(*op_info) + max_len);
+ if (!req) {
+ return;
+ }
+
+ if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
+ size_t max_len;
+ CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
+
+ max_len = op_info->iv_len +
+ op_info->aad_len +
+ op_info->src_len +
+ op_info->dst_len +
+ op_info->digest_result_len;
+
+ /* Zeroize and free request data structure */
+ memset(op_info, 0, sizeof(*op_info) + max_len);
+ g_free(op_info);
+ } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+ CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
+ if (op_info) {
+ memset(op_info, 0, sizeof(*op_info));
g_free(op_info);
}
- g_free(req);
}
+
+ g_free(req);
}

static void
@@ -397,6 +486,35 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev,
}
}

+static void
+virtio_crypto_akcipher_input_data_helper(VirtIODevice *vdev,
+ VirtIOCryptoReq *req, int32_t status,
+ CryptoDevBackendAsymOpInfo *asym_op_info)
+{
+ size_t s, len;
+
+ if (status != VIRTIO_CRYPTO_OK) {
+ return;
+ }
+
+ len = asym_op_info->dst_len;
+ if (!len) {
+ return;
+ }
+
+ s = iov_from_buf(req->in_iov, req->in_num, 0, asym_op_info->dst, len);
+ if (s != len) {
+ virtio_error(vdev, "virtio-crypto asym dest data incorrect");
+ return;
+ }
+
+ iov_discard_front(&req->in_iov, &req->in_num, len);
+
+ /* For akcipher, dst_len may be changed after operation */
+ req->in_len = sizeof(struct virtio_crypto_inhdr) + asym_op_info->dst_len;
+}
+
+
static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)
{
VirtIOCrypto *vcrypto = req->vcrypto;
@@ -404,7 +522,10 @@ static void virtio_crypto_req_complete(VirtIOCryptoReq *req, uint8_t status)

if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
virtio_crypto_sym_input_data_helper(vdev, req, status,
- req->u.sym_op_info);
+ req->op_info.u.sym_op_info);
+ } else if (req->flags == CRYPTODEV_BACKEND_ALG_ASYM) {
+ virtio_crypto_akcipher_input_data_helper(vdev, req, status,
+ req->op_info.u.asym_op_info);
}
stb_p(&req->in->status, status);
virtqueue_push(req->vq, &req->elem, req->in_len);
@@ -543,41 +664,100 @@ err:
static int
virtio_crypto_handle_sym_req(VirtIOCrypto *vcrypto,
struct virtio_crypto_sym_data_req *req,
- CryptoDevBackendSymOpInfo **sym_op_info,
+ CryptoDevBackendOpInfo *op_info,
struct iovec *iov, unsigned int out_num)
{
VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+ CryptoDevBackendSymOpInfo *sym_op_info;
uint32_t op_type;
- CryptoDevBackendSymOpInfo *op_info;

op_type = ldl_le_p(&req->op_type);
-
if (op_type == VIRTIO_CRYPTO_SYM_OP_CIPHER) {
- op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
+ sym_op_info = virtio_crypto_sym_op_helper(vdev, &req->u.cipher.para,
NULL, iov, out_num);
- if (!op_info) {
+ if (!sym_op_info) {
return -EFAULT;
}
- op_info->op_type = op_type;
} else if (op_type == VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING) {
- op_info = virtio_crypto_sym_op_helper(vdev, NULL,
+ sym_op_info = virtio_crypto_sym_op_helper(vdev, NULL,
&req->u.chain.para,
iov, out_num);
- if (!op_info) {
+ if (!sym_op_info) {
return -EFAULT;
}
- op_info->op_type = op_type;
} else {
/* VIRTIO_CRYPTO_SYM_OP_NONE */
error_report("virtio-crypto unsupported cipher type");
return -VIRTIO_CRYPTO_NOTSUPP;
}

- *sym_op_info = op_info;
+ sym_op_info->op_type = op_type;
+ op_info->u.sym_op_info = sym_op_info;

return 0;
}

+static int
+virtio_crypto_handle_asym_req(VirtIOCrypto *vcrypto,
+ struct virtio_crypto_akcipher_data_req *req,
+ CryptoDevBackendOpInfo *op_info,
+ struct iovec *iov, unsigned int out_num)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(vcrypto);
+ CryptoDevBackendAsymOpInfo *asym_op_info;
+ uint32_t src_len;
+ uint32_t dst_len;
+ uint32_t len;
+ uint8_t *src = NULL;
+ uint8_t *dst = NULL;
+
+ asym_op_info = g_malloc0(sizeof(CryptoDevBackendAsymOpInfo));
+ src_len = ldl_le_p(&req->para.src_data_len);
+ dst_len = ldl_le_p(&req->para.dst_data_len);
+
+ if (src_len > 0) {
+ src = g_malloc0(src_len);
+ len = iov_to_buf(iov, out_num, 0, src, src_len);
+ if (unlikely(len != src_len)) {
+ virtio_error(vdev, "virtio-crypto asym src data incorrect"
+ "expected %u, actual %u", src_len, len);
+ goto err;
+ }
+
+ iov_discard_front(&iov, &out_num, src_len);
+ }
+
+ if (dst_len > 0) {
+ dst = g_malloc0(dst_len);
+
+ if (op_info->op_code == VIRTIO_CRYPTO_AKCIPHER_VERIFY) {
+ len = iov_to_buf(iov, out_num, 0, dst, dst_len);
+ if (unlikely(len != dst_len)) {
+ virtio_error(vdev, "virtio-crypto asym dst data incorrect"
+ "expected %u, actual %u", dst_len, len);
+ goto err;
+ }
+
+ iov_discard_front(&iov, &out_num, dst_len);
+ }
+ }
+
+ asym_op_info->src_len = src_len;
+ asym_op_info->dst_len = dst_len;
+ asym_op_info->src = src;
+ asym_op_info->dst = dst;
+ op_info->u.asym_op_info = asym_op_info;
+
+ return 0;
+
+ err:
+ g_free(asym_op_info);
+ g_free(src);
+ g_free(dst);
+
+ return -EFAULT;
+}
+
static int
virtio_crypto_handle_request(VirtIOCryptoReq *request)
{
@@ -595,8 +775,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
unsigned out_num;
uint32_t opcode;
uint8_t status = VIRTIO_CRYPTO_ERR;
- uint64_t session_id;
- CryptoDevBackendSymOpInfo *sym_op_info = NULL;
+ CryptoDevBackendOpInfo *op_info = &request->op_info;
Error *local_err = NULL;

if (elem->out_num < 1 || elem->in_num < 1) {
@@ -639,15 +818,28 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
request->in_iov = in_iov;

opcode = ldl_le_p(&req.header.opcode);
- session_id = ldq_le_p(&req.header.session_id);
+ op_info->session_id = ldq_le_p(&req.header.session_id);
+ op_info->op_code = opcode;

switch (opcode) {
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
case VIRTIO_CRYPTO_CIPHER_DECRYPT:
+ op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_SYM;
ret = virtio_crypto_handle_sym_req(vcrypto,
- &req.u.sym_req,
- &sym_op_info,
+ &req.u.sym_req, op_info,
+ out_iov, out_num);
+ goto check_result;
+
+ case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
+ case VIRTIO_CRYPTO_AKCIPHER_DECRYPT:
+ case VIRTIO_CRYPTO_AKCIPHER_SIGN:
+ case VIRTIO_CRYPTO_AKCIPHER_VERIFY:
+ op_info->algtype = request->flags = CRYPTODEV_BACKEND_ALG_ASYM;
+ ret = virtio_crypto_handle_asym_req(vcrypto,
+ &req.u.akcipher_req, op_info,
out_iov, out_num);
+
+check_result:
/* Serious errors, need to reset virtio crypto device */
if (ret == -EFAULT) {
return -1;
@@ -655,11 +847,8 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
virtio_crypto_req_complete(request, VIRTIO_CRYPTO_NOTSUPP);
virtio_crypto_free_request(request);
} else {
- sym_op_info->session_id = session_id;

/* Set request's parameter */
- request->flags = CRYPTODEV_BACKEND_ALG_SYM;
- request->u.sym_op_info = sym_op_info;
ret = cryptodev_backend_crypto_operation(vcrypto->cryptodev,
request, queue_index, &local_err);
if (ret < 0) {
@@ -674,6 +863,7 @@ virtio_crypto_handle_request(VirtIOCryptoReq *request)
virtio_crypto_free_request(request);
}
break;
+
case VIRTIO_CRYPTO_HASH:
case VIRTIO_CRYPTO_MAC:
case VIRTIO_CRYPTO_AEAD_ENCRYPT:
@@ -779,6 +969,7 @@ static void virtio_crypto_init_config(VirtIODevice *vdev)
vcrypto->conf.mac_algo_l = vcrypto->conf.cryptodev->conf.mac_algo_l;
vcrypto->conf.mac_algo_h = vcrypto->conf.cryptodev->conf.mac_algo_h;
vcrypto->conf.aead_algo = vcrypto->conf.cryptodev->conf.aead_algo;
+ vcrypto->conf.akcipher_algo = vcrypto->conf.cryptodev->conf.akcipher_algo;
vcrypto->conf.max_cipher_key_len =
vcrypto->conf.cryptodev->conf.max_cipher_key_len;
vcrypto->conf.max_auth_key_len =
@@ -891,6 +1082,7 @@ static void virtio_crypto_get_config(VirtIODevice *vdev, uint8_t *config)
stl_le_p(&crypto_cfg.max_cipher_key_len, c->conf.max_cipher_key_len);
stl_le_p(&crypto_cfg.max_auth_key_len, c->conf.max_auth_key_len);
stq_le_p(&crypto_cfg.max_size, c->conf.max_size);
+ stl_le_p(&crypto_cfg.akcipher_algo, c->conf.akcipher_algo);

memcpy(config, &crypto_cfg, c->config_size);
}
diff --git a/include/hw/virtio/virtio-crypto.h b/include/hw/virtio/virtio-crypto.h
index a2228d7b2e..348749f5d5 100644
--- a/include/hw/virtio/virtio-crypto.h
+++ b/include/hw/virtio/virtio-crypto.h
@@ -50,6 +50,7 @@ typedef struct VirtIOCryptoConf {
uint32_t mac_algo_l;
uint32_t mac_algo_h;
uint32_t aead_algo;
+ uint32_t akcipher_algo;

/* Maximum length of cipher key */
uint32_t max_cipher_key_len;
@@ -71,9 +72,7 @@ typedef struct VirtIOCryptoReq {
size_t in_len;
VirtQueue *vq;
struct VirtIOCrypto *vcrypto;
- union {
- CryptoDevBackendSymOpInfo *sym_op_info;
- } u;
+ CryptoDevBackendOpInfo op_info;
} VirtIOCryptoReq;

typedef struct VirtIOCryptoQueue {
diff --git a/include/sysemu/cryptodev.h b/include/sysemu/cryptodev.h
index f4d4057d4d..b306775849 100644
--- a/include/sysemu/cryptodev.h
+++ b/include/sysemu/cryptodev.h
@@ -50,13 +50,13 @@ typedef struct CryptoDevBackendClient

enum CryptoDevBackendAlgType {
CRYPTODEV_BACKEND_ALG_SYM,
+ CRYPTODEV_BACKEND_ALG_ASYM,
CRYPTODEV_BACKEND_ALG__MAX,
};

/**
* CryptoDevBackendSymSessionInfo:
*
- * @op_code: operation code (refer to virtio_crypto.h)
* @cipher_alg: algorithm type of CIPHER
* @key_len: byte length of cipher key
* @hash_alg: algorithm type of HASH/MAC
@@ -74,7 +74,6 @@ enum CryptoDevBackendAlgType {
*/
typedef struct CryptoDevBackendSymSessionInfo {
/* corresponding with virtio crypto spec */
- uint32_t op_code;
uint32_t cipher_alg;
uint32_t key_len;
uint32_t hash_alg;
@@ -89,11 +88,41 @@ typedef struct CryptoDevBackendSymSessionInfo {
uint8_t *auth_key;
} CryptoDevBackendSymSessionInfo;

+/**
+ * CryptoDevBackendAsymSessionInfo:
+ */
+typedef struct CryptoDevBackendRsaPara {
+ uint32_t padding_algo;
+ uint32_t hash_algo;
+} CryptoDevBackendRsaPara;
+
+typedef struct CryptoDevBackendEcdsaPara {
+ uint32_t curve_id;
+} CryptoDevBackendEcdsaPara;
+
+typedef struct CryptoDevBackendAsymSessionInfo {
+ /* corresponding with virtio crypto spec */
+ uint32_t algo;
+ uint32_t keytype;
+ uint32_t keylen;
+ uint8_t *key;
+ union {
+ CryptoDevBackendRsaPara rsa;
+ CryptoDevBackendEcdsaPara ecdsa;
+ } u;
+} CryptoDevBackendAsymSessionInfo;
+
+typedef struct CryptoDevBackendSessionInfo {
+ uint32_t op_code;
+ union {
+ CryptoDevBackendSymSessionInfo sym_sess_info;
+ CryptoDevBackendAsymSessionInfo asym_sess_info;
+ } u;
+} CryptoDevBackendSessionInfo;
+
/**
* CryptoDevBackendSymOpInfo:
*
- * @session_id: session index which was previously
- * created by cryptodev_backend_sym_create_session()
* @aad_len: byte length of additional authenticated data
* @iv_len: byte length of initialization vector or counter
* @src_len: byte length of source data
@@ -119,7 +148,6 @@ typedef struct CryptoDevBackendSymSessionInfo {
*
*/
typedef struct CryptoDevBackendSymOpInfo {
- uint64_t session_id;
uint32_t aad_len;
uint32_t iv_len;
uint32_t src_len;
@@ -138,6 +166,33 @@ typedef struct CryptoDevBackendSymOpInfo {
uint8_t data[];
} CryptoDevBackendSymOpInfo;

+
+/**
+ * CryptoDevBackendAsymOpInfo:
+ *
+ * @src_len: byte length of source data
+ * @dst_len: byte length of destination data
+ * @src: point to the source data
+ * @dst: point to the destination data
+ *
+ */
+typedef struct CryptoDevBackendAsymOpInfo {
+ uint32_t src_len;
+ uint32_t dst_len;
+ uint8_t *src;
+ uint8_t *dst;
+} CryptoDevBackendAsymOpInfo;
+
+typedef struct CryptoDevBackendOpInfo {
+ enum CryptoDevBackendAlgType algtype;
+ uint32_t op_code;
+ uint64_t session_id;
+ union {
+ CryptoDevBackendSymOpInfo *sym_op_info;
+ CryptoDevBackendAsymOpInfo *asym_op_info;
+ } u;
+} CryptoDevBackendOpInfo;
+
struct CryptoDevBackendClass {
ObjectClass parent_class;

@@ -145,13 +200,13 @@ struct CryptoDevBackendClass {
void (*cleanup)(CryptoDevBackend *backend, Error **errp);

int64_t (*create_session)(CryptoDevBackend *backend,
- CryptoDevBackendSymSessionInfo *sess_info,
+ CryptoDevBackendSessionInfo *sess_info,
uint32_t queue_index, Error **errp);
int (*close_session)(CryptoDevBackend *backend,
uint64_t session_id,
uint32_t queue_index, Error **errp);
- int (*do_sym_op)(CryptoDevBackend *backend,
- CryptoDevBackendSymOpInfo *op_info,
+ int (*do_op)(CryptoDevBackend *backend,
+ CryptoDevBackendOpInfo *op_info,
uint32_t queue_index, Error **errp);
};

@@ -190,6 +245,7 @@ struct CryptoDevBackendConf {
uint32_t mac_algo_l;
uint32_t mac_algo_h;
uint32_t aead_algo;
+ uint32_t akcipher_algo;
/* Maximum length of cipher key */
uint32_t max_cipher_key_len;
/* Maximum length of authenticated key */
@@ -247,34 +303,34 @@ void cryptodev_backend_cleanup(
Error **errp);

/**
- * cryptodev_backend_sym_create_session:
+ * cryptodev_backend_create_session:
* @backend: the cryptodev backend object
* @sess_info: parameters needed by session creating
* @queue_index: queue index of cryptodev backend client
* @errp: pointer to a NULL-initialized error object
*
- * Create a session for symmetric algorithms
+ * Create a session for symmetric/symmetric algorithms
*
* Returns: session id on success, or -1 on error
*/
-int64_t cryptodev_backend_sym_create_session(
+int64_t cryptodev_backend_create_session(
CryptoDevBackend *backend,
- CryptoDevBackendSymSessionInfo *sess_info,
+ CryptoDevBackendSessionInfo *sess_info,
uint32_t queue_index, Error **errp);

/**
- * cryptodev_backend_sym_close_session:
+ * cryptodev_backend_close_session:
* @backend: the cryptodev backend object
* @session_id: the session id
* @queue_index: queue index of cryptodev backend client
* @errp: pointer to a NULL-initialized error object
*
- * Close a session for symmetric algorithms which was previously
- * created by cryptodev_backend_sym_create_session()
+ * Close a session for which was previously
+ * created by cryptodev_backend_create_session()
*
* Returns: 0 on success, or Negative on error
*/
-int cryptodev_backend_sym_close_session(
+int cryptodev_backend_close_session(
CryptoDevBackend *backend,
uint64_t session_id,
uint32_t queue_index, Error **errp);
--
2.25.1

2022-03-25 04:17:40

by zhenwei pi

[permalink] [raw]
Subject: [PATCH v3 2/6] crypto-akcipher: Introduce akcipher types to qapi

From: Lei He <[email protected]>

Introduce akcipher types, also include RSA & ECDSA related types.

Signed-off-by: Lei He <[email protected]>
Signed-off-by: zhenwei pi <[email protected]>
---
qapi/crypto.json | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)

diff --git a/qapi/crypto.json b/qapi/crypto.json
index 1ec54c15ca..d44c38e3b1 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -540,3 +540,89 @@
'data': { '*loaded': { 'type': 'bool', 'features': ['deprecated'] },
'*sanity-check': 'bool',
'*passwordid': 'str' } }
+##
+# @QCryptoAkcipherAlgorithm:
+#
+# The supported algorithms for asymmetric encryption ciphers
+#
+# @rsa: RSA algorithm
+# @ecdsa: ECDSA algorithm
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherAlgorithm',
+ 'prefix': 'QCRYPTO_AKCIPHER_ALG',
+ 'data': ['rsa', 'ecdsa']}
+
+##
+# @QCryptoAkcipherKeyType:
+#
+# The type of asymmetric keys.
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoAkcipherKeyType',
+ 'prefix': 'QCRYPTO_AKCIPHER_KEY_TYPE',
+ 'data': ['public', 'private']}
+
+##
+# @QCryptoRsaHashAlgorithm:
+#
+# The hash algorithm for RSA pkcs1 padding algothrim
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaHashAlgorithm',
+ 'prefix': 'QCRYPTO_RSA_HASH_ALG',
+ 'data': [ 'md2', 'md3', 'md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'sha224' ]}
+
+##
+# @QCryptoRsaPaddingAlgorithm:
+#
+# The padding algorithm for RSA.
+#
+# @raw: no padding used
+# @pkcs1: pkcs1#v1.5
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoRsaPaddingAlgorithm',
+ 'prefix': 'QCRYPTO_RSA_PADDING_ALG',
+ 'data': ['raw', 'pkcs1']}
+
+##
+# @QCryptoCurveId:
+#
+# The well-known curves, referenced from https://csrc.nist.gov/csrc/media/publications/fips/186/3/archive/2009-06-25/documents/fips_186-3.pdf
+#
+# Since: 7.0
+##
+{ 'enum': 'QCryptoCurveId',
+ 'prefix': 'QCRYPTO_CURVE_ID',
+ 'data': ['nist-p192', 'nist-p224', 'nist-p256', 'nist-p384', 'nist-p521']}
+
+##
+# @QCryptoRsaOptions:
+#
+# Specific parameters for RSA algorithm.
+#
+# @hash-algo: QCryptoRsaHashAlgorithm
+# @padding-algo: QCryptoRsaPaddingAlgorithm
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoRsaOptions',
+ 'data': { 'hash-algo':'QCryptoRsaHashAlgorithm',
+ 'padding-algo': 'QCryptoRsaPaddingAlgorithm'}}
+
+##
+# @QCryptoEcdsaOptions:
+#
+# Specific parameter for ECDSA algorithm.
+#
+# @curve-id: QCryptoCurveId
+#
+# Since: 7.0
+##
+{ 'struct': 'QCryptoEcdsaOptions',
+ 'data': { 'curve-id': 'QCryptoCurveId' }}
--
2.25.1