Re: [PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed

2022-03-23 Thread Daniel P . Berrangé
On Wed, Mar 23, 2022 at 10:49:10AM +0800, zhenwei pi wrote:
> From: Lei He 
> 
> Introduce ASN.1 decoder, and implement RSA algorithm by hogweed
> from nettle. Thus QEMU supports a 'real' RSA backend to handle
> request from guest side. It's important to test RSA offload case
> without OS & hardware requirement.
> 
> Signed-off-by: lei he 
> Signed-off-by: zhenwei pi 
> ---
>  crypto/akcipher-nettle.c  | 523 ++
>  crypto/akcipher.c |   3 +
>  crypto/asn1_decoder.c | 185 ++
>  crypto/asn1_decoder.h |  42 +++

Please introduce the asn1 files in a separate commit, and also
provide a unit test to validate them in the same commit.

> diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
> new file mode 100644
> index 00..45b93af772
> --- /dev/null
> +++ b/crypto/akcipher-nettle.c
> @@ -0,0 +1,523 @@
> +/*
> + * QEMU Crypto akcipher algorithms
> + *
> + * Copyright (c) 2022 Bytedance
> + * Author: lei he 
> + *
> + * 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.1 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 
> .
> + *
> + */
> +
> +#include 
> +
> +#include 
> +
> +#include "qemu/osdep.h"
> +#include "qemu/host-utils.h"
> +#include "asn1_decoder.h"
> +#include "crypto/akcipher.h"
> +#include "crypto/random.h"
> +#include "qapi/error.h"
> +#include "sysemu/cryptodev.h"
> +
> +typedef struct QCryptoNettleRsa {
> +QCryptoAkcipher akcipher;
> +struct rsa_public_key pub;
> +struct rsa_private_key priv;
> +QCryptoRsaPaddingAlgorithm padding_algo;
> +QCryptoRsaHashAlgorithm hash_algo;
> +} QCryptoNettleRsa;

Call this QCryptoAkCipherNettleRSA

> +
> +struct asn1_parse_ctx {
> +const uint8_t *data;
> +size_t dlen;
> +};
> +
> +#define Octet 8
> +
> +static int extract_value(void *p, const uint8_t *data, size_t dlen)
> +{
> +struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
> +ctx->data = (uint8_t *)data;
> +ctx->dlen = dlen;
> +
> +return 0;
> +}
> +
> +static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
> +{
> +mpz_t *target = (mpz_t *)p;
> +nettle_mpz_set_str_256_u(*target, dlen, data);
> +
> +return 0;
> +}
> +
> +static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
> +
> +static void qcrypto_nettle_rsa_destroy(void *ptr)
> +{
> +QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
> +if (!rsa) {
> +return;
> +}
> +
> +rsa_public_key_clear(>pub);
> +rsa_private_key_clear(>priv);
> +g_free(rsa);
> +}
> +
> +static QCryptoAkcipher *qcrypto_nettle_new_rsa(
> +QCryptoAkcipherKeyType type,
> +const uint8_t *key,  size_t keylen,
> +QCryptoRsaOptions *opt, Error **errp);
> +
> +QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
> + QCryptoAkcipherKeyType type,
> + const uint8_t *key,
> + size_t keylen, void *para,
> + Error **errp)
> +{
> +switch (alg) {
> +case QCRYPTO_AKCIPHER_ALG_RSA:
> +return qcrypto_nettle_new_rsa(type, key, keylen,
> +  (QCryptoRsaOptions *)para, errp);
> +default:
> +error_setg(errp, "Unsupported algorithm: %u", alg);
> +return NULL;
> +}
> +
> +return NULL;
> +}
> +
> +/**
> + * Parse ber encoded rsa private key, asn1 schema:
> + *RsaPrivKey ::= SEQUENCE {
> + * version INTEGER
> + * n   INTEGER
> + * e   INTEGER
> + * d   INTEGER
> + * p   INTEGER
> + * q   INTEGER
> + * e1  INTEGER
> + * e2  INTEGER
> + * u   INTEGER
> + * }
> + */
> +static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
> + const uint8_t *key, size_t keylen)
> +{
> +struct asn1_parse_ctx ctx;
> +
> +if (ber_decode_seq(, , extract_value, ) != 0 ||
> +keylen != 0) {
> +return -1;
> +}
> +
> +if (ber_decode_int(, , NULL, NULL) != 0 ||
> +ber_decode_int(, , extract_mpi, >pub.n) != 0 
> ||
> +ber_decode_int(, , extract_mpi, >pub.e) != 0 
> ||
> +ber_decode_int(, , extract_mpi, >priv.d) != 

[PATCH v3 4/6] crypto: Implement RSA algorithm by hogweed

2022-03-22 Thread zhenwei pi
From: Lei He 

Introduce ASN.1 decoder, and implement RSA algorithm by hogweed
from nettle. Thus QEMU supports a 'real' RSA backend to handle
request from guest side. It's important to test RSA offload case
without OS & hardware requirement.

Signed-off-by: lei he 
Signed-off-by: zhenwei pi 
---
 crypto/akcipher-nettle.c  | 523 ++
 crypto/akcipher.c |   3 +
 crypto/asn1_decoder.c | 185 ++
 crypto/asn1_decoder.h |  42 +++
 crypto/meson.build|   3 +
 include/crypto/akcipher.h |  16 ++
 meson.build   |  11 +
 7 files changed, 783 insertions(+)
 create mode 100644 crypto/akcipher-nettle.c
 create mode 100644 crypto/asn1_decoder.c
 create mode 100644 crypto/asn1_decoder.h

diff --git a/crypto/akcipher-nettle.c b/crypto/akcipher-nettle.c
new file mode 100644
index 00..45b93af772
--- /dev/null
+++ b/crypto/akcipher-nettle.c
@@ -0,0 +1,523 @@
+/*
+ * QEMU Crypto akcipher algorithms
+ *
+ * Copyright (c) 2022 Bytedance
+ * Author: lei he 
+ *
+ * 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.1 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 .
+ *
+ */
+
+#include 
+
+#include 
+
+#include "qemu/osdep.h"
+#include "qemu/host-utils.h"
+#include "asn1_decoder.h"
+#include "crypto/akcipher.h"
+#include "crypto/random.h"
+#include "qapi/error.h"
+#include "sysemu/cryptodev.h"
+
+typedef struct QCryptoNettleRsa {
+QCryptoAkcipher akcipher;
+struct rsa_public_key pub;
+struct rsa_private_key priv;
+QCryptoRsaPaddingAlgorithm padding_algo;
+QCryptoRsaHashAlgorithm hash_algo;
+} QCryptoNettleRsa;
+
+struct asn1_parse_ctx {
+const uint8_t *data;
+size_t dlen;
+};
+
+#define Octet 8
+
+static int extract_value(void *p, const uint8_t *data, size_t dlen)
+{
+struct asn1_parse_ctx *ctx = (struct asn1_parse_ctx *)p;
+ctx->data = (uint8_t *)data;
+ctx->dlen = dlen;
+
+return 0;
+}
+
+static int extract_mpi(void *p, const uint8_t *data, size_t dlen)
+{
+mpz_t *target = (mpz_t *)p;
+nettle_mpz_set_str_256_u(*target, dlen, data);
+
+return 0;
+}
+
+static QCryptoNettleRsa *qcrypto_nettle_rsa_malloc(void);
+
+static void qcrypto_nettle_rsa_destroy(void *ptr)
+{
+QCryptoNettleRsa *rsa = (QCryptoNettleRsa *)ptr;
+if (!rsa) {
+return;
+}
+
+rsa_public_key_clear(>pub);
+rsa_private_key_clear(>priv);
+g_free(rsa);
+}
+
+static QCryptoAkcipher *qcrypto_nettle_new_rsa(
+QCryptoAkcipherKeyType type,
+const uint8_t *key,  size_t keylen,
+QCryptoRsaOptions *opt, Error **errp);
+
+QCryptoAkcipher *qcrypto_akcipher_nettle_new(QCryptoAkcipherAlgorithm alg,
+ QCryptoAkcipherKeyType type,
+ const uint8_t *key,
+ size_t keylen, void *para,
+ Error **errp)
+{
+switch (alg) {
+case QCRYPTO_AKCIPHER_ALG_RSA:
+return qcrypto_nettle_new_rsa(type, key, keylen,
+  (QCryptoRsaOptions *)para, errp);
+default:
+error_setg(errp, "Unsupported algorithm: %u", alg);
+return NULL;
+}
+
+return NULL;
+}
+
+/**
+ * Parse ber encoded rsa private key, asn1 schema:
+ *RsaPrivKey ::= SEQUENCE {
+ * version INTEGER
+ * n   INTEGER
+ * e   INTEGER
+ * d   INTEGER
+ * p   INTEGER
+ * q   INTEGER
+ * e1  INTEGER
+ * e2  INTEGER
+ * u   INTEGER
+ * }
+ */
+static int parse_rsa_private_key(QCryptoNettleRsa *rsa,
+ const uint8_t *key, size_t keylen)
+{
+struct asn1_parse_ctx ctx;
+
+if (ber_decode_seq(, , extract_value, ) != 0 ||
+keylen != 0) {
+return -1;
+}
+
+if (ber_decode_int(, , NULL, NULL) != 0 ||
+ber_decode_int(, , extract_mpi, >pub.n) != 0 ||
+ber_decode_int(, , extract_mpi, >pub.e) != 0 ||
+ber_decode_int(, , extract_mpi, >priv.d) != 0 ||
+ber_decode_int(, , extract_mpi, >priv.p) != 0 ||
+ber_decode_int(, , extract_mpi, >priv.q) != 0 ||
+ber_decode_int(, , extract_mpi, >priv.a) != 0 ||
+ber_decode_int(, , extract_mpi, >priv.b) != 0 ||
+