Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'ak-pull-request' of https://gitlab.com/berrange/qemu into …
…staging Merge asymmetric cipher crypto support This extends the internal crypto APIs to support the use of asymmetric ciphers. # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmKPWdgACgkQvobrtBUQ # T9/dXA//XozeQbIK9y/1wb60LXiqHiHDMi8Ct1oEpNsLaL4lsp09VjtmxggqMfad # MjxQjKdOVMVPISRnrKCJQ6qiGKQB7C/php1ZxOPdG4zgf2Ofl312GHZCLjqLkpB8 # KnhdFB31coI45EQ+agk5ZO8Baml85yY4sALLofGXV3xatJswH1HoMAmDATe5ebko # ox7qd/S9Q4bpZA4v+8fUbvX2zI95hZta8+4d2Irx542gO8KibYKRVmffJhcKx6hy # 4x7iTEaGQQn3DFMbVxsvb4wLwx1v8sSS6C2rHuGZY67ZzDnYhAdaHG9CaWR3uvtS # vs7EcEWqn45SfJ/FaYUyon/btsawJrXP9NISmns4J6TYoN6sJJVxk9T9A/hlqtEE # /iwTfp/Se+o2JDLgC+JHQz8maj4igloGNhF8+u4lXBLEpT7tlvaxhkrcPo9Um7ay # bWpmLoxVN5vEvOnsrfLhK6LGPIzfjP4tYX0xwWy5Lm/DZ1LinJOONPXjArFr3TaQ # rcS6L15ZaiFu9bYUyN1Uf7V7VydiVV8RlkuTqJ614gSX0v+GCMR1J+0WsQ4DtPlT # G6WP0EnnD4Ulg9XpSMte2GXKQ0d8c7hTKr3/RW+BuvvgP5T4P7guBTRhmufRiip6 # BByKpXrQ72yGm6U+nTtEVFdUWVER31U0ufsW64hdM+LGfiG7fUE= # =X589 # -----END PGP SIGNATURE----- # gpg: Signature made Thu 26 May 2022 03:43:36 AM PDT # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] * tag 'ak-pull-request' of https://gitlab.com/berrange/qemu: tests/crypto: Add test suite for RSA keys test/crypto: Add test suite for crypto akcipher crypto: Implement RSA algorithm by gcrypt crypto: Implement RSA algorithm by hogweed crypto: add ASN.1 DER decoder crypto: Introduce akcipher crypto class qapi: crypto-akcipher: Introduce akcipher types to qapi Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
- Loading branch information
Showing
20 changed files
with
4,169 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
* QEMU Crypto akcipher algorithms | ||
* | ||
* Copyright (c) 2022 Bytedance | ||
* Author: zhenwei pi <pizhenwei@bytedance.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.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 <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#include "qemu/osdep.h" | ||
#include "crypto/akcipher.h" | ||
#include "akcipherpriv.h" | ||
|
||
#if defined(CONFIG_GCRYPT) | ||
#include "akcipher-gcrypt.c.inc" | ||
#elif defined(CONFIG_NETTLE) && defined(CONFIG_HOGWEED) | ||
#include "akcipher-nettle.c.inc" | ||
#else | ||
QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts, | ||
QCryptoAkCipherKeyType type, | ||
const uint8_t *key, size_t keylen, | ||
Error **errp) | ||
{ | ||
QCryptoAkCipher *akcipher = NULL; | ||
|
||
return akcipher; | ||
} | ||
|
||
bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts) | ||
{ | ||
return false; | ||
} | ||
#endif | ||
|
||
int qcrypto_akcipher_encrypt(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
void *out, size_t out_len, Error **errp) | ||
{ | ||
const QCryptoAkCipherDriver *drv = akcipher->driver; | ||
|
||
return drv->encrypt(akcipher, in, in_len, out, out_len, errp); | ||
} | ||
|
||
int qcrypto_akcipher_decrypt(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
void *out, size_t out_len, Error **errp) | ||
{ | ||
const QCryptoAkCipherDriver *drv = akcipher->driver; | ||
|
||
return drv->decrypt(akcipher, in, in_len, out, out_len, errp); | ||
} | ||
|
||
int qcrypto_akcipher_sign(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
void *out, size_t out_len, Error **errp) | ||
{ | ||
const QCryptoAkCipherDriver *drv = akcipher->driver; | ||
|
||
return drv->sign(akcipher, in, in_len, out, out_len, errp); | ||
} | ||
|
||
int qcrypto_akcipher_verify(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
const void *in2, size_t in2_len, Error **errp) | ||
{ | ||
const QCryptoAkCipherDriver *drv = akcipher->driver; | ||
|
||
return drv->verify(akcipher, in, in_len, in2, in2_len, errp); | ||
} | ||
|
||
int qcrypto_akcipher_max_plaintext_len(QCryptoAkCipher *akcipher) | ||
{ | ||
return akcipher->max_plaintext_len; | ||
} | ||
|
||
int qcrypto_akcipher_max_ciphertext_len(QCryptoAkCipher *akcipher) | ||
{ | ||
return akcipher->max_ciphertext_len; | ||
} | ||
|
||
int qcrypto_akcipher_max_signature_len(QCryptoAkCipher *akcipher) | ||
{ | ||
return akcipher->max_signature_len; | ||
} | ||
|
||
int qcrypto_akcipher_max_dgst_len(QCryptoAkCipher *akcipher) | ||
{ | ||
return akcipher->max_dgst_len; | ||
} | ||
|
||
void qcrypto_akcipher_free(QCryptoAkCipher *akcipher) | ||
{ | ||
const QCryptoAkCipherDriver *drv = akcipher->driver; | ||
|
||
drv->free(akcipher); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* | ||
* QEMU Crypto asymmetric algorithms | ||
* | ||
* Copyright (c) 2022 Bytedance | ||
* Author: zhenwei pi <pizhenwei@bytedance.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.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 <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#ifndef QCRYPTO_AKCIPHERPRIV_H | ||
#define QCRYPTO_AKCIPHERPRIV_H | ||
|
||
#include "qapi/qapi-types-crypto.h" | ||
|
||
typedef struct QCryptoAkCipherDriver QCryptoAkCipherDriver; | ||
|
||
struct QCryptoAkCipher { | ||
QCryptoAkCipherAlgorithm alg; | ||
QCryptoAkCipherKeyType type; | ||
int max_plaintext_len; | ||
int max_ciphertext_len; | ||
int max_signature_len; | ||
int max_dgst_len; | ||
QCryptoAkCipherDriver *driver; | ||
}; | ||
|
||
struct QCryptoAkCipherDriver { | ||
int (*encrypt)(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
void *out, size_t out_len, Error **errp); | ||
int (*decrypt)(QCryptoAkCipher *akcipher, | ||
const void *out, size_t out_len, | ||
void *in, size_t in_len, Error **errp); | ||
int (*sign)(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
void *out, size_t out_len, Error **errp); | ||
int (*verify)(QCryptoAkCipher *akcipher, | ||
const void *in, size_t in_len, | ||
const void *in2, size_t in2_len, Error **errp); | ||
void (*free)(QCryptoAkCipher *akcipher); | ||
}; | ||
|
||
#endif /* QCRYPTO_AKCIPHER_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/* | ||
* QEMU Crypto ASN.1 DER decoder | ||
* | ||
* Copyright (c) 2022 Bytedance | ||
* Author: lei he <helei.sig11@bytedance.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.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 <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
#include "qemu/osdep.h" | ||
#include "crypto/der.h" | ||
|
||
enum QCryptoDERTypeTag { | ||
QCRYPTO_DER_TYPE_TAG_BOOL = 0x1, | ||
QCRYPTO_DER_TYPE_TAG_INT = 0x2, | ||
QCRYPTO_DER_TYPE_TAG_BIT_STR = 0x3, | ||
QCRYPTO_DER_TYPE_TAG_OCT_STR = 0x4, | ||
QCRYPTO_DER_TYPE_TAG_OCT_NULL = 0x5, | ||
QCRYPTO_DER_TYPE_TAG_OCT_OID = 0x6, | ||
QCRYPTO_DER_TYPE_TAG_SEQ = 0x10, | ||
QCRYPTO_DER_TYPE_TAG_SET = 0x11, | ||
}; | ||
|
||
#define QCRYPTO_DER_CONSTRUCTED_MASK 0x20 | ||
#define QCRYPTO_DER_SHORT_LEN_MASK 0x80 | ||
|
||
static uint8_t qcrypto_der_peek_byte(const uint8_t **data, size_t *dlen) | ||
{ | ||
return **data; | ||
} | ||
|
||
static void qcrypto_der_cut_nbytes(const uint8_t **data, | ||
size_t *dlen, | ||
size_t nbytes) | ||
{ | ||
*data += nbytes; | ||
*dlen -= nbytes; | ||
} | ||
|
||
static uint8_t qcrypto_der_cut_byte(const uint8_t **data, size_t *dlen) | ||
{ | ||
uint8_t val = qcrypto_der_peek_byte(data, dlen); | ||
|
||
qcrypto_der_cut_nbytes(data, dlen, 1); | ||
|
||
return val; | ||
} | ||
|
||
static int qcrypto_der_invoke_callback(QCryptoDERDecodeCb cb, void *ctx, | ||
const uint8_t *value, size_t vlen, | ||
Error **errp) | ||
{ | ||
if (!cb) { | ||
return 0; | ||
} | ||
|
||
return cb(ctx, value, vlen, errp); | ||
} | ||
|
||
static int qcrypto_der_extract_definite_data(const uint8_t **data, size_t *dlen, | ||
QCryptoDERDecodeCb cb, void *ctx, | ||
Error **errp) | ||
{ | ||
const uint8_t *value; | ||
size_t vlen = 0; | ||
uint8_t byte_count = qcrypto_der_cut_byte(data, dlen); | ||
|
||
/* short format of definite-length */ | ||
if (!(byte_count & QCRYPTO_DER_SHORT_LEN_MASK)) { | ||
if (byte_count > *dlen) { | ||
error_setg(errp, "Invalid content length: %u", byte_count); | ||
return -1; | ||
} | ||
|
||
value = *data; | ||
vlen = byte_count; | ||
qcrypto_der_cut_nbytes(data, dlen, vlen); | ||
|
||
if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) { | ||
return -1; | ||
} | ||
return vlen; | ||
} | ||
|
||
/* Ignore highest bit */ | ||
byte_count &= ~QCRYPTO_DER_SHORT_LEN_MASK; | ||
|
||
/* | ||
* size_t is enough to store the value of length, although the DER | ||
* encoding standard supports larger length. | ||
*/ | ||
if (byte_count > sizeof(size_t)) { | ||
error_setg(errp, "Invalid byte count of content length: %u", | ||
byte_count); | ||
return -1; | ||
} | ||
|
||
if (byte_count > *dlen) { | ||
error_setg(errp, "Invalid content length: %u", byte_count); | ||
return -1; | ||
} | ||
while (byte_count--) { | ||
vlen <<= 8; | ||
vlen += qcrypto_der_cut_byte(data, dlen); | ||
} | ||
|
||
if (vlen > *dlen) { | ||
error_setg(errp, "Invalid content length: %zu", vlen); | ||
return -1; | ||
} | ||
|
||
value = *data; | ||
qcrypto_der_cut_nbytes(data, dlen, vlen); | ||
|
||
if (qcrypto_der_invoke_callback(cb, ctx, value, vlen, errp) != 0) { | ||
return -1; | ||
} | ||
return vlen; | ||
} | ||
|
||
static int qcrypto_der_extract_data(const uint8_t **data, size_t *dlen, | ||
QCryptoDERDecodeCb cb, void *ctx, | ||
Error **errp) | ||
{ | ||
uint8_t val; | ||
if (*dlen < 1) { | ||
error_setg(errp, "Need more data"); | ||
return -1; | ||
} | ||
val = qcrypto_der_peek_byte(data, dlen); | ||
|
||
/* must use definite length format */ | ||
if (val == QCRYPTO_DER_SHORT_LEN_MASK) { | ||
error_setg(errp, "Only definite length format is allowed"); | ||
return -1; | ||
} | ||
|
||
return qcrypto_der_extract_definite_data(data, dlen, cb, ctx, errp); | ||
} | ||
|
||
int qcrypto_der_decode_int(const uint8_t **data, size_t *dlen, | ||
QCryptoDERDecodeCb cb, void *ctx, Error **errp) | ||
{ | ||
uint8_t tag; | ||
if (*dlen < 1) { | ||
error_setg(errp, "Need more data"); | ||
return -1; | ||
} | ||
tag = qcrypto_der_cut_byte(data, dlen); | ||
|
||
/* INTEGER must encoded in primitive-form */ | ||
if (tag != QCRYPTO_DER_TYPE_TAG_INT) { | ||
error_setg(errp, "Invalid integer type tag: %u", tag); | ||
return -1; | ||
} | ||
|
||
return qcrypto_der_extract_data(data, dlen, cb, ctx, errp); | ||
} | ||
|
||
int qcrypto_der_decode_seq(const uint8_t **data, size_t *dlen, | ||
QCryptoDERDecodeCb cb, void *ctx, Error **errp) | ||
{ | ||
uint8_t tag; | ||
if (*dlen < 1) { | ||
error_setg(errp, "Need more data"); | ||
return -1; | ||
} | ||
tag = qcrypto_der_cut_byte(data, dlen); | ||
|
||
/* SEQUENCE must use constructed form */ | ||
if (tag != (QCRYPTO_DER_TYPE_TAG_SEQ | QCRYPTO_DER_CONSTRUCTED_MASK)) { | ||
error_setg(errp, "Invalid type sequence tag: %u", tag); | ||
return -1; | ||
} | ||
|
||
return qcrypto_der_extract_data(data, dlen, cb, ctx, errp); | ||
} |
Oops, something went wrong.