Merge crypto and other misc fixes / features
* Increase minimum gnutls to 3.7.5
* Increase minimum libgcrypt to 1.9.4
* Increase minimum nettle to 3.7.3
* Drop obsolete in-tree XTS impl
* Fix memory leak when loading certificates
* Remove/reduce duplication when loading certifcates
* Fix possible crash when certificates are unloaded
while an active TLS connection is using when in a
TLS handshake operation
* Deprecate use of dh-params.pem file
* Document how to create certificates with Post-Quantum
Cryptography compliant algorithms.
* Support loading multiple certificate identities to
allow support for Post-Quantum crypto in parallel
with traditional RSA/ECC
* Add "-run-with exit-with-parent=on" parameter
* Flush pending errors when seeing ENOBUFS with
a zero-copy send attempt
* Fix data buffer parameters in hash & IO channel APIs
to use 'void *'
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmkIr/8ACgkQvobrtBUQ
T9+2RhAAhEak/krdlTJw8OlJonUop7G5mlLU2TEoX0duRORcFhScsdSwb2pyc/wM
tnwfWXsnsKFItJx1y3STkOICtdNqizGoU3+c7wl4anQBurydu+XTs4ESBtVJtMYr
1lTYvp0HFyKvaXwDWKE+ztltlJiog51tHPDLUIBCnyJysLVqxCHMHmkbG46IPBZo
A2XXxp3j/VBPmhls0JHpbAD4iVE3PChdK7zhyeGe/rld9+0JA12EPCvZ5Uokdj41
aYP/okvnVH1atucoygPdDE3P5GYBKaSXZUWqzfkKhU7FgaF2863Td7ff1ip+WyWN
FFPNEU1hVg+T5hfsZVQmmIFDdSJWqoZaZM/WJVYdrRY4dKUCPnJ9OINbbnhuWz5E
JFmZOPibRZKQ44XcHX49JRfJEBvoq1z9OT1r7HkEP4D9/O7V/riIunbAESMk0sgi
0/fatvdhNKMN6YBQM3mtN3yNOcfRSWFtSy9XS9zDjdpEKT7ui2t9FC0ZNSP0FRkS
aTY31FyacjHwU3zaoh6NoqqpxV9wwHrgsJwNbA/IztjmX/jvGG0Gb/sXVEqM59tR
e3VWTmlmZ1T8OLImh1hG4t+nY+XzI64QpVX8H9RCGm21o28DyTcOnTFK4OyIfWe5
ttnNfEJN8WCVCsA8tcM8yAbZ/0qXrYfiZSO7hq79wE7LvyholAQ=
=9ESG
-----END PGP SIGNATURE-----
Merge tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu into staging
Merge crypto and other misc fixes / features
* Increase minimum gnutls to 3.7.5
* Increase minimum libgcrypt to 1.9.4
* Increase minimum nettle to 3.7.3
* Drop obsolete in-tree XTS impl
* Fix memory leak when loading certificates
* Remove/reduce duplication when loading certifcates
* Fix possible crash when certificates are unloaded
while an active TLS connection is using when in a
TLS handshake operation
* Deprecate use of dh-params.pem file
* Document how to create certificates with Post-Quantum
Cryptography compliant algorithms.
* Support loading multiple certificate identities to
allow support for Post-Quantum crypto in parallel
with traditional RSA/ECC
* Add "-run-with exit-with-parent=on" parameter
* Flush pending errors when seeing ENOBUFS with
a zero-copy send attempt
* Fix data buffer parameters in hash & IO channel APIs
to use 'void *'
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmkIr/8ACgkQvobrtBUQ
# T9+2RhAAhEak/krdlTJw8OlJonUop7G5mlLU2TEoX0duRORcFhScsdSwb2pyc/wM
# tnwfWXsnsKFItJx1y3STkOICtdNqizGoU3+c7wl4anQBurydu+XTs4ESBtVJtMYr
# 1lTYvp0HFyKvaXwDWKE+ztltlJiog51tHPDLUIBCnyJysLVqxCHMHmkbG46IPBZo
# A2XXxp3j/VBPmhls0JHpbAD4iVE3PChdK7zhyeGe/rld9+0JA12EPCvZ5Uokdj41
# aYP/okvnVH1atucoygPdDE3P5GYBKaSXZUWqzfkKhU7FgaF2863Td7ff1ip+WyWN
# FFPNEU1hVg+T5hfsZVQmmIFDdSJWqoZaZM/WJVYdrRY4dKUCPnJ9OINbbnhuWz5E
# JFmZOPibRZKQ44XcHX49JRfJEBvoq1z9OT1r7HkEP4D9/O7V/riIunbAESMk0sgi
# 0/fatvdhNKMN6YBQM3mtN3yNOcfRSWFtSy9XS9zDjdpEKT7ui2t9FC0ZNSP0FRkS
# aTY31FyacjHwU3zaoh6NoqqpxV9wwHrgsJwNbA/IztjmX/jvGG0Gb/sXVEqM59tR
# e3VWTmlmZ1T8OLImh1hG4t+nY+XzI64QpVX8H9RCGm21o28DyTcOnTFK4OyIfWe5
# ttnNfEJN8WCVCsA8tcM8yAbZ/0qXrYfiZSO7hq79wE7LvyholAQ=
# =9ESG
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 03 Nov 2025 02:37:03 PM CET
# gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [unknown]
# gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF
* tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu: (32 commits)
docs: creation of x509 certs compliant with post-quantum crypto
crypto: support upto 5 parallel certificate identities
crypto: expand logic to cope with multiple certificate identities
crypto: avoid loading the identity certs twice
crypto: avoid loading the CA certs twice
crypto: deprecate use of external dh-params.pem file
crypto: make TLS credentials structs private
crypto: fix lifecycle handling of gnutls credentials objects
crypto: introduce a wrapper around gnutls credentials
crypto: introduce method for reloading TLS creds
crypto: reduce duplication in handling TLS priority strings
crypto: remove duplication loading x509 CA cert
crypto: shorten the endpoint == server check in TLS creds
crypto: move release of DH parameters into TLS creds parent
crypto: remove needless indirection via parent_obj field
crypto: use g_autofree when loading x509 credentials
crypto: move check for TLS creds 'dir' property
crypto: remove redundant access() checks before loading certs
crypto: replace stat() with access() for credential checks
crypto: add missing free of certs array
...
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
e9c692eabb
42 changed files with 1216 additions and 1533 deletions
|
|
@ -23,10 +23,6 @@
|
|||
|
||||
#include <gnutls/crypto.h>
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030608
|
||||
#define QEMU_GNUTLS_XTS
|
||||
#endif
|
||||
|
||||
bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
|
||||
QCryptoCipherMode mode)
|
||||
{
|
||||
|
|
@ -44,7 +40,6 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
#ifdef QEMU_GNUTLS_XTS
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALGO_AES_128:
|
||||
|
|
@ -53,7 +48,6 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
|
|||
default:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -241,7 +235,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
|
|||
int err;
|
||||
|
||||
switch (mode) {
|
||||
#ifdef QEMU_GNUTLS_XTS
|
||||
case QCRYPTO_CIPHER_MODE_XTS:
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALGO_AES_128:
|
||||
|
|
@ -254,7 +247,6 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
|
|||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
#include "crypto/xts.h"
|
||||
#endif
|
||||
|
||||
#include <nettle/nettle-types.h>
|
||||
#include <nettle/aes.h>
|
||||
#include <nettle/des.h>
|
||||
|
|
@ -30,9 +26,7 @@
|
|||
#include <nettle/serpent.h>
|
||||
#include <nettle/twofish.h>
|
||||
#include <nettle/ctr.h>
|
||||
#ifndef CONFIG_QEMU_PRIVATE_XTS
|
||||
#include <nettle/xts.h>
|
||||
#endif
|
||||
#ifdef CONFIG_CRYPTO_SM4
|
||||
#include <nettle/sm4.h>
|
||||
#endif
|
||||
|
|
@ -154,43 +148,6 @@ static const struct QCryptoCipherDriver NAME##_driver_ctr = { \
|
|||
};
|
||||
|
||||
|
||||
#ifdef CONFIG_QEMU_PRIVATE_XTS
|
||||
#define DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static void NAME##_xts_wrape(const void *ctx, size_t length, \
|
||||
uint8_t *dst, const uint8_t *src) \
|
||||
{ \
|
||||
ENCRYPT((const void *)ctx, length, dst, src); \
|
||||
} \
|
||||
static void NAME##_xts_wrapd(const void *ctx, size_t length, \
|
||||
uint8_t *dst, const uint8_t *src) \
|
||||
{ \
|
||||
DECRYPT((const void *)ctx, length, dst, src); \
|
||||
} \
|
||||
static int NAME##_encrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
xts_encrypt(&ctx->key, &ctx->key_xts, \
|
||||
NAME##_xts_wrape, NAME##_xts_wrapd, \
|
||||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
} \
|
||||
static int NAME##_decrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
{ \
|
||||
TYPE *ctx = container_of(cipher, TYPE, base); \
|
||||
if (!qcrypto_length_check(len, BLEN, errp)) { \
|
||||
return -1; \
|
||||
} \
|
||||
xts_decrypt(&ctx->key, &ctx->key_xts, \
|
||||
NAME##_xts_wrape, NAME##_xts_wrapd, \
|
||||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
}
|
||||
#else
|
||||
#define DEFINE__XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
static int NAME##_encrypt_xts(QCryptoCipher *cipher, const void *in, \
|
||||
void *out, size_t len, Error **errp) \
|
||||
|
|
@ -214,7 +171,6 @@ static int NAME##_decrypt_xts(QCryptoCipher *cipher, const void *in, \
|
|||
ctx->iv, len, out, in); \
|
||||
return 0; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DEFINE_XTS(NAME, TYPE, BLEN, ENCRYPT, DECRYPT) \
|
||||
QEMU_BUILD_BUG_ON(BLEN != XTS_BLOCK_SIZE); \
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgo alg,
|
|||
#include "cipher-gcrypt.c.inc"
|
||||
#elif defined CONFIG_NETTLE
|
||||
#include "cipher-nettle.c.inc"
|
||||
#elif defined CONFIG_GNUTLS_CRYPTO
|
||||
#elif defined CONFIG_GNUTLS
|
||||
#include "cipher-gnutls.c.inc"
|
||||
#else
|
||||
#include "cipher-stub.c.inc"
|
||||
|
|
|
|||
|
|
@ -67,13 +67,13 @@ int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
|
|||
|
||||
|
||||
int qcrypto_hash_bytes(QCryptoHashAlgo alg,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (char *)buf,
|
||||
struct iovec iov = { .iov_base = (void *)buf,
|
||||
.iov_len = len };
|
||||
return qcrypto_hash_bytesv(alg, &iov, 1, result, resultlen, errp);
|
||||
}
|
||||
|
|
@ -89,11 +89,11 @@ int qcrypto_hash_updatev(QCryptoHash *hash,
|
|||
}
|
||||
|
||||
int qcrypto_hash_update(QCryptoHash *hash,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
|
||||
struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
|
||||
|
||||
return qcrypto_hash_updatev(hash, &iov, 1, errp);
|
||||
}
|
||||
|
|
@ -206,12 +206,12 @@ int qcrypto_hash_digestv(QCryptoHashAlgo alg,
|
|||
}
|
||||
|
||||
int qcrypto_hash_digest(QCryptoHashAlgo alg,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
char **digest,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
|
||||
struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
|
||||
|
||||
return qcrypto_hash_digestv(alg, &iov, 1, digest, errp);
|
||||
}
|
||||
|
|
@ -237,12 +237,12 @@ int qcrypto_hash_base64v(QCryptoHashAlgo alg,
|
|||
}
|
||||
|
||||
int qcrypto_hash_base64(QCryptoHashAlgo alg,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
char **base64,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = { .iov_base = (char *)buf, .iov_len = len };
|
||||
struct iovec iov = { .iov_base = (void *)buf, .iov_len = len };
|
||||
|
||||
return qcrypto_hash_base64v(alg, &iov, 1, base64, errp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,14 +28,14 @@ int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
|||
}
|
||||
|
||||
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = (char *)buf,
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = len
|
||||
};
|
||||
|
||||
|
|
@ -70,13 +70,13 @@ int qcrypto_hmac_digestv(QCryptoHmac *hmac,
|
|||
}
|
||||
|
||||
int qcrypto_hmac_digest(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
char **digest,
|
||||
Error **errp)
|
||||
{
|
||||
struct iovec iov = {
|
||||
.iov_base = (char *)buf,
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = len
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@ crypto_ss.add(files(
|
|||
))
|
||||
|
||||
if gnutls.found()
|
||||
crypto_ss.add(files('x509-utils.c'))
|
||||
crypto_ss.add(files(
|
||||
'tlscredsbox.c',
|
||||
'x509-utils.c',
|
||||
))
|
||||
endif
|
||||
|
||||
if nettle.found()
|
||||
|
|
@ -33,12 +36,9 @@ if nettle.found()
|
|||
if hogweed.found()
|
||||
crypto_ss.add(gmp, hogweed)
|
||||
endif
|
||||
if xts == 'private'
|
||||
crypto_ss.add(files('xts.c'))
|
||||
endif
|
||||
elif gcrypt.found()
|
||||
crypto_ss.add(gcrypt, files('hash-gcrypt.c', 'hmac-gcrypt.c', 'pbkdf-gcrypt.c'))
|
||||
elif gnutls_crypto.found()
|
||||
elif gnutls.found()
|
||||
crypto_ss.add(gnutls, files('hash-gnutls.c', 'hmac-gnutls.c', 'pbkdf-gnutls.c'))
|
||||
else
|
||||
crypto_ss.add(files('hash-glib.c', 'hmac-glib.c', 'pbkdf-stub.c'))
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qapi-types-crypto.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "tlscredspriv.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
|
@ -38,22 +39,7 @@ qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
|
|||
|
||||
trace_qcrypto_tls_creds_load_dh(creds, filename ? filename : "<generated>");
|
||||
|
||||
if (filename == NULL) {
|
||||
ret = gnutls_dh_params_init(dh_params);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to initialize DH parameters: %s",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
ret = gnutls_dh_params_generate2(*dh_params, DH_BITS);
|
||||
if (ret < 0) {
|
||||
gnutls_dh_params_deinit(*dh_params);
|
||||
*dh_params = NULL;
|
||||
error_setg(errp, "Unable to generate DH parameters: %s",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (filename != NULL) {
|
||||
GError *gerr = NULL;
|
||||
gchar *contents;
|
||||
gsize len;
|
||||
|
|
@ -67,6 +53,10 @@ qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
|
|||
g_error_free(gerr);
|
||||
return -1;
|
||||
}
|
||||
warn_report_once("Use of an external DH parameters file '%s' is "
|
||||
"deprecated and will be removed in a future release",
|
||||
filename);
|
||||
|
||||
data.data = (unsigned char *)contents;
|
||||
data.size = len;
|
||||
ret = gnutls_dh_params_init(dh_params);
|
||||
|
|
@ -87,12 +77,22 @@ qcrypto_tls_creds_get_dh_params_file(QCryptoTLSCreds *creds,
|
|||
filename, gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
*dh_params = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
qcrypto_tls_creds_build_path(QCryptoTLSCreds *creds,
|
||||
const char *filename)
|
||||
{
|
||||
return g_strdup_printf("%s/%s", creds->dir, filename);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
|
||||
const char *filename,
|
||||
|
|
@ -100,21 +100,11 @@ qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
|
|||
char **cred,
|
||||
Error **errp)
|
||||
{
|
||||
struct stat sb;
|
||||
int ret = -1;
|
||||
|
||||
if (!creds->dir) {
|
||||
if (required) {
|
||||
error_setg(errp, "Missing 'dir' property value");
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*cred = qcrypto_tls_creds_build_path(creds, filename);
|
||||
|
||||
*cred = g_strdup_printf("%s/%s", creds->dir, filename);
|
||||
|
||||
if (stat(*cred, &sb) < 0) {
|
||||
if (access(*cred, R_OK) < 0) {
|
||||
if (errno == ENOENT && !required) {
|
||||
ret = 0;
|
||||
} else {
|
||||
|
|
@ -256,6 +246,9 @@ qcrypto_tls_creds_finalize(Object *obj)
|
|||
{
|
||||
QCryptoTLSCreds *creds = QCRYPTO_TLS_CREDS(obj);
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
qcrypto_tls_creds_box_unref(creds->box);
|
||||
#endif
|
||||
g_free(creds->dir);
|
||||
g_free(creds->priority);
|
||||
}
|
||||
|
|
@ -272,6 +265,36 @@ bool qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds *creds,
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
char *qcrypto_tls_creds_get_priority(QCryptoTLSCreds *creds)
|
||||
{
|
||||
QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_GET_CLASS(creds);
|
||||
const char *priorityBase =
|
||||
creds->priority ? creds->priority : CONFIG_TLS_PRIORITY;
|
||||
|
||||
if (tcc->prioritySuffix) {
|
||||
return g_strdup_printf("%s:%s", priorityBase, tcc->prioritySuffix);
|
||||
} else {
|
||||
return g_strdup(priorityBase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool qcrypto_tls_creds_reload(QCryptoTLSCreds *creds,
|
||||
Error **errp)
|
||||
{
|
||||
QCryptoTLSCredsClass *credscls = QCRYPTO_TLS_CREDS_GET_CLASS(creds);
|
||||
|
||||
if (credscls->reload) {
|
||||
return credscls->reload(creds, errp);
|
||||
}
|
||||
|
||||
error_setg(errp, "%s does not support reloading credentials",
|
||||
object_get_typename(OBJECT(creds)));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static const TypeInfo qcrypto_tls_creds_info = {
|
||||
.parent = TYPE_OBJECT,
|
||||
.name = TYPE_QCRYPTO_TLS_CREDS,
|
||||
|
|
|
|||
|
|
@ -27,15 +27,19 @@
|
|||
#include "trace.h"
|
||||
|
||||
|
||||
struct QCryptoTLSCredsAnon {
|
||||
QCryptoTLSCreds parent_obj;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
|
||||
Error **errp)
|
||||
{
|
||||
g_autoptr(QCryptoTLSCredsBox) box = NULL;
|
||||
g_autofree char *dhparams = NULL;
|
||||
int ret;
|
||||
|
||||
|
|
@ -43,13 +47,16 @@ qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
|
|||
creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
|
||||
|
||||
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_ANON);
|
||||
|
||||
if (creds->parent_obj.dir &&
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_DH_PARAMS,
|
||||
false, &dhparams, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gnutls_anon_allocate_server_credentials(&creds->data.server);
|
||||
ret = gnutls_anon_allocate_server_credentials(&box->data.anonserver);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot allocate credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
|
|
@ -57,46 +64,28 @@ qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds,
|
|||
}
|
||||
|
||||
if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
|
||||
&creds->parent_obj.dh_params,
|
||||
errp) < 0) {
|
||||
&box->dh_params, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
gnutls_anon_set_server_dh_params(creds->data.server,
|
||||
creds->parent_obj.dh_params);
|
||||
if (box->dh_params) {
|
||||
gnutls_anon_set_server_dh_params(box->data.anonserver,
|
||||
box->dh_params);
|
||||
}
|
||||
} else {
|
||||
ret = gnutls_anon_allocate_client_credentials(&creds->data.client);
|
||||
ret = gnutls_anon_allocate_client_credentials(&box->data.anonclient);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot allocate credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
creds->parent_obj.box = g_steal_pointer(&box);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds)
|
||||
{
|
||||
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
|
||||
if (creds->data.client) {
|
||||
gnutls_anon_free_client_credentials(creds->data.client);
|
||||
creds->data.client = NULL;
|
||||
}
|
||||
} else {
|
||||
if (creds->data.server) {
|
||||
gnutls_anon_free_server_credentials(creds->data.server);
|
||||
creds->data.server = NULL;
|
||||
}
|
||||
}
|
||||
if (creds->parent_obj.dh_params) {
|
||||
gnutls_dh_params_deinit(creds->parent_obj.dh_params);
|
||||
creds->parent_obj.dh_params = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* ! CONFIG_GNUTLS */
|
||||
|
||||
|
||||
|
|
@ -108,13 +97,6 @@ qcrypto_tls_creds_anon_load(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_anon_unload(QCryptoTLSCredsAnon *creds G_GNUC_UNUSED)
|
||||
{
|
||||
/* nada */
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! CONFIG_GNUTLS */
|
||||
|
||||
|
||||
|
|
@ -127,21 +109,14 @@ qcrypto_tls_creds_anon_complete(UserCreatable *uc, Error **errp)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_anon_finalize(Object *obj)
|
||||
{
|
||||
QCryptoTLSCredsAnon *creds = QCRYPTO_TLS_CREDS_ANON(obj);
|
||||
|
||||
qcrypto_tls_creds_anon_unload(creds);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_anon_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_CLASS(oc);
|
||||
|
||||
ucc->complete = qcrypto_tls_creds_anon_complete;
|
||||
tcc->prioritySuffix = "+ANON-DH";
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -149,7 +124,6 @@ static const TypeInfo qcrypto_tls_creds_anon_info = {
|
|||
.parent = TYPE_QCRYPTO_TLS_CREDS,
|
||||
.name = TYPE_QCRYPTO_TLS_CREDS_ANON,
|
||||
.instance_size = sizeof(QCryptoTLSCredsAnon),
|
||||
.instance_finalize = qcrypto_tls_creds_anon_finalize,
|
||||
.class_size = sizeof(QCryptoTLSCredsAnonClass),
|
||||
.class_init = qcrypto_tls_creds_anon_class_init,
|
||||
.interfaces = (const InterfaceInfo[]) {
|
||||
|
|
|
|||
101
crypto/tlscredsbox.c
Normal file
101
crypto/tlscredsbox.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* QEMU crypto TLS credential support
|
||||
*
|
||||
* Copyright (c) 2025 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/tlscredsbox.h"
|
||||
#include "qemu/atomic.h"
|
||||
|
||||
|
||||
static QCryptoTLSCredsBox *
|
||||
qcrypto_tls_creds_box_new_impl(int type, bool server)
|
||||
{
|
||||
QCryptoTLSCredsBox *credsbox = g_new0(QCryptoTLSCredsBox, 1);
|
||||
credsbox->ref = 1;
|
||||
credsbox->server = server;
|
||||
credsbox->type = type;
|
||||
return credsbox;
|
||||
}
|
||||
|
||||
|
||||
QCryptoTLSCredsBox *
|
||||
qcrypto_tls_creds_box_new_server(int type)
|
||||
{
|
||||
return qcrypto_tls_creds_box_new_impl(type, true);
|
||||
}
|
||||
|
||||
|
||||
QCryptoTLSCredsBox *
|
||||
qcrypto_tls_creds_box_new_client(int type)
|
||||
{
|
||||
return qcrypto_tls_creds_box_new_impl(type, false);
|
||||
}
|
||||
|
||||
static void qcrypto_tls_creds_box_free(QCryptoTLSCredsBox *credsbox)
|
||||
{
|
||||
switch (credsbox->type) {
|
||||
case GNUTLS_CRD_CERTIFICATE:
|
||||
if (credsbox->data.cert) {
|
||||
gnutls_certificate_free_credentials(credsbox->data.cert);
|
||||
}
|
||||
break;
|
||||
case GNUTLS_CRD_PSK:
|
||||
if (credsbox->server) {
|
||||
if (credsbox->data.pskserver) {
|
||||
gnutls_psk_free_server_credentials(credsbox->data.pskserver);
|
||||
}
|
||||
} else {
|
||||
if (credsbox->data.pskclient) {
|
||||
gnutls_psk_free_client_credentials(credsbox->data.pskclient);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GNUTLS_CRD_ANON:
|
||||
if (credsbox->server) {
|
||||
if (credsbox->data.anonserver) {
|
||||
gnutls_anon_free_server_credentials(credsbox->data.anonserver);
|
||||
}
|
||||
} else {
|
||||
if (credsbox->data.anonclient) {
|
||||
gnutls_anon_free_client_credentials(credsbox->data.anonclient);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (credsbox->dh_params) {
|
||||
gnutls_dh_params_deinit(credsbox->dh_params);
|
||||
}
|
||||
|
||||
g_free(credsbox);
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_tls_creds_box_ref(QCryptoTLSCredsBox *credsbox)
|
||||
{
|
||||
uint32_t ref = qatomic_fetch_inc(&credsbox->ref);
|
||||
/* Assert waaay before the integer overflows */
|
||||
g_assert(ref < INT_MAX);
|
||||
}
|
||||
|
||||
|
||||
void qcrypto_tls_creds_box_unref(QCryptoTLSCredsBox *credsbox)
|
||||
{
|
||||
if (!credsbox) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert(credsbox->ref > 0);
|
||||
|
||||
if (qatomic_fetch_dec(&credsbox->ref) == 1) {
|
||||
qcrypto_tls_creds_box_free(credsbox);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
50
crypto/tlscredsbox.h
Normal file
50
crypto/tlscredsbox.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* QEMU crypto TLS credential support
|
||||
*
|
||||
* Copyright (c) 2025 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_TLSCREDS_BOX_H
|
||||
#define QCRYPTO_TLSCREDS_BOX_H
|
||||
|
||||
#include "qom/object.h"
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
#include <gnutls/gnutls.h>
|
||||
#endif
|
||||
|
||||
typedef struct QCryptoTLSCredsBox QCryptoTLSCredsBox;
|
||||
|
||||
struct QCryptoTLSCredsBox {
|
||||
uint32_t ref;
|
||||
bool server;
|
||||
int type;
|
||||
union {
|
||||
void *any;
|
||||
#ifdef CONFIG_GNUTLS
|
||||
/*
|
||||
* All of these gnutls_XXXX_credentials_t types are
|
||||
* pointers, hence matching the 'any' field above
|
||||
*/
|
||||
gnutls_anon_server_credentials_t anonserver;
|
||||
gnutls_anon_client_credentials_t anonclient;
|
||||
gnutls_psk_server_credentials_t pskserver;
|
||||
gnutls_psk_client_credentials_t pskclient;
|
||||
gnutls_certificate_credentials_t cert;
|
||||
#endif
|
||||
} data;
|
||||
#ifdef CONFIG_GNUTLS
|
||||
gnutls_dh_params_t dh_params;
|
||||
#endif
|
||||
};
|
||||
|
||||
QCryptoTLSCredsBox *qcrypto_tls_creds_box_new_server(int type);
|
||||
QCryptoTLSCredsBox *qcrypto_tls_creds_box_new_client(int type);
|
||||
void qcrypto_tls_creds_box_ref(QCryptoTLSCredsBox *credsbox);
|
||||
void qcrypto_tls_creds_box_unref(QCryptoTLSCredsBox *credsbox);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsBox, qcrypto_tls_creds_box_unref);
|
||||
|
||||
#endif /* QCRYPTO_TLSCREDS_BOX_H */
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#define QCRYPTO_TLSCREDSPRIV_H
|
||||
|
||||
#include "crypto/tlscreds.h"
|
||||
#include "crypto/tlscredsbox.h"
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
#include <gnutls/gnutls.h>
|
||||
|
|
@ -31,45 +32,16 @@ struct QCryptoTLSCreds {
|
|||
Object parent_obj;
|
||||
char *dir;
|
||||
QCryptoTLSCredsEndpoint endpoint;
|
||||
#ifdef CONFIG_GNUTLS
|
||||
gnutls_dh_params_t dh_params;
|
||||
#endif
|
||||
bool verifyPeer;
|
||||
char *priority;
|
||||
};
|
||||
|
||||
struct QCryptoTLSCredsAnon {
|
||||
QCryptoTLSCreds parent_obj;
|
||||
#ifdef CONFIG_GNUTLS
|
||||
union {
|
||||
gnutls_anon_server_credentials_t server;
|
||||
gnutls_anon_client_credentials_t client;
|
||||
} data;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct QCryptoTLSCredsPSK {
|
||||
QCryptoTLSCreds parent_obj;
|
||||
char *username;
|
||||
#ifdef CONFIG_GNUTLS
|
||||
union {
|
||||
gnutls_psk_server_credentials_t server;
|
||||
gnutls_psk_client_credentials_t client;
|
||||
} data;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct QCryptoTLSCredsX509 {
|
||||
QCryptoTLSCreds parent_obj;
|
||||
#ifdef CONFIG_GNUTLS
|
||||
gnutls_certificate_credentials_t data;
|
||||
#endif
|
||||
bool sanityCheck;
|
||||
char *passwordid;
|
||||
QCryptoTLSCredsBox *box;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
|
||||
char *qcrypto_tls_creds_build_path(QCryptoTLSCreds *creds,
|
||||
const char *filename);
|
||||
|
||||
int qcrypto_tls_creds_get_path(QCryptoTLSCreds *creds,
|
||||
const char *filename,
|
||||
bool required,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,11 @@
|
|||
#include "trace.h"
|
||||
|
||||
|
||||
struct QCryptoTLSCredsPSK {
|
||||
QCryptoTLSCreds parent_obj;
|
||||
char *username;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
|
|
@ -71,6 +76,7 @@ static int
|
|||
qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
||||
Error **errp)
|
||||
{
|
||||
g_autoptr(QCryptoTLSCredsBox) box = NULL;
|
||||
g_autofree char *pskfile = NULL;
|
||||
g_autofree char *dhparams = NULL;
|
||||
const char *username;
|
||||
|
|
@ -81,7 +87,14 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
|||
trace_qcrypto_tls_creds_psk_load(creds,
|
||||
creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
|
||||
|
||||
if (!creds->parent_obj.dir) {
|
||||
error_setg(errp, "Missing 'dir' property value");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_PSK);
|
||||
|
||||
if (creds->username) {
|
||||
error_setg(errp, "username should not be set when endpoint=server");
|
||||
goto cleanup;
|
||||
|
|
@ -96,7 +109,7 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = gnutls_psk_allocate_server_credentials(&creds->data.server);
|
||||
ret = gnutls_psk_allocate_server_credentials(&box->data.pskserver);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot allocate credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
|
|
@ -104,20 +117,25 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
|||
}
|
||||
|
||||
if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
|
||||
&creds->parent_obj.dh_params,
|
||||
&box->dh_params,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = gnutls_psk_set_server_credentials_file(creds->data.server, pskfile);
|
||||
ret = gnutls_psk_set_server_credentials_file(box->data.pskserver,
|
||||
pskfile);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set PSK server credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
goto cleanup;
|
||||
}
|
||||
gnutls_psk_set_server_dh_params(creds->data.server,
|
||||
creds->parent_obj.dh_params);
|
||||
if (box->dh_params) {
|
||||
gnutls_psk_set_server_dh_params(box->data.pskserver,
|
||||
box->dh_params);
|
||||
}
|
||||
} else {
|
||||
box = qcrypto_tls_creds_box_new_client(GNUTLS_CRD_PSK);
|
||||
|
||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_PSKFILE,
|
||||
true, &pskfile, errp) < 0) {
|
||||
|
|
@ -133,14 +151,14 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = gnutls_psk_allocate_client_credentials(&creds->data.client);
|
||||
ret = gnutls_psk_allocate_client_credentials(&box->data.pskclient);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot allocate credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = gnutls_psk_set_client_credentials(creds->data.client,
|
||||
ret = gnutls_psk_set_client_credentials(box->data.pskclient,
|
||||
username, &key, GNUTLS_PSK_KEY_HEX);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set PSK client credentials: %s",
|
||||
|
|
@ -148,6 +166,7 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
|||
goto cleanup;
|
||||
}
|
||||
}
|
||||
creds->parent_obj.box = g_steal_pointer(&box);
|
||||
|
||||
rv = 0;
|
||||
cleanup:
|
||||
|
|
@ -155,27 +174,6 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds,
|
|||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds)
|
||||
{
|
||||
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
|
||||
if (creds->data.client) {
|
||||
gnutls_psk_free_client_credentials(creds->data.client);
|
||||
creds->data.client = NULL;
|
||||
}
|
||||
} else {
|
||||
if (creds->data.server) {
|
||||
gnutls_psk_free_server_credentials(creds->data.server);
|
||||
creds->data.server = NULL;
|
||||
}
|
||||
}
|
||||
if (creds->parent_obj.dh_params) {
|
||||
gnutls_dh_params_deinit(creds->parent_obj.dh_params);
|
||||
creds->parent_obj.dh_params = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* ! CONFIG_GNUTLS */
|
||||
|
||||
|
||||
|
|
@ -187,13 +185,6 @@ qcrypto_tls_creds_psk_load(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_psk_unload(QCryptoTLSCredsPSK *creds G_GNUC_UNUSED)
|
||||
{
|
||||
/* nada */
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! CONFIG_GNUTLS */
|
||||
|
||||
|
||||
|
|
@ -211,7 +202,6 @@ qcrypto_tls_creds_psk_finalize(Object *obj)
|
|||
{
|
||||
QCryptoTLSCredsPSK *creds = QCRYPTO_TLS_CREDS_PSK(obj);
|
||||
|
||||
qcrypto_tls_creds_psk_unload(creds);
|
||||
g_free(creds->username);
|
||||
}
|
||||
|
||||
|
|
@ -239,8 +229,10 @@ static void
|
|||
qcrypto_tls_creds_psk_class_init(ObjectClass *oc, const void *data)
|
||||
{
|
||||
UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc);
|
||||
QCryptoTLSCredsClass *tcc = QCRYPTO_TLS_CREDS_CLASS(oc);
|
||||
|
||||
ucc->complete = qcrypto_tls_creds_psk_complete;
|
||||
tcc->prioritySuffix = "+ECDHE-PSK:+DHE-PSK:+PSK";
|
||||
|
||||
object_class_property_add_str(oc, "username",
|
||||
qcrypto_tls_creds_psk_prop_get_username,
|
||||
|
|
|
|||
|
|
@ -28,12 +28,81 @@
|
|||
#include "trace.h"
|
||||
|
||||
|
||||
struct QCryptoTLSCredsX509 {
|
||||
QCryptoTLSCreds parent_obj;
|
||||
bool sanityCheck;
|
||||
char *passwordid;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GNUTLS
|
||||
|
||||
#include <gnutls/gnutls.h>
|
||||
#include <gnutls/x509.h>
|
||||
|
||||
|
||||
typedef struct QCryptoTLSCredsX509IdentFiles QCryptoTLSCredsX509IdentFiles;
|
||||
struct QCryptoTLSCredsX509IdentFiles {
|
||||
char *certpath;
|
||||
char *keypath;
|
||||
gnutls_x509_crt_t *certs;
|
||||
unsigned int ncerts;
|
||||
gnutls_x509_privkey_t key;
|
||||
};
|
||||
|
||||
typedef struct QCryptoTLSCredsX509Files QCryptoTLSCredsX509Files;
|
||||
struct QCryptoTLSCredsX509Files {
|
||||
char *cacertpath;
|
||||
gnutls_x509_crt_t *cacerts;
|
||||
unsigned int ncacerts;
|
||||
|
||||
QCryptoTLSCredsX509IdentFiles **identities;
|
||||
size_t nidentities;
|
||||
};
|
||||
|
||||
static QCryptoTLSCredsX509Files *
|
||||
qcrypto_tls_creds_x509_files_new(void)
|
||||
{
|
||||
return g_new0(QCryptoTLSCredsX509Files, 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_x509_ident_files_free(QCryptoTLSCredsX509IdentFiles *files)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < files->ncerts; i++) {
|
||||
gnutls_x509_crt_deinit(files->certs[i]);
|
||||
}
|
||||
gnutls_x509_privkey_deinit(files->key);
|
||||
g_free(files->certs);
|
||||
g_free(files->certpath);
|
||||
g_free(files->keypath);
|
||||
g_free(files);
|
||||
}
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509IdentFiles,
|
||||
qcrypto_tls_creds_x509_ident_files_free);
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_x509_files_free(QCryptoTLSCredsX509Files *files)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < files->ncacerts; i++) {
|
||||
gnutls_x509_crt_deinit(files->cacerts[i]);
|
||||
}
|
||||
g_free(files->cacerts);
|
||||
g_free(files->cacertpath);
|
||||
for (i = 0; i < files->nidentities; i++) {
|
||||
qcrypto_tls_creds_x509_ident_files_free(files->identities[i]);
|
||||
}
|
||||
g_free(files->identities);
|
||||
g_free(files);
|
||||
}
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSCredsX509Files,
|
||||
qcrypto_tls_creds_x509_files_free);
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_check_cert_times(gnutls_x509_crt_t cert,
|
||||
const char *certFile,
|
||||
|
|
@ -309,13 +378,10 @@ qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
|
|||
|
||||
static int
|
||||
qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
|
||||
QCryptoTLSCredsX509Files *files,
|
||||
gnutls_x509_crt_t *certs,
|
||||
unsigned int ncerts,
|
||||
gnutls_x509_crt_t *cacerts,
|
||||
unsigned int ncacerts,
|
||||
const char *cacertFile,
|
||||
bool isServer,
|
||||
bool isCA,
|
||||
Error **errp)
|
||||
{
|
||||
gnutls_x509_crt_t cert_to_check = certs[ncerts - 1];
|
||||
|
|
@ -355,13 +421,13 @@ qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
|
|||
* reached the root of trust.
|
||||
*/
|
||||
return qcrypto_tls_creds_check_cert(
|
||||
creds, cert_to_check, cacertFile,
|
||||
isServer, isCA, errp);
|
||||
creds, cert_to_check, files->cacertpath,
|
||||
isServer, true, errp);
|
||||
}
|
||||
for (int i = 0; i < ncacerts; i++) {
|
||||
for (int i = 0; i < files->ncacerts; i++) {
|
||||
if (gnutls_x509_crt_check_issuer(cert_to_check,
|
||||
cacerts[i])) {
|
||||
cert_issuer = cacerts[i];
|
||||
files->cacerts[i])) {
|
||||
cert_issuer = files->cacerts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -369,8 +435,8 @@ qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
|
|||
break;
|
||||
}
|
||||
|
||||
if (qcrypto_tls_creds_check_cert(creds, cert_issuer, cacertFile,
|
||||
isServer, isCA, errp) < 0) {
|
||||
if (qcrypto_tls_creds_check_cert(creds, cert_issuer, files->cacertpath,
|
||||
isServer, true, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -389,19 +455,17 @@ qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
|
|||
}
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t *certs,
|
||||
qcrypto_tls_creds_check_cert_pair(QCryptoTLSCredsX509Files *files,
|
||||
gnutls_x509_crt_t *certs,
|
||||
size_t ncerts,
|
||||
const char *certFile,
|
||||
gnutls_x509_crt_t *cacerts,
|
||||
size_t ncacerts,
|
||||
const char *cacertFile,
|
||||
bool isServer,
|
||||
Error **errp)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
if (gnutls_x509_crt_list_verify(certs, ncerts,
|
||||
cacerts, ncacerts,
|
||||
files->cacerts, files->ncacerts,
|
||||
NULL, 0,
|
||||
0, &status) < 0) {
|
||||
error_setg(errp, isServer ?
|
||||
|
|
@ -409,7 +473,7 @@ qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t *certs,
|
|||
"CA certificate %s" :
|
||||
"Unable to verify client certificate %s against "
|
||||
"CA certificate %s",
|
||||
certFile, cacertFile);
|
||||
certFile, files->cacertpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -434,7 +498,7 @@ qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t *certs,
|
|||
|
||||
error_setg(errp,
|
||||
"Our own certificate %s failed validation against %s: %s",
|
||||
certFile, cacertFile, reason);
|
||||
certFile, files->cacertpath, reason);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -447,14 +511,13 @@ qcrypto_tls_creds_load_cert_list(QCryptoTLSCredsX509 *creds,
|
|||
const char *certFile,
|
||||
gnutls_x509_crt_t **certs,
|
||||
unsigned int *ncerts,
|
||||
bool isServer,
|
||||
bool isCA,
|
||||
Error **errp)
|
||||
{
|
||||
gnutls_datum_t data;
|
||||
g_autofree char *buf = NULL;
|
||||
gsize buflen;
|
||||
GError *gerr = NULL;
|
||||
int ret;
|
||||
|
||||
*ncerts = 0;
|
||||
trace_qcrypto_tls_creds_x509_load_cert_list(creds, certFile);
|
||||
|
|
@ -469,13 +532,94 @@ qcrypto_tls_creds_load_cert_list(QCryptoTLSCredsX509 *creds,
|
|||
data.data = (unsigned char *)buf;
|
||||
data.size = strlen(buf);
|
||||
|
||||
if (gnutls_x509_crt_list_import2(certs, ncerts, &data,
|
||||
GNUTLS_X509_FMT_PEM, 0) < 0) {
|
||||
error_setg(errp,
|
||||
isCA ? "Unable to import CA certificate list %s" :
|
||||
(isServer ? "Unable to import server certificate %s" :
|
||||
"Unable to import client certificate %s"),
|
||||
certFile);
|
||||
ret = gnutls_x509_crt_list_import2(certs, ncerts, &data,
|
||||
GNUTLS_X509_FMT_PEM, 0);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to import certificate %s: %s",
|
||||
certFile, gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_load_privkey(QCryptoTLSCredsX509 *creds,
|
||||
const char *keyFile,
|
||||
gnutls_x509_privkey_t *key,
|
||||
Error **errp)
|
||||
{
|
||||
gnutls_datum_t data;
|
||||
g_autofree char *buf = NULL;
|
||||
g_autofree char *password = NULL;
|
||||
gsize buflen;
|
||||
GError *gerr = NULL;
|
||||
int ret;
|
||||
|
||||
ret = gnutls_x509_privkey_init(key);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to initialize private key: %s",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_file_get_contents(keyFile, &buf, &buflen, &gerr)) {
|
||||
error_setg(errp, "Cannot load private key %s: %s",
|
||||
keyFile, gerr->message);
|
||||
g_error_free(gerr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data.data = (unsigned char *)buf;
|
||||
data.size = strlen(buf);
|
||||
|
||||
if (creds->passwordid) {
|
||||
password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
|
||||
errp);
|
||||
if (!password) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (gnutls_x509_privkey_import2(*key, &data,
|
||||
GNUTLS_X509_FMT_PEM,
|
||||
password, 0) < 0) {
|
||||
error_setg(errp, "Unable to import private key %s", keyFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_x509_sanity_check_identity(QCryptoTLSCredsX509 *creds,
|
||||
QCryptoTLSCredsX509Files *files,
|
||||
QCryptoTLSCredsX509IdentFiles *ifiles,
|
||||
bool isServer,
|
||||
Error **errp)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ifiles->ncerts; i++) {
|
||||
if (qcrypto_tls_creds_check_cert(creds,
|
||||
ifiles->certs[i], ifiles->certpath,
|
||||
isServer, i != 0, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifiles->ncerts &&
|
||||
qcrypto_tls_creds_check_authority_chain(creds, files,
|
||||
ifiles->certs, ifiles->ncerts,
|
||||
isServer, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifiles->ncerts &&
|
||||
qcrypto_tls_creds_check_cert_pair(files, ifiles->certs, ifiles->ncerts,
|
||||
ifiles->certpath, isServer, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -485,78 +629,191 @@ qcrypto_tls_creds_load_cert_list(QCryptoTLSCredsX509 *creds,
|
|||
|
||||
static int
|
||||
qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
|
||||
QCryptoTLSCredsX509Files *files,
|
||||
bool isServer,
|
||||
const char *cacertFile,
|
||||
const char *certFile,
|
||||
Error **errp)
|
||||
{
|
||||
gnutls_x509_crt_t *certs = NULL;
|
||||
unsigned int ncerts = 0;
|
||||
gnutls_x509_crt_t *cacerts = NULL;
|
||||
unsigned int ncacerts = 0;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
if (certFile &&
|
||||
access(certFile, R_OK) == 0) {
|
||||
if (qcrypto_tls_creds_load_cert_list(creds,
|
||||
certFile,
|
||||
&certs,
|
||||
&ncerts,
|
||||
isServer,
|
||||
false,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
for (i = 0; i < files->nidentities; i++) {
|
||||
if (qcrypto_tls_creds_x509_sanity_check_identity(creds,
|
||||
files,
|
||||
files->identities[i],
|
||||
isServer,
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (access(cacertFile, R_OK) == 0) {
|
||||
if (qcrypto_tls_creds_load_cert_list(creds,
|
||||
cacertFile,
|
||||
&cacerts,
|
||||
&ncacerts,
|
||||
isServer,
|
||||
true,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_x509_load_ca(QCryptoTLSCredsX509 *creds,
|
||||
QCryptoTLSCredsBox *box,
|
||||
QCryptoTLSCredsX509Files *files,
|
||||
bool isServer,
|
||||
Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_CA_CERT,
|
||||
true, &files->cacertpath, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qcrypto_tls_creds_load_cert_list(creds,
|
||||
files->cacertpath,
|
||||
&files->cacerts,
|
||||
&files->ncacerts,
|
||||
errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gnutls_certificate_set_x509_trust(box->data.cert,
|
||||
files->cacerts, files->ncacerts);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set CA certificate '%s': %s",
|
||||
files->cacertpath, gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static QCryptoTLSCredsX509IdentFiles *
|
||||
qcrypto_tls_creds_x509_load_identity(QCryptoTLSCredsX509 *creds,
|
||||
QCryptoTLSCredsBox *box,
|
||||
const char *certbase,
|
||||
const char *keybase,
|
||||
Error **errp)
|
||||
{
|
||||
g_autoptr(QCryptoTLSCredsX509IdentFiles) files =
|
||||
g_new0(QCryptoTLSCredsX509IdentFiles, 1);
|
||||
int ret;
|
||||
|
||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj, certbase,
|
||||
false, &files->certpath, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj, keybase,
|
||||
false, &files->keypath, errp) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!files->certpath &&
|
||||
!files->keypath) {
|
||||
return NULL;
|
||||
}
|
||||
if (files->certpath && !files->keypath) {
|
||||
g_autofree char *keypath =
|
||||
qcrypto_tls_creds_build_path(&creds->parent_obj, keybase);
|
||||
error_setg(errp, "Cert '%s' without corresponding key '%s'",
|
||||
files->certpath, keypath);
|
||||
return NULL;
|
||||
}
|
||||
if (!files->certpath && files->keypath) {
|
||||
g_autofree char *certpath =
|
||||
qcrypto_tls_creds_build_path(&creds->parent_obj, certbase);
|
||||
error_setg(errp, "Key '%s' without corresponding cert '%s'",
|
||||
files->keypath, certpath);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qcrypto_tls_creds_load_cert_list(creds,
|
||||
files->certpath,
|
||||
&files->certs,
|
||||
&files->ncerts,
|
||||
errp) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qcrypto_tls_creds_load_privkey(creds,
|
||||
files->keypath,
|
||||
&files->key,
|
||||
errp) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = gnutls_certificate_set_x509_key(box->data.cert,
|
||||
files->certs,
|
||||
files->ncerts,
|
||||
files->key);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set certificate '%s' & key '%s': %s",
|
||||
files->certpath, files->keypath, gnutls_strerror(ret));
|
||||
return NULL;
|
||||
}
|
||||
return g_steal_pointer(&files);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qcrypto_tls_creds_x509_load_identities(QCryptoTLSCredsX509 *creds,
|
||||
QCryptoTLSCredsBox *box,
|
||||
QCryptoTLSCredsX509Files *files,
|
||||
bool isServer,
|
||||
Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
QCryptoTLSCredsX509IdentFiles *ifiles;
|
||||
size_t i;
|
||||
|
||||
ifiles = qcrypto_tls_creds_x509_load_identity(
|
||||
creds, box,
|
||||
isServer ?
|
||||
QCRYPTO_TLS_CREDS_X509_SERVER_CERT :
|
||||
QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
|
||||
isServer ?
|
||||
QCRYPTO_TLS_CREDS_X509_SERVER_KEY :
|
||||
QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
|
||||
errp);
|
||||
if (!ifiles && *errp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ifiles) {
|
||||
files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
|
||||
files->identities,
|
||||
files->nidentities + 1);
|
||||
files->identities[files->nidentities++] = ifiles;
|
||||
}
|
||||
|
||||
for (i = 0; i < QCRYPTO_TLS_CREDS_X509_IDENTITY_MAX; i++) {
|
||||
g_autofree char *cert = g_strdup_printf(
|
||||
isServer ?
|
||||
QCRYPTO_TLS_CREDS_X509_SERVER_CERT_N :
|
||||
QCRYPTO_TLS_CREDS_X509_CLIENT_CERT_N, i);
|
||||
g_autofree char *key = g_strdup_printf(
|
||||
isServer ?
|
||||
QCRYPTO_TLS_CREDS_X509_SERVER_KEY_N :
|
||||
QCRYPTO_TLS_CREDS_X509_CLIENT_KEY_N, i);
|
||||
|
||||
ifiles = qcrypto_tls_creds_x509_load_identity(creds, box,
|
||||
cert, key, errp);
|
||||
if (!ifiles && *errp) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ncerts; i++) {
|
||||
if (qcrypto_tls_creds_check_cert(creds,
|
||||
certs[i], certFile,
|
||||
isServer, i != 0, errp) < 0) {
|
||||
goto cleanup;
|
||||
if (!ifiles) {
|
||||
break;
|
||||
}
|
||||
|
||||
files->identities = g_renew(QCryptoTLSCredsX509IdentFiles *,
|
||||
files->identities,
|
||||
files->nidentities + 1);
|
||||
files->identities[files->nidentities++] = ifiles;
|
||||
}
|
||||
|
||||
if (ncerts &&
|
||||
qcrypto_tls_creds_check_authority_chain(creds,
|
||||
certs, ncerts,
|
||||
cacerts, ncacerts,
|
||||
cacertFile, isServer,
|
||||
true, errp) < 0) {
|
||||
goto cleanup;
|
||||
if (files->nidentities == 0 && isServer) {
|
||||
g_autofree char *certpath = qcrypto_tls_creds_build_path(
|
||||
&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_CERT);
|
||||
g_autofree char *keypath = qcrypto_tls_creds_build_path(
|
||||
&creds->parent_obj, QCRYPTO_TLS_CREDS_X509_SERVER_KEY);
|
||||
error_setg(errp, "Missing server cert '%s' & key '%s'",
|
||||
certpath, keypath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ncerts && ncacerts &&
|
||||
qcrypto_tls_creds_check_cert_pair(certs, ncerts, certFile,
|
||||
cacerts, ncacerts, cacertFile,
|
||||
isServer, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
for (i = 0; i < ncerts; i++) {
|
||||
gnutls_x509_crt_deinit(certs[i]);
|
||||
}
|
||||
for (i = 0; i < ncacerts; i++) {
|
||||
gnutls_x509_crt_deinit(cacerts[i]);
|
||||
}
|
||||
g_free(cacerts);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -564,134 +821,85 @@ static int
|
|||
qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds,
|
||||
Error **errp)
|
||||
{
|
||||
char *cacert = NULL, *cacrl = NULL, *cert = NULL,
|
||||
*key = NULL, *dhparams = NULL;
|
||||
g_autoptr(QCryptoTLSCredsBox) box = NULL;
|
||||
g_autoptr(QCryptoTLSCredsX509Files) files = NULL;
|
||||
g_autofree char *cacrl = NULL;
|
||||
g_autofree char *dhparams = NULL;
|
||||
bool isServer = (creds->parent_obj.endpoint ==
|
||||
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER);
|
||||
int ret;
|
||||
int rv = -1;
|
||||
|
||||
trace_qcrypto_tls_creds_x509_load(creds,
|
||||
creds->parent_obj.dir ? creds->parent_obj.dir : "<nodir>");
|
||||
if (!creds->parent_obj.dir) {
|
||||
error_setg(errp, "Missing 'dir' property value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace_qcrypto_tls_creds_x509_load(creds, creds->parent_obj.dir);
|
||||
|
||||
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
box = qcrypto_tls_creds_box_new_server(GNUTLS_CRD_CERTIFICATE);
|
||||
} else {
|
||||
box = qcrypto_tls_creds_box_new_client(GNUTLS_CRD_CERTIFICATE);
|
||||
}
|
||||
|
||||
ret = gnutls_certificate_allocate_credentials(&box->data.cert);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot allocate credentials: '%s'",
|
||||
gnutls_strerror(ret));
|
||||
return -1;
|
||||
}
|
||||
|
||||
files = qcrypto_tls_creds_x509_files_new();
|
||||
|
||||
if (qcrypto_tls_creds_x509_load_ca(creds, box, files, isServer, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qcrypto_tls_creds_x509_load_identities(creds, box, files,
|
||||
isServer, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isServer) {
|
||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_CA_CERT,
|
||||
true, &cacert, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_CA_CRL,
|
||||
false, &cacrl, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_SERVER_CERT,
|
||||
true, &cert, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_SERVER_KEY,
|
||||
true, &key, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_DH_PARAMS,
|
||||
false, &dhparams, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_CA_CERT,
|
||||
true, &cacert, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_CLIENT_CERT,
|
||||
false, &cert, errp) < 0 ||
|
||||
qcrypto_tls_creds_get_path(&creds->parent_obj,
|
||||
QCRYPTO_TLS_CREDS_X509_CLIENT_KEY,
|
||||
false, &key, errp) < 0) {
|
||||
goto cleanup;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (creds->sanityCheck &&
|
||||
qcrypto_tls_creds_x509_sanity_check(creds,
|
||||
creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
|
||||
cacert, cert, errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = gnutls_certificate_allocate_credentials(&creds->data);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot allocate credentials: '%s'",
|
||||
gnutls_strerror(ret));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = gnutls_certificate_set_x509_trust_file(creds->data,
|
||||
cacert,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot load CA certificate '%s': %s",
|
||||
cacert, gnutls_strerror(ret));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cert != NULL && key != NULL) {
|
||||
char *password = NULL;
|
||||
if (creds->passwordid) {
|
||||
password = qcrypto_secret_lookup_as_utf8(creds->passwordid,
|
||||
errp);
|
||||
if (!password) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
ret = gnutls_certificate_set_x509_key_file2(creds->data,
|
||||
cert, key,
|
||||
GNUTLS_X509_FMT_PEM,
|
||||
password,
|
||||
0);
|
||||
g_free(password);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot load certificate '%s' & key '%s': %s",
|
||||
cert, key, gnutls_strerror(ret));
|
||||
goto cleanup;
|
||||
}
|
||||
qcrypto_tls_creds_x509_sanity_check(creds, files, isServer, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cacrl != NULL) {
|
||||
ret = gnutls_certificate_set_x509_crl_file(creds->data,
|
||||
ret = gnutls_certificate_set_x509_crl_file(box->data.cert,
|
||||
cacrl,
|
||||
GNUTLS_X509_FMT_PEM);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot load CRL '%s': %s",
|
||||
cacrl, gnutls_strerror(ret));
|
||||
goto cleanup;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (creds->parent_obj.endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
if (isServer) {
|
||||
if (qcrypto_tls_creds_get_dh_params_file(&creds->parent_obj, dhparams,
|
||||
&creds->parent_obj.dh_params,
|
||||
&box->dh_params,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
return -1;
|
||||
}
|
||||
if (box->dh_params) {
|
||||
gnutls_certificate_set_dh_params(box->data.cert, box->dh_params);
|
||||
}
|
||||
gnutls_certificate_set_dh_params(creds->data,
|
||||
creds->parent_obj.dh_params);
|
||||
}
|
||||
creds->parent_obj.box = g_steal_pointer(&box);
|
||||
|
||||
rv = 0;
|
||||
cleanup:
|
||||
g_free(cacert);
|
||||
g_free(cacrl);
|
||||
g_free(cert);
|
||||
g_free(key);
|
||||
g_free(dhparams);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds)
|
||||
{
|
||||
if (creds->data) {
|
||||
gnutls_certificate_free_credentials(creds->data);
|
||||
creds->data = NULL;
|
||||
}
|
||||
if (creds->parent_obj.dh_params) {
|
||||
gnutls_dh_params_deinit(creds->parent_obj.dh_params);
|
||||
creds->parent_obj.dh_params = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -706,13 +914,6 @@ qcrypto_tls_creds_x509_load(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED,
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
qcrypto_tls_creds_x509_unload(QCryptoTLSCredsX509 *creds G_GNUC_UNUSED)
|
||||
{
|
||||
/* nada */
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! CONFIG_GNUTLS */
|
||||
|
||||
|
||||
|
|
@ -775,26 +976,17 @@ qcrypto_tls_creds_x509_reload(QCryptoTLSCreds *creds, Error **errp)
|
|||
{
|
||||
QCryptoTLSCredsX509 *x509_creds = QCRYPTO_TLS_CREDS_X509(creds);
|
||||
Error *local_err = NULL;
|
||||
gnutls_certificate_credentials_t creds_data = x509_creds->data;
|
||||
gnutls_dh_params_t creds_dh_params = x509_creds->parent_obj.dh_params;
|
||||
QCryptoTLSCredsBox *creds_box = creds->box;
|
||||
|
||||
x509_creds->data = NULL;
|
||||
x509_creds->parent_obj.dh_params = NULL;
|
||||
creds->box = NULL;
|
||||
qcrypto_tls_creds_x509_load(x509_creds, &local_err);
|
||||
if (local_err) {
|
||||
qcrypto_tls_creds_x509_unload(x509_creds);
|
||||
x509_creds->data = creds_data;
|
||||
x509_creds->parent_obj.dh_params = creds_dh_params;
|
||||
creds->box = creds_box;
|
||||
error_propagate(errp, local_err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (creds_data) {
|
||||
gnutls_certificate_free_credentials(creds_data);
|
||||
}
|
||||
if (creds_dh_params) {
|
||||
gnutls_dh_params_deinit(creds_dh_params);
|
||||
}
|
||||
qcrypto_tls_creds_box_unref(creds_box);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -827,7 +1019,6 @@ qcrypto_tls_creds_x509_finalize(Object *obj)
|
|||
QCryptoTLSCredsX509 *creds = QCRYPTO_TLS_CREDS_X509(obj);
|
||||
|
||||
g_free(creds->passwordid);
|
||||
qcrypto_tls_creds_x509_unload(creds);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
struct QCryptoTLSSession {
|
||||
QCryptoTLSCreds *creds;
|
||||
QCryptoTLSCredsBox *credsbox;
|
||||
gnutls_session_t handle;
|
||||
char *hostname;
|
||||
char *authzid;
|
||||
|
|
@ -78,6 +79,7 @@ qcrypto_tls_session_free(QCryptoTLSSession *session)
|
|||
g_free(session->hostname);
|
||||
g_free(session->peername);
|
||||
g_free(session->authzid);
|
||||
qcrypto_tls_creds_box_unref(session->credsbox);
|
||||
object_unref(OBJECT(session->creds));
|
||||
qemu_mutex_destroy(&session->lock);
|
||||
g_free(session);
|
||||
|
|
@ -155,9 +157,6 @@ qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
|
|||
}
|
||||
}
|
||||
|
||||
#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
|
||||
#define TLS_PRIORITY_ADDITIONAL_PSK "+ECDHE-PSK:+DHE-PSK:+PSK"
|
||||
|
||||
QCryptoTLSSession *
|
||||
qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
||||
const char *hostname,
|
||||
|
|
@ -167,6 +166,7 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
|||
{
|
||||
QCryptoTLSSession *session;
|
||||
int ret;
|
||||
g_autofree char *prio = NULL;
|
||||
|
||||
session = g_new0(QCryptoTLSSession, 1);
|
||||
trace_qcrypto_tls_session_new(
|
||||
|
|
@ -200,113 +200,41 @@ qcrypto_tls_session_new(QCryptoTLSCreds *creds,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (object_dynamic_cast(OBJECT(creds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_ANON)) {
|
||||
QCryptoTLSCredsAnon *acreds = QCRYPTO_TLS_CREDS_ANON(creds);
|
||||
char *prio;
|
||||
|
||||
if (creds->priority != NULL) {
|
||||
prio = g_strdup_printf("%s:%s",
|
||||
creds->priority,
|
||||
TLS_PRIORITY_ADDITIONAL_ANON);
|
||||
} else {
|
||||
prio = g_strdup(CONFIG_TLS_PRIORITY ":"
|
||||
TLS_PRIORITY_ADDITIONAL_ANON);
|
||||
}
|
||||
|
||||
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to set TLS session priority %s: %s",
|
||||
prio, gnutls_strerror(ret));
|
||||
g_free(prio);
|
||||
goto error;
|
||||
}
|
||||
g_free(prio);
|
||||
if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
ret = gnutls_credentials_set(session->handle,
|
||||
GNUTLS_CRD_ANON,
|
||||
acreds->data.server);
|
||||
} else {
|
||||
ret = gnutls_credentials_set(session->handle,
|
||||
GNUTLS_CRD_ANON,
|
||||
acreds->data.client);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set session credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
} else if (object_dynamic_cast(OBJECT(creds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_PSK)) {
|
||||
QCryptoTLSCredsPSK *pcreds = QCRYPTO_TLS_CREDS_PSK(creds);
|
||||
char *prio;
|
||||
|
||||
if (creds->priority != NULL) {
|
||||
prio = g_strdup_printf("%s:%s",
|
||||
creds->priority,
|
||||
TLS_PRIORITY_ADDITIONAL_PSK);
|
||||
} else {
|
||||
prio = g_strdup(CONFIG_TLS_PRIORITY ":"
|
||||
TLS_PRIORITY_ADDITIONAL_PSK);
|
||||
}
|
||||
|
||||
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to set TLS session priority %s: %s",
|
||||
prio, gnutls_strerror(ret));
|
||||
g_free(prio);
|
||||
goto error;
|
||||
}
|
||||
g_free(prio);
|
||||
if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
ret = gnutls_credentials_set(session->handle,
|
||||
GNUTLS_CRD_PSK,
|
||||
pcreds->data.server);
|
||||
} else {
|
||||
ret = gnutls_credentials_set(session->handle,
|
||||
GNUTLS_CRD_PSK,
|
||||
pcreds->data.client);
|
||||
}
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set session credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
} else if (object_dynamic_cast(OBJECT(creds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509)) {
|
||||
QCryptoTLSCredsX509 *tcreds = QCRYPTO_TLS_CREDS_X509(creds);
|
||||
const char *prio = creds->priority;
|
||||
if (!prio) {
|
||||
prio = CONFIG_TLS_PRIORITY;
|
||||
}
|
||||
|
||||
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set default TLS session priority %s: %s",
|
||||
prio, gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
ret = gnutls_credentials_set(session->handle,
|
||||
GNUTLS_CRD_CERTIFICATE,
|
||||
tcreds->data);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set session credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
/* This requests, but does not enforce a client cert.
|
||||
* The cert checking code later does enforcement */
|
||||
gnutls_certificate_server_set_request(session->handle,
|
||||
GNUTLS_CERT_REQUEST);
|
||||
}
|
||||
} else {
|
||||
error_setg(errp, "Unsupported TLS credentials type %s",
|
||||
object_get_typename(OBJECT(creds)));
|
||||
prio = qcrypto_tls_creds_get_priority(creds);
|
||||
ret = gnutls_priority_set_direct(session->handle, prio, NULL);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Unable to set TLS session priority %s: %s",
|
||||
prio, gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = gnutls_credentials_set(session->handle,
|
||||
creds->box->type,
|
||||
creds->box->data.any);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Cannot set session credentials: %s",
|
||||
gnutls_strerror(ret));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* creds->box->data.any must be kept alive for as long
|
||||
* as the gnutls_session_t is alive, so acquire a ref
|
||||
*/
|
||||
qcrypto_tls_creds_box_ref(creds->box);
|
||||
session->credsbox = creds->box;
|
||||
|
||||
if (object_dynamic_cast(OBJECT(creds),
|
||||
TYPE_QCRYPTO_TLS_CREDS_X509) &&
|
||||
creds->endpoint == QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
|
||||
/*
|
||||
* This requests, but does not enforce a client cert.
|
||||
* The cert checking code later does enforcement
|
||||
*/
|
||||
gnutls_certificate_server_set_request(session->handle,
|
||||
GNUTLS_CERT_REQUEST);
|
||||
}
|
||||
|
||||
gnutls_transport_set_ptr(session->handle, session);
|
||||
gnutls_transport_set_push_function(session->handle,
|
||||
qcrypto_tls_session_push);
|
||||
|
|
@ -417,6 +345,7 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
|
|||
goto error;
|
||||
}
|
||||
session->peername = (char *)g_steal_pointer(&dname.data);
|
||||
trace_qcrypto_tls_session_check_x509_dn(session, session->peername);
|
||||
if (session->authzid) {
|
||||
bool allow;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ qcrypto_tls_creds_x509_load_cert_list(void *creds, const char *file) "TLS creds
|
|||
# tlssession.c
|
||||
qcrypto_tls_session_new(void *session, void *creds, const char *hostname, const char *authzid, int endpoint) "TLS session new session=%p creds=%p hostname=%s authzid=%s endpoint=%d"
|
||||
qcrypto_tls_session_check_creds(void *session, const char *status) "TLS session check creds session=%p status=%s"
|
||||
qcrypto_tls_session_check_x509_dn(void *session, const char *dname) "TLS session check x509 distinguished name session=%p dname=%s"
|
||||
qcrypto_tls_session_parameters(void *session, int threadSafety, int protocol, int cipher) "TLS session parameters session=%p threadSafety=%d protocol=%d cipher=%d"
|
||||
qcrypto_tls_session_bug1717_workaround(void *session) "TLS session bug1717 workaround session=%p"
|
||||
|
||||
|
|
|
|||
250
crypto/xts.c
250
crypto/xts.c
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "crypto/xts.h"
|
||||
|
||||
typedef union {
|
||||
uint8_t b[XTS_BLOCK_SIZE];
|
||||
uint64_t u[2];
|
||||
} xts_uint128;
|
||||
|
||||
static inline void xts_uint128_xor(xts_uint128 *D,
|
||||
const xts_uint128 *S1,
|
||||
const xts_uint128 *S2)
|
||||
{
|
||||
D->u[0] = S1->u[0] ^ S2->u[0];
|
||||
D->u[1] = S1->u[1] ^ S2->u[1];
|
||||
}
|
||||
|
||||
static inline void xts_uint128_cpu_to_les(xts_uint128 *v)
|
||||
{
|
||||
cpu_to_le64s(&v->u[0]);
|
||||
cpu_to_le64s(&v->u[1]);
|
||||
}
|
||||
|
||||
static inline void xts_uint128_le_to_cpus(xts_uint128 *v)
|
||||
{
|
||||
le64_to_cpus(&v->u[0]);
|
||||
le64_to_cpus(&v->u[1]);
|
||||
}
|
||||
|
||||
static void xts_mult_x(xts_uint128 *I)
|
||||
{
|
||||
uint64_t tt;
|
||||
|
||||
xts_uint128_le_to_cpus(I);
|
||||
|
||||
tt = I->u[0] >> 63;
|
||||
I->u[0] <<= 1;
|
||||
|
||||
if (I->u[1] >> 63) {
|
||||
I->u[0] ^= 0x87;
|
||||
}
|
||||
I->u[1] <<= 1;
|
||||
I->u[1] |= tt;
|
||||
|
||||
xts_uint128_cpu_to_les(I);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* xts_tweak_encdec:
|
||||
* @param ctxt: the cipher context
|
||||
* @param func: the cipher function
|
||||
* @src: buffer providing the input text of XTS_BLOCK_SIZE bytes
|
||||
* @dst: buffer to output the output text of XTS_BLOCK_SIZE bytes
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
*
|
||||
* Encrypt/decrypt data with a tweak
|
||||
*/
|
||||
static inline void xts_tweak_encdec(const void *ctx,
|
||||
xts_cipher_func *func,
|
||||
const xts_uint128 *src,
|
||||
xts_uint128 *dst,
|
||||
xts_uint128 *iv)
|
||||
{
|
||||
/* tweak encrypt block i */
|
||||
xts_uint128_xor(dst, src, iv);
|
||||
|
||||
func(ctx, XTS_BLOCK_SIZE, dst->b, dst->b);
|
||||
|
||||
xts_uint128_xor(dst, dst, iv);
|
||||
|
||||
/* LFSR the tweak */
|
||||
xts_mult_x(iv);
|
||||
}
|
||||
|
||||
|
||||
void xts_decrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
xts_uint128 PP, CC, T;
|
||||
unsigned long i, m, mo, lim;
|
||||
|
||||
/* get number of blocks */
|
||||
m = length >> 4;
|
||||
mo = length & 15;
|
||||
|
||||
/* must have at least one full block */
|
||||
g_assert(m != 0);
|
||||
|
||||
if (mo == 0) {
|
||||
lim = m;
|
||||
} else {
|
||||
lim = m - 1;
|
||||
}
|
||||
|
||||
/* encrypt the iv */
|
||||
encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
|
||||
|
||||
if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
|
||||
QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
|
||||
xts_uint128 *S = (xts_uint128 *)src;
|
||||
xts_uint128 *D = (xts_uint128 *)dst;
|
||||
for (i = 0; i < lim; i++, S++, D++) {
|
||||
xts_tweak_encdec(datactx, decfunc, S, D, &T);
|
||||
}
|
||||
} else {
|
||||
xts_uint128 D;
|
||||
|
||||
for (i = 0; i < lim; i++) {
|
||||
memcpy(&D, src, XTS_BLOCK_SIZE);
|
||||
xts_tweak_encdec(datactx, decfunc, &D, &D, &T);
|
||||
memcpy(dst, &D, XTS_BLOCK_SIZE);
|
||||
src += XTS_BLOCK_SIZE;
|
||||
dst += XTS_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* if length is not a multiple of XTS_BLOCK_SIZE then */
|
||||
if (mo > 0) {
|
||||
xts_uint128 S, D;
|
||||
memcpy(&CC, &T, XTS_BLOCK_SIZE);
|
||||
xts_mult_x(&CC);
|
||||
|
||||
/* PP = tweak decrypt block m-1 */
|
||||
memcpy(&S, src, XTS_BLOCK_SIZE);
|
||||
xts_tweak_encdec(datactx, decfunc, &S, &PP, &CC);
|
||||
|
||||
/* Pm = first length % XTS_BLOCK_SIZE bytes of PP */
|
||||
for (i = 0; i < mo; i++) {
|
||||
CC.b[i] = src[XTS_BLOCK_SIZE + i];
|
||||
dst[XTS_BLOCK_SIZE + i] = PP.b[i];
|
||||
}
|
||||
for (; i < XTS_BLOCK_SIZE; i++) {
|
||||
CC.b[i] = PP.b[i];
|
||||
}
|
||||
|
||||
/* Pm-1 = Tweak uncrypt CC */
|
||||
xts_tweak_encdec(datactx, decfunc, &CC, &D, &T);
|
||||
memcpy(dst, &D, XTS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/* Decrypt the iv back */
|
||||
decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
|
||||
}
|
||||
|
||||
|
||||
void xts_encrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
xts_uint128 PP, CC, T;
|
||||
unsigned long i, m, mo, lim;
|
||||
|
||||
/* get number of blocks */
|
||||
m = length >> 4;
|
||||
mo = length & 15;
|
||||
|
||||
/* must have at least one full block */
|
||||
g_assert(m != 0);
|
||||
|
||||
if (mo == 0) {
|
||||
lim = m;
|
||||
} else {
|
||||
lim = m - 1;
|
||||
}
|
||||
|
||||
/* encrypt the iv */
|
||||
encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
|
||||
|
||||
if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
|
||||
QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
|
||||
xts_uint128 *S = (xts_uint128 *)src;
|
||||
xts_uint128 *D = (xts_uint128 *)dst;
|
||||
for (i = 0; i < lim; i++, S++, D++) {
|
||||
xts_tweak_encdec(datactx, encfunc, S, D, &T);
|
||||
}
|
||||
} else {
|
||||
xts_uint128 D;
|
||||
|
||||
for (i = 0; i < lim; i++) {
|
||||
memcpy(&D, src, XTS_BLOCK_SIZE);
|
||||
xts_tweak_encdec(datactx, encfunc, &D, &D, &T);
|
||||
memcpy(dst, &D, XTS_BLOCK_SIZE);
|
||||
|
||||
dst += XTS_BLOCK_SIZE;
|
||||
src += XTS_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* if length is not a multiple of XTS_BLOCK_SIZE then */
|
||||
if (mo > 0) {
|
||||
xts_uint128 S, D;
|
||||
/* CC = tweak encrypt block m-1 */
|
||||
memcpy(&S, src, XTS_BLOCK_SIZE);
|
||||
xts_tweak_encdec(datactx, encfunc, &S, &CC, &T);
|
||||
|
||||
/* Cm = first length % XTS_BLOCK_SIZE bytes of CC */
|
||||
for (i = 0; i < mo; i++) {
|
||||
PP.b[i] = src[XTS_BLOCK_SIZE + i];
|
||||
dst[XTS_BLOCK_SIZE + i] = CC.b[i];
|
||||
}
|
||||
|
||||
for (; i < XTS_BLOCK_SIZE; i++) {
|
||||
PP.b[i] = CC.b[i];
|
||||
}
|
||||
|
||||
/* Cm-1 = Tweak encrypt PP */
|
||||
xts_tweak_encdec(datactx, encfunc, &PP, &D, &T);
|
||||
memcpy(dst, &D, XTS_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/* Decrypt the iv back */
|
||||
decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
|
||||
}
|
||||
|
|
@ -385,6 +385,15 @@ Options are:
|
|||
- move backing file to NVDIMM storage and keep ``pmem=on``
|
||||
(to have NVDIMM with persistence guaranties).
|
||||
|
||||
Using an external DH (Diffie-Hellman) parameters file (since 10.2)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
Loading of external Diffie-Hellman parameters from a 'dh-params.pem'
|
||||
file is deprecated and will be removed with no replacement in a
|
||||
future release. Where no 'dh-params.pem' file is provided, the DH
|
||||
parameters will be automatically negotiated in accordance with
|
||||
RFC7919.
|
||||
|
||||
Device options
|
||||
--------------
|
||||
|
||||
|
|
|
|||
|
|
@ -36,8 +36,58 @@ server and exposing it directly to remote browser clients. In such a
|
|||
case it might be useful to use a commercial CA to avoid needing to
|
||||
install custom CA certs in the web browsers.
|
||||
|
||||
The recommendation is for the server to keep its certificates in either
|
||||
``/etc/pki/qemu`` or for unprivileged users in ``$HOME/.pki/qemu``.
|
||||
.. _tls_cert_file_naming:
|
||||
|
||||
Certificate file naming
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In a simple setup, where all QEMU instances on a machine share the
|
||||
same TLS configuration, it is suggested that QEMU certificates be
|
||||
kept in either ``/etc/pki/qemu`` or, for unprivileged users, in
|
||||
``$HOME/.pki/qemu``. Where different QEMU subsystems require
|
||||
different certificate configurations, sub-dirs of these locations
|
||||
may be chosen.
|
||||
|
||||
The default file names that QEMU will traditionally load are:
|
||||
|
||||
* ``ca-cert.pem`` - mandatory; for both client and server configurations
|
||||
* ``ca-crl.pem`` - optional; for server configurations only
|
||||
* ``server-cert.pem`` - mandatory; for server configurations only
|
||||
* ``server-key.pem`` - mandatory; for server configurations only
|
||||
* ``client-cert.pem`` - optional; for client configurations only
|
||||
* ``client-key.pem`` - optional; for client configurations only
|
||||
* ``dh-params.pem`` - optional; for server configurations only
|
||||
|
||||
Since QEMU 10.2.0, there is support for loading upto four additional
|
||||
identities:
|
||||
|
||||
* ``server-cert-[IDX].pem`` - optional; for server configurations only
|
||||
* ``server-key-[IDX].pem`` - optional; for server configurations only
|
||||
* ``client-cert-[IDX].pem`` - optional; for client configurations only
|
||||
* ``client-key-[IDX].pem`` - optional; for client configurations only
|
||||
|
||||
where ``-[IDX]`` is one of the digits 0-3. Loading will terminate at
|
||||
the first absent index. The index based certificate files may be used
|
||||
as a replacement for, or in addition to, the traditional non-index
|
||||
based certificate files. The traditional certificate files will be
|
||||
loaded first, if present, then the index based certificates. Where
|
||||
multiple certificates are compatible with a TLS session, the first
|
||||
loaded certificate will preferred. IOW file naming can influence
|
||||
which certificates are used for a session.
|
||||
|
||||
The use of multiple sets of certificates is intended to allow an
|
||||
incremental transition to certificates using different crytographic
|
||||
algorithms. This allows a newly deployed QEMU to introduce use of
|
||||
stronger cryptographic algorithms that will be preferred when talking
|
||||
to other newly deployed QEMU instances, while retaining compatbility
|
||||
with certificates issued to a historically deployed QEMU. This is
|
||||
notably useful to support live migration from an old QEMU deployed
|
||||
on older operating system releases, which may support fewer crypto
|
||||
algorithm choices than the current OS.
|
||||
|
||||
The certificate creation commands below will be illustrated using
|
||||
the traditional naming scheme, but their args can be substituted
|
||||
to use the indexed naming in the obvious manner.
|
||||
|
||||
.. _tls_005fgenerate_005fca:
|
||||
|
||||
|
|
@ -251,11 +301,13 @@ When specifying the object, the ``dir`` parameters specifies which
|
|||
directory contains the credential files. This directory is expected to
|
||||
contain files with the names mentioned previously, ``ca-cert.pem``,
|
||||
``server-key.pem``, ``server-cert.pem``, ``client-key.pem`` and
|
||||
``client-cert.pem`` as appropriate. It is also possible to include a set
|
||||
of pre-generated Diffie-Hellman (DH) parameters in a file
|
||||
``dh-params.pem``, which can be created using the
|
||||
``certtool --generate-dh-params`` command. If omitted, QEMU will
|
||||
dynamically generate DH parameters when loading the credentials.
|
||||
``client-cert.pem`` as appropriate.
|
||||
|
||||
While it is possible to include a set of pre-generated Diffie-Hellman
|
||||
(DH) parameters in a file ``dh-params.pem``, this facility is now
|
||||
deprecated and will be removed in a future release. When omitted the
|
||||
DH parameters will be automatically negotiated in accordance with
|
||||
RFC7919.
|
||||
|
||||
The ``endpoint`` parameter indicates whether the credentials will be
|
||||
used for a network client or server, and determines which PEM files are
|
||||
|
|
@ -293,6 +345,74 @@ example with VNC:
|
|||
|
||||
.. _tls_005fpsk:
|
||||
|
||||
TLS certificates for Post-Quantum Cryptography
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Given a new enough gnutls release, suitably integrated & configured with the
|
||||
operating system crypto policies, QEMU is able to support post-quantum
|
||||
crytography on TLS enabled services, either exclusively or in a hybrid mode.
|
||||
|
||||
In exclusive mode, only a single set of certificates need to be configured
|
||||
for QEMU, with PQC compliant algorithms. Such a QEMU configuration will only
|
||||
be able to interoperate with other services (including other QEMU's) that
|
||||
also have PQC enabled. This can result in compatibility concerns during the
|
||||
period of transition over to PQC compliant algorithms.
|
||||
|
||||
In hybrid mode, multiple sets of certificates need to be configured for QEMU,
|
||||
at least one set with traditional (non-PQC compliant) algorithms, and at least
|
||||
one other set with modern (PQC compliant) algorithms. At time of the TLS
|
||||
handshake, the GNUTLS algorithm priorities should ensure that PQC compliant
|
||||
algorithms are negotiated if both sides of the connection support PQC. If one
|
||||
side lacks PQC, the TLS handshake should fallback to the non-PQC algorithms.
|
||||
This can assist with interoperability during the transition to PQC, but has a
|
||||
potential weakness wrt downgrade attacks forcing use of non-PQC algorithms.
|
||||
Exclusive PQC mode should be preferred where both peers in the TLS connections
|
||||
are known to support PQC.
|
||||
|
||||
Key generation parameters
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To create certificates with PQC compliant algorithms, the ``--key-type``
|
||||
argument must be passed to ``certtool`` when creating private keys. No
|
||||
extra arguments are required for the other ``certtool`` commands, as
|
||||
their behaviour will be determined by the private key type.
|
||||
|
||||
The typical PQC compliant algorithms to use are ``ML-DSA-44``, ``ML-DSA-65``
|
||||
and ``ML-DSA-87``, with ``ML-DSA-65`` being a suitable default choice in
|
||||
the absence of explicit requirements.
|
||||
|
||||
Taking the example earlier, for creating a key for a client certificate,
|
||||
to use ``ML-DSA-65`` the command line would be modified to look like::
|
||||
|
||||
# certtool --generate-privkey --key-type=mldsa65 > client-hostNNN-key.pem
|
||||
|
||||
The equivalent modification applies to the creation of the private keys
|
||||
used for server certs, or root/intermediate CA certs.
|
||||
|
||||
For hybrid mode, the additional indexed certificate naming must be used.
|
||||
If multiple configured certificates are compatible with the mutually
|
||||
supported crypto algorithms between the client and server, then the
|
||||
first matching certificate will be used.
|
||||
|
||||
IOW, to ensure that PQC certificates are preferred, they must use a
|
||||
non-index based filename, or use an index that is smaller than any
|
||||
non-PQC certificates. ie, ``server-cert.pem`` for PQC and ``server-cert-0.pem``
|
||||
for non-PQC, or ``server-cert-0.pem`` for PQC and ``server-cert-1.pem`` for
|
||||
non-PQC.
|
||||
|
||||
Force disabling PQC via crypto priority
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In the OS configuration for system crypto algorithm priorities has
|
||||
enabled PQC, this can (optionally) be overriden in QEMU configuration
|
||||
disable use of PQC using the ``priority`` parameter to the ``tls-creds-x509``
|
||||
object::
|
||||
|
||||
NO_MLDSA="-SIGN-ML-DSA-65:-SIGN-ML-DSA-44:-SIGN-ML-DSA-87"
|
||||
NO_MLKEM="-GROUP-X25519-MLKEM768:-GROUP-SECP256R1-MLKEM768:-GROUP-SECP384R1-MLKEM1024"
|
||||
# qemu-nbd --object tls-creds-x509,id=tls0,endpoint=server,dir=....,priority=@SYSTEM:$NO_MLDSA:$NO_MLKEM
|
||||
|
||||
|
||||
TLS Pre-Shared Keys (PSK)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ int qcrypto_hash_bytesv(QCryptoHashAlgo alg,
|
|||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hash_bytes(QCryptoHashAlgo alg,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
|
|
@ -180,7 +180,7 @@ int qcrypto_hash_updatev(QCryptoHash *hash,
|
|||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hash_update(QCryptoHash *hash,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
Error **errp);
|
||||
|
||||
|
|
@ -289,7 +289,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoHash, qcrypto_hash_free)
|
|||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hash_digest(QCryptoHashAlgo alg,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
char **digest,
|
||||
Error **errp);
|
||||
|
|
@ -335,7 +335,7 @@ int qcrypto_hash_base64v(QCryptoHashAlgo alg,
|
|||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hash_base64(QCryptoHashAlgo alg,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
char **base64,
|
||||
Error **errp);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ int qcrypto_hmac_bytesv(QCryptoHmac *hmac,
|
|||
* 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hmac_bytes(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
uint8_t **result,
|
||||
size_t *resultlen,
|
||||
|
|
@ -187,7 +187,7 @@ int qcrypto_hmac_digestv(QCryptoHmac *hmac,
|
|||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int qcrypto_hmac_digest(QCryptoHmac *hmac,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t len,
|
||||
char **digest,
|
||||
Error **errp);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ typedef bool (*CryptoTLSCredsReload)(QCryptoTLSCreds *, Error **);
|
|||
struct QCryptoTLSCredsClass {
|
||||
ObjectClass parent_class;
|
||||
CryptoTLSCredsReload reload;
|
||||
const char *prioritySuffix;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -64,4 +65,29 @@ bool qcrypto_tls_creds_check_endpoint(QCryptoTLSCreds *creds,
|
|||
QCryptoTLSCredsEndpoint endpoint,
|
||||
Error **errp);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_tls_creds_get_priority:
|
||||
* @creds: pointer to a TLS credentials object
|
||||
*
|
||||
* Get the TLS credentials priority string. The caller
|
||||
* must free the returned string when no longer required.
|
||||
*
|
||||
* Returns: a non-NULL priority string
|
||||
*/
|
||||
char *qcrypto_tls_creds_get_priority(QCryptoTLSCreds *creds);
|
||||
|
||||
|
||||
/**
|
||||
* qcrypto_tls_creds_reload:
|
||||
* @creds: pointer to a TLS credentials object
|
||||
* @errp: pointer to a NULL-initialized error object
|
||||
*
|
||||
* Request a reload of the TLS credentials, if supported
|
||||
*
|
||||
* Returns: true on success, false on error or if not supported
|
||||
*/
|
||||
bool qcrypto_tls_creds_reload(QCryptoTLSCreds *creds,
|
||||
Error **errp);
|
||||
|
||||
#endif /* QCRYPTO_TLSCREDS_H */
|
||||
|
|
|
|||
|
|
@ -37,7 +37,13 @@ typedef struct QCryptoTLSCredsX509Class QCryptoTLSCredsX509Class;
|
|||
#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT "server-cert.pem"
|
||||
#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY "client-key.pem"
|
||||
#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT "client-cert.pem"
|
||||
#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY_N "server-key-%zu.pem"
|
||||
#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT_N "server-cert-%zu.pem"
|
||||
#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY_N "client-key-%zu.pem"
|
||||
#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT_N "client-cert-%zu.pem"
|
||||
|
||||
/* Max number of additional cert/key pairs (ie _N constants) */
|
||||
#define QCRYPTO_TLS_CREDS_X509_IDENTITY_MAX 4
|
||||
|
||||
/**
|
||||
* QCryptoTLSCredsX509:
|
||||
|
|
|
|||
|
|
@ -199,11 +199,11 @@ int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
|
|||
* These must return QCRYPTO_TLS_SESSION_ERR_BLOCK if the I/O
|
||||
* would block, but on other errors, must fill 'errp'
|
||||
*/
|
||||
typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
|
||||
typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const void *buf,
|
||||
size_t len,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
|
||||
typedef ssize_t (*QCryptoTLSSessionReadFunc)(void *buf,
|
||||
size_t len,
|
||||
void *opaque,
|
||||
Error **errp);
|
||||
|
|
|
|||
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* Copyright (c) 2015-2016 Red Hat, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QCRYPTO_XTS_H
|
||||
#define QCRYPTO_XTS_H
|
||||
|
||||
|
||||
#define XTS_BLOCK_SIZE 16
|
||||
|
||||
typedef void xts_cipher_func(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
/**
|
||||
* xts_decrypt:
|
||||
* @datactx: the cipher context for data decryption
|
||||
* @tweakctx: the cipher context for tweak decryption
|
||||
* @encfunc: the cipher function for encryption
|
||||
* @decfunc: the cipher function for decryption
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
* @length: the length of @dst and @src
|
||||
* @dst: buffer to hold the decrypted plaintext
|
||||
* @src: buffer providing the ciphertext
|
||||
*
|
||||
* Decrypts @src into @dst
|
||||
*/
|
||||
void xts_decrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
/**
|
||||
* xts_decrypt:
|
||||
* @datactx: the cipher context for data encryption
|
||||
* @tweakctx: the cipher context for tweak encryption
|
||||
* @encfunc: the cipher function for encryption
|
||||
* @decfunc: the cipher function for decryption
|
||||
* @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
|
||||
* @length: the length of @dst and @src
|
||||
* @dst: buffer to hold the encrypted ciphertext
|
||||
* @src: buffer providing the plaintext
|
||||
*
|
||||
* Decrypts @src into @dst
|
||||
*/
|
||||
void xts_encrypt(const void *datactx,
|
||||
const void *tweakctx,
|
||||
xts_cipher_func *encfunc,
|
||||
xts_cipher_func *decfunc,
|
||||
uint8_t *iv,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src);
|
||||
|
||||
|
||||
#endif /* QCRYPTO_XTS_H */
|
||||
|
|
@ -49,6 +49,12 @@ struct QIOChannelSocket {
|
|||
socklen_t remoteAddrLen;
|
||||
ssize_t zero_copy_queued;
|
||||
ssize_t zero_copy_sent;
|
||||
bool blocking;
|
||||
/**
|
||||
* This flag indicates whether any new data was successfully sent with
|
||||
* zerocopy since the last qio_channel_socket_flush() call.
|
||||
*/
|
||||
bool new_zero_copy_sent_success;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc,
|
|||
* a single memory region.
|
||||
*/
|
||||
ssize_t qio_channel_read(QIOChannel *ioc,
|
||||
char *buf,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
|
@ -453,7 +453,7 @@ ssize_t qio_channel_read(QIOChannel *ioc,
|
|||
* single memory region.
|
||||
*/
|
||||
ssize_t qio_channel_write(QIOChannel *ioc,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
|
@ -475,7 +475,7 @@ ssize_t qio_channel_write(QIOChannel *ioc,
|
|||
* without data, or -1 on error
|
||||
*/
|
||||
int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
|
||||
char *buf,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
|
@ -495,7 +495,7 @@ int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
|
|||
* Returns: 0 if all bytes were read, or -1 on error
|
||||
*/
|
||||
int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
|
||||
char *buf,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
|
@ -514,7 +514,7 @@ int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
|
|||
* Returns: 0 if all bytes were written, or -1 on error
|
||||
*/
|
||||
int coroutine_mixed_fn qio_channel_write_all(QIOChannel *ioc,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t buflen,
|
||||
Error **errp);
|
||||
|
||||
|
|
@ -595,7 +595,7 @@ ssize_t qio_channel_pwritev(QIOChannel *ioc, const struct iovec *iov,
|
|||
* flag QIO_CHANNEL_FEATURE_SEEKABLE prior to calling this method.
|
||||
*
|
||||
*/
|
||||
ssize_t qio_channel_pwrite(QIOChannel *ioc, char *buf, size_t buflen,
|
||||
ssize_t qio_channel_pwrite(QIOChannel *ioc, void *buf, size_t buflen,
|
||||
off_t offset, Error **errp);
|
||||
|
||||
/**
|
||||
|
|
@ -631,7 +631,7 @@ ssize_t qio_channel_preadv(QIOChannel *ioc, const struct iovec *iov,
|
|||
* flag QIO_CHANNEL_FEATURE_SEEKABLE prior to calling this method.
|
||||
*
|
||||
*/
|
||||
ssize_t qio_channel_pread(QIOChannel *ioc, char *buf, size_t buflen,
|
||||
ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
|
||||
off_t offset, Error **errp);
|
||||
|
||||
/**
|
||||
|
|
|
|||
57
include/qemu/exit-with-parent.h
Normal file
57
include/qemu/exit-with-parent.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Originally derived from nbdkit common/utils/exit-with-parent.h
|
||||
* Copyright Red Hat
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Red Hat nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef NBDKIT_EXIT_WITH_PARENT_H
|
||||
#define NBDKIT_EXIT_WITH_PARENT_H
|
||||
|
||||
/* Test if the feature is available on the platform. */
|
||||
static inline bool can_exit_with_parent(void)
|
||||
{
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* --exit-with-parent: kill the current process if the parent exits.
|
||||
* This may return -1 on error.
|
||||
*
|
||||
* Note this will abort on platforms where can_exit_with_parent()
|
||||
* returned false.
|
||||
*/
|
||||
extern int set_exit_with_parent(void);
|
||||
|
||||
#endif /* NBDKIT_EXIT_WITH_PARENT_H */
|
||||
|
|
@ -37,6 +37,12 @@
|
|||
|
||||
#define SOCKET_MAX_FDS 16
|
||||
|
||||
#ifdef QEMU_MSG_ZEROCOPY
|
||||
static int qio_channel_socket_flush_internal(QIOChannel *ioc,
|
||||
bool block,
|
||||
Error **errp);
|
||||
#endif
|
||||
|
||||
SocketAddress *
|
||||
qio_channel_socket_get_local_address(QIOChannelSocket *ioc,
|
||||
Error **errp)
|
||||
|
|
@ -65,6 +71,8 @@ qio_channel_socket_new(void)
|
|||
sioc->fd = -1;
|
||||
sioc->zero_copy_queued = 0;
|
||||
sioc->zero_copy_sent = 0;
|
||||
sioc->blocking = false;
|
||||
sioc->new_zero_copy_sent_success = false;
|
||||
|
||||
ioc = QIO_CHANNEL(sioc);
|
||||
qio_channel_set_feature(ioc, QIO_CHANNEL_FEATURE_SHUTDOWN);
|
||||
|
|
@ -617,6 +625,10 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
|
|||
size_t fdsize = sizeof(int) * nfds;
|
||||
struct cmsghdr *cmsg;
|
||||
int sflags = 0;
|
||||
#ifdef QEMU_MSG_ZEROCOPY
|
||||
bool blocking = sioc->blocking;
|
||||
bool zerocopy_flushed_once = false;
|
||||
#endif
|
||||
|
||||
memset(control, 0, CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS));
|
||||
|
||||
|
|
@ -661,13 +673,30 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
|
|||
return QIO_CHANNEL_ERR_BLOCK;
|
||||
case EINTR:
|
||||
goto retry;
|
||||
#ifdef QEMU_MSG_ZEROCOPY
|
||||
case ENOBUFS:
|
||||
if (flags & QIO_CHANNEL_WRITE_FLAG_ZERO_COPY) {
|
||||
error_setg_errno(errp, errno,
|
||||
"Process can't lock enough memory for using MSG_ZEROCOPY");
|
||||
return -1;
|
||||
/**
|
||||
* Socket error queueing may exhaust the OPTMEM limit. Try
|
||||
* flushing the error queue once.
|
||||
*/
|
||||
if (!zerocopy_flushed_once) {
|
||||
ret = qio_channel_socket_flush_internal(ioc, blocking,
|
||||
errp);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
zerocopy_flushed_once = true;
|
||||
goto retry;
|
||||
} else {
|
||||
error_setg_errno(errp, errno,
|
||||
"Process can't lock enough memory for "
|
||||
"using MSG_ZEROCOPY");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
error_setg_errno(errp, errno,
|
||||
|
|
@ -776,8 +805,9 @@ static ssize_t qio_channel_socket_writev(QIOChannel *ioc,
|
|||
|
||||
|
||||
#ifdef QEMU_MSG_ZEROCOPY
|
||||
static int qio_channel_socket_flush(QIOChannel *ioc,
|
||||
Error **errp)
|
||||
static int qio_channel_socket_flush_internal(QIOChannel *ioc,
|
||||
bool block,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
||||
struct msghdr msg = {};
|
||||
|
|
@ -785,7 +815,6 @@ static int qio_channel_socket_flush(QIOChannel *ioc,
|
|||
struct cmsghdr *cm;
|
||||
char control[CMSG_SPACE(sizeof(*serr))];
|
||||
int received;
|
||||
int ret;
|
||||
|
||||
if (sioc->zero_copy_queued == sioc->zero_copy_sent) {
|
||||
return 0;
|
||||
|
|
@ -795,16 +824,25 @@ static int qio_channel_socket_flush(QIOChannel *ioc,
|
|||
msg.msg_controllen = sizeof(control);
|
||||
memset(control, 0, sizeof(control));
|
||||
|
||||
ret = 1;
|
||||
|
||||
while (sioc->zero_copy_sent < sioc->zero_copy_queued) {
|
||||
received = recvmsg(sioc->fd, &msg, MSG_ERRQUEUE);
|
||||
if (received < 0) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
/* Nothing on errqueue, wait until something is available */
|
||||
qio_channel_wait(ioc, G_IO_ERR);
|
||||
continue;
|
||||
if (block) {
|
||||
/*
|
||||
* Nothing on errqueue, wait until something is
|
||||
* available.
|
||||
*
|
||||
* Use G_IO_ERR instead of G_IO_IN since MSG_ERRQUEUE reads
|
||||
* are signaled via POLLERR, not POLLIN, as the kernel
|
||||
* sets POLLERR when zero-copy notificatons appear on the
|
||||
* socket error queue.
|
||||
*/
|
||||
qio_channel_wait(ioc, G_IO_ERR);
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
case EINTR:
|
||||
continue;
|
||||
default:
|
||||
|
|
@ -842,13 +880,32 @@ static int qio_channel_socket_flush(QIOChannel *ioc,
|
|||
/* No errors, count successfully finished sendmsg()*/
|
||||
sioc->zero_copy_sent += serr->ee_data - serr->ee_info + 1;
|
||||
|
||||
/* If any sendmsg() succeeded using zero copy, return 0 at the end */
|
||||
/* If any sendmsg() succeeded using zero copy, mark zerocopy success */
|
||||
if (serr->ee_code != SO_EE_CODE_ZEROCOPY_COPIED) {
|
||||
ret = 0;
|
||||
sioc->new_zero_copy_sent_success = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qio_channel_socket_flush(QIOChannel *ioc,
|
||||
Error **errp)
|
||||
{
|
||||
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
||||
int ret;
|
||||
|
||||
ret = qio_channel_socket_flush_internal(ioc, true, errp);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sioc->new_zero_copy_sent_success) {
|
||||
sioc->new_zero_copy_sent_success = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* QEMU_MSG_ZEROCOPY */
|
||||
|
|
@ -859,6 +916,7 @@ qio_channel_socket_set_blocking(QIOChannel *ioc,
|
|||
Error **errp)
|
||||
{
|
||||
QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(ioc);
|
||||
sioc->blocking = enabled;
|
||||
|
||||
if (!qemu_set_blocking(sioc->fd, enabled, errp)) {
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include "qemu/atomic.h"
|
||||
|
||||
|
||||
static ssize_t qio_channel_tls_write_handler(const char *buf,
|
||||
static ssize_t qio_channel_tls_write_handler(const void *buf,
|
||||
size_t len,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
|
|
@ -43,7 +43,7 @@ static ssize_t qio_channel_tls_write_handler(const char *buf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t qio_channel_tls_read_handler(char *buf,
|
||||
static ssize_t qio_channel_tls_read_handler(void *buf,
|
||||
size_t len,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
|
|
|
|||
14
io/channel.c
14
io/channel.c
|
|
@ -310,7 +310,7 @@ ssize_t qio_channel_writev(QIOChannel *ioc,
|
|||
|
||||
|
||||
ssize_t qio_channel_read(QIOChannel *ioc,
|
||||
char *buf,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
|
|
@ -320,7 +320,7 @@ ssize_t qio_channel_read(QIOChannel *ioc,
|
|||
|
||||
|
||||
ssize_t qio_channel_write(QIOChannel *ioc,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
|
|
@ -330,7 +330,7 @@ ssize_t qio_channel_write(QIOChannel *ioc,
|
|||
|
||||
|
||||
int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
|
||||
char *buf,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
|
|
@ -340,7 +340,7 @@ int coroutine_mixed_fn qio_channel_read_all_eof(QIOChannel *ioc,
|
|||
|
||||
|
||||
int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
|
||||
char *buf,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
|
|
@ -350,7 +350,7 @@ int coroutine_mixed_fn qio_channel_read_all(QIOChannel *ioc,
|
|||
|
||||
|
||||
int coroutine_mixed_fn qio_channel_write_all(QIOChannel *ioc,
|
||||
const char *buf,
|
||||
const void *buf,
|
||||
size_t buflen,
|
||||
Error **errp)
|
||||
{
|
||||
|
|
@ -475,7 +475,7 @@ ssize_t qio_channel_pwritev(QIOChannel *ioc, const struct iovec *iov,
|
|||
return klass->io_pwritev(ioc, iov, niov, offset, errp);
|
||||
}
|
||||
|
||||
ssize_t qio_channel_pwrite(QIOChannel *ioc, char *buf, size_t buflen,
|
||||
ssize_t qio_channel_pwrite(QIOChannel *ioc, void *buf, size_t buflen,
|
||||
off_t offset, Error **errp)
|
||||
{
|
||||
struct iovec iov = {
|
||||
|
|
@ -504,7 +504,7 @@ ssize_t qio_channel_preadv(QIOChannel *ioc, const struct iovec *iov,
|
|||
return klass->io_preadv(ioc, iov, niov, offset, errp);
|
||||
}
|
||||
|
||||
ssize_t qio_channel_pread(QIOChannel *ioc, char *buf, size_t buflen,
|
||||
ssize_t qio_channel_pread(QIOChannel *ioc, void *buf, size_t buflen,
|
||||
off_t offset, Error **errp)
|
||||
{
|
||||
struct iovec iov = {
|
||||
|
|
|
|||
69
meson.build
69
meson.build
|
|
@ -1823,33 +1823,11 @@ if not get_option('libcbor').auto() or have_system
|
|||
endif
|
||||
|
||||
gnutls = not_found
|
||||
gnutls_crypto = not_found
|
||||
gnutls_bug1717_workaround = false
|
||||
if get_option('gnutls').enabled() or (get_option('gnutls').auto() and have_system)
|
||||
# For general TLS support our min gnutls matches
|
||||
# that implied by our platform support matrix
|
||||
#
|
||||
# For the crypto backends, we look for a newer
|
||||
# gnutls:
|
||||
#
|
||||
# Version 3.6.8 is needed to get XTS
|
||||
# Version 3.6.13 is needed to get PBKDF
|
||||
# Version 3.6.14 is needed to get HW accelerated XTS
|
||||
#
|
||||
# If newer enough gnutls isn't available, we can
|
||||
# still use a different crypto backend to satisfy
|
||||
# the platform support requirements
|
||||
gnutls_crypto = dependency('gnutls', version: '>=3.6.14',
|
||||
method: 'pkg-config',
|
||||
required: false)
|
||||
if gnutls_crypto.found()
|
||||
gnutls = gnutls_crypto
|
||||
else
|
||||
# Our min version if all we need is TLS
|
||||
gnutls = dependency('gnutls', version: '>=3.5.18',
|
||||
method: 'pkg-config',
|
||||
required: get_option('gnutls'))
|
||||
endif
|
||||
gnutls = dependency('gnutls', version: '>=3.7.5',
|
||||
method: 'pkg-config',
|
||||
required: get_option('gnutls'))
|
||||
|
||||
#if gnutls.found() and not get_option('gnutls-bug1717-workaround').disabled()
|
||||
# XXX: when bug 1717 is resolved, add logic to probe for
|
||||
|
|
@ -1868,20 +1846,14 @@ nettle = not_found
|
|||
hogweed = not_found
|
||||
crypto_sm4 = not_found
|
||||
crypto_sm3 = not_found
|
||||
xts = 'none'
|
||||
|
||||
if get_option('nettle').enabled() and get_option('gcrypt').enabled()
|
||||
error('Only one of gcrypt & nettle can be enabled')
|
||||
endif
|
||||
|
||||
# Explicit nettle/gcrypt request, so ignore gnutls for crypto
|
||||
if get_option('nettle').enabled() or get_option('gcrypt').enabled()
|
||||
gnutls_crypto = not_found
|
||||
endif
|
||||
|
||||
if not gnutls_crypto.found()
|
||||
if not gnutls.found()
|
||||
if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
|
||||
gcrypt = dependency('libgcrypt', version: '>=1.8',
|
||||
gcrypt = dependency('libgcrypt', version: '>=1.9.4',
|
||||
required: get_option('gcrypt'))
|
||||
# Debian has removed -lgpg-error from libgcrypt-config
|
||||
# as it "spreads unnecessary dependencies" which in
|
||||
|
|
@ -1893,35 +1865,12 @@ if not gnutls_crypto.found()
|
|||
version: gcrypt.version())
|
||||
endif
|
||||
crypto_sm4 = gcrypt
|
||||
# SM4 ALG is available in libgcrypt >= 1.9
|
||||
if gcrypt.found() and not cc.links('''
|
||||
#include <gcrypt.h>
|
||||
int main(void) {
|
||||
gcry_cipher_hd_t handler;
|
||||
gcry_cipher_open(&handler, GCRY_CIPHER_SM4, GCRY_CIPHER_MODE_ECB, 0);
|
||||
return 0;
|
||||
}''', dependencies: gcrypt)
|
||||
crypto_sm4 = not_found
|
||||
endif
|
||||
crypto_sm3 = gcrypt
|
||||
# SM3 ALG is available in libgcrypt >= 1.9
|
||||
if gcrypt.found() and not cc.links('''
|
||||
#include <gcrypt.h>
|
||||
int main(void) {
|
||||
gcry_md_hd_t handler;
|
||||
gcry_md_open(&handler, GCRY_MD_SM3, 0);
|
||||
return 0;
|
||||
}''', dependencies: gcrypt)
|
||||
crypto_sm3 = not_found
|
||||
endif
|
||||
endif
|
||||
if (not get_option('nettle').auto() or have_system) and not gcrypt.found()
|
||||
nettle = dependency('nettle', version: '>=3.4',
|
||||
nettle = dependency('nettle', version: '>=3.7.3',
|
||||
method: 'pkg-config',
|
||||
required: get_option('nettle'))
|
||||
if nettle.found() and not cc.has_header('nettle/xts.h', dependencies: nettle)
|
||||
xts = 'private'
|
||||
endif
|
||||
crypto_sm4 = nettle
|
||||
# SM4 ALG is available in nettle >= 3.9
|
||||
if nettle.found() and not cc.links('''
|
||||
|
|
@ -2606,7 +2555,6 @@ config_host_data.set('CONFIG_XKBCOMMON', xkbcommon.found())
|
|||
config_host_data.set('CONFIG_KEYUTILS', keyutils.found())
|
||||
config_host_data.set('CONFIG_GETTID', has_gettid)
|
||||
config_host_data.set('CONFIG_GNUTLS', gnutls.found())
|
||||
config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
|
||||
config_host_data.set('CONFIG_GNUTLS_BUG1717_WORKAROUND', gnutls_bug1717_workaround)
|
||||
config_host_data.set('CONFIG_TASN1', tasn1.found())
|
||||
config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
|
||||
|
|
@ -2614,7 +2562,6 @@ config_host_data.set('CONFIG_NETTLE', nettle.found())
|
|||
config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found())
|
||||
config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found())
|
||||
config_host_data.set('CONFIG_HOGWEED', hogweed.found())
|
||||
config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
|
||||
config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
|
||||
config_host_data.set('CONFIG_ZSTD', zstd.found())
|
||||
config_host_data.set('CONFIG_QPL', qpl.found())
|
||||
|
|
@ -4906,14 +4853,10 @@ summary_info = {}
|
|||
summary_info += {'TLS priority': get_option('tls_priority')}
|
||||
summary_info += {'GNUTLS support': gnutls}
|
||||
if gnutls.found()
|
||||
summary_info += {' GNUTLS crypto': gnutls_crypto.found()}
|
||||
summary_info += {' GNUTLS bug 1717 workaround': gnutls_bug1717_workaround }
|
||||
endif
|
||||
summary_info += {'libgcrypt': gcrypt}
|
||||
summary_info += {'nettle': nettle}
|
||||
if nettle.found()
|
||||
summary_info += {' XTS': xts != 'private'}
|
||||
endif
|
||||
summary_info += {'SM4 ALG support': crypto_sm4}
|
||||
summary_info += {'SM3 ALG support': crypto_sm3}
|
||||
summary_info += {'AF_ALG support': have_afalg}
|
||||
|
|
|
|||
|
|
@ -5467,15 +5467,18 @@ DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL)
|
|||
|
||||
#if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN)
|
||||
DEF("run-with", HAS_ARG, QEMU_OPTION_run_with,
|
||||
"-run-with [async-teardown=on|off][,chroot=dir][user=username|uid:gid]\n"
|
||||
"-run-with [async-teardown=on|off][,chroot=dir]\n" \
|
||||
" [,exit-with-parent=on|off][,user=username|uid:gid]\n"
|
||||
" Set miscellaneous QEMU process lifecycle options:\n"
|
||||
" async-teardown=on enables asynchronous teardown (Linux only)\n"
|
||||
" exit-with-parent=on causes QEMU to exit if the parent\n"
|
||||
" process of QEMU exits (Linux, FreeBSD, macOS only)\n"
|
||||
" chroot=dir chroot to dir just before starting the VM\n"
|
||||
" user=username switch to the specified user before starting the VM\n"
|
||||
" user=uid:gid ditto, but use specified user-ID and group-ID instead\n",
|
||||
QEMU_ARCH_ALL)
|
||||
SRST
|
||||
``-run-with [async-teardown=on|off][,chroot=dir][user=username|uid:gid]``
|
||||
``-run-with [async-teardown=on|off][,chroot=dir][,exit-with-parent=on|off][,user=username|uid:gid]``
|
||||
Set QEMU process lifecycle options.
|
||||
|
||||
``async-teardown=on`` enables asynchronous teardown. A new process called
|
||||
|
|
@ -5493,6 +5496,12 @@ SRST
|
|||
immediately before starting the guest execution. This is especially useful
|
||||
in combination with ``user=...``.
|
||||
|
||||
``exit-with-parent=on`` causes QEMU to exit if the parent process of
|
||||
QEMU exits. This can be used when QEMU runs a captive appliance,
|
||||
where the lifetime of the appliance is scoped to the parent process.
|
||||
In case the parent process crashes, QEMU is still cleaned up.
|
||||
This only works on Linux, FreeBSD and macOS platforms.
|
||||
|
||||
``user=username`` or ``user=uid:gid`` can be used to drop root privileges
|
||||
before starting guest execution. QEMU will use the ``setuid`` and ``setgid``
|
||||
system calls to switch to the specified identity. Note that the
|
||||
|
|
|
|||
140
system/exit-with-parent.c
Normal file
140
system/exit-with-parent.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Originally derived from nbdkit common/utils/exit-with-parent.c
|
||||
* Copyright Red Hat
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of Red Hat nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Implement the --exit-with-parent feature on operating systems which
|
||||
* support it.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/exit-with-parent.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
/*
|
||||
* Send SIGTERM to self when the parent exits. This will cause
|
||||
* qemu_system_killed() to be called.
|
||||
*
|
||||
* PR_SET_PDEATHSIG has been defined since Linux 2.1.57.
|
||||
*/
|
||||
int
|
||||
set_exit_with_parent(void)
|
||||
{
|
||||
return prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
#include <sys/procctl.h>
|
||||
|
||||
/*
|
||||
* Send SIGTERM to self when the parent exits. This will cause
|
||||
* qemu_system_killed() to be called.
|
||||
*
|
||||
* PROC_PDEATHSIG_CTL has been defined since FreeBSD 11.2.
|
||||
*/
|
||||
int
|
||||
set_exit_with_parent(void)
|
||||
{
|
||||
const int sig = SIGTERM;
|
||||
return procctl(P_PID, 0, PROC_PDEATHSIG_CTL, (void *) &sig);
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
/* For macOS. */
|
||||
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "system/runstate.h"
|
||||
#include <sys/event.h>
|
||||
|
||||
static void *
|
||||
exit_with_parent_loop(void *vp)
|
||||
{
|
||||
const pid_t ppid = getppid();
|
||||
int fd;
|
||||
struct kevent kev, res[1];
|
||||
int r;
|
||||
|
||||
/* Register the kevent to wait for ppid to exit. */
|
||||
fd = kqueue();
|
||||
if (fd == -1) {
|
||||
error_report("exit_with_parent_loop: kqueue: %m");
|
||||
return NULL;
|
||||
}
|
||||
EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL);
|
||||
if (kevent(fd, &kev, 1, NULL, 0, NULL) == -1) {
|
||||
error_report("exit_with_parent_loop: kevent: %m");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Wait for the kevent to happen. */
|
||||
r = kevent(fd, 0, 0, res, 1, NULL);
|
||||
if (r == 1 && res[0].ident == ppid) {
|
||||
/* Behave like Linux and FreeBSD above, as if SIGTERM was sent */
|
||||
qemu_system_killed(SIGTERM, ppid);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
set_exit_with_parent(void)
|
||||
{
|
||||
QemuThread exit_with_parent_thread;
|
||||
|
||||
/*
|
||||
* We have to block waiting for kevent, so that requires that we
|
||||
* start a background thread.
|
||||
*/
|
||||
qemu_thread_create(&exit_with_parent_thread,
|
||||
"exit-parent",
|
||||
exit_with_parent_loop, NULL,
|
||||
QEMU_THREAD_DETACHED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* any platform that doesn't support this function */
|
||||
|
||||
int
|
||||
set_exit_with_parent(void)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -15,6 +15,7 @@ system_ss.add(files(
|
|||
'datadir.c',
|
||||
'dirtylimit.c',
|
||||
'dma-helpers.c',
|
||||
'exit-with-parent.c',
|
||||
'globals.c',
|
||||
'ioport.c',
|
||||
'ram-block-attributes.c',
|
||||
|
|
|
|||
13
system/vl.c
13
system/vl.c
|
|
@ -53,6 +53,7 @@
|
|||
#include "qemu/sockets.h"
|
||||
#include "qemu/accel.h"
|
||||
#include "qemu/async-teardown.h"
|
||||
#include "qemu/exit-with-parent.h"
|
||||
#include "hw/usb.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/scsi/scsi.h"
|
||||
|
|
@ -783,6 +784,10 @@ static QemuOptsList qemu_run_with_opts = {
|
|||
.name = "chroot",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "exit-with-parent",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{
|
||||
.name = "user",
|
||||
.type = QEMU_OPT_STRING,
|
||||
|
|
@ -3691,6 +3696,14 @@ void qemu_init(int argc, char **argv)
|
|||
if (str) {
|
||||
os_set_chroot(str);
|
||||
}
|
||||
if (qemu_opt_get_bool(opts, "exit-with-parent", false)) {
|
||||
if (!can_exit_with_parent()) {
|
||||
error_report("exit-with-parent is not available"
|
||||
" on this platform");
|
||||
exit(1);
|
||||
}
|
||||
set_exit_with_parent();
|
||||
}
|
||||
str = qemu_opt_get(opts, "user");
|
||||
if (str) {
|
||||
if (!os_set_runas(str)) {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "qemu/accel.h"
|
||||
#include "qemu/ctype.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/exit-with-parent.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qobject/qdict.h"
|
||||
#include "qobject/qjson.h"
|
||||
|
|
@ -433,24 +434,6 @@ static QTestState *qtest_spawn_qemu(const char *qemu_bin, const char *args,
|
|||
#ifndef _WIN32
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
#ifdef __linux__
|
||||
/*
|
||||
* Although we register a ABRT handler to kill off QEMU
|
||||
* when g_assert() triggers, we want an extra safety
|
||||
* net. The QEMU process might be non-functional and
|
||||
* thus not have responded to SIGTERM. The test script
|
||||
* might also have crashed with SEGV, in which case the
|
||||
* cleanup handlers won't ever run.
|
||||
*
|
||||
* This PR_SET_PDEATHSIG setup will ensure any remaining
|
||||
* QEMU will get terminated with SIGKILL in these cases.
|
||||
*/
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
|
||||
#endif /* __linux__ */
|
||||
#ifdef __FreeBSD__
|
||||
int sig = SIGKILL;
|
||||
procctl(P_PID, getpid(), PROC_PDEATHSIG_CTL, &sig);
|
||||
#endif /* __FreeBSD__ */
|
||||
execlp("/bin/sh", "sh", "-c", command->str, NULL);
|
||||
exit(1);
|
||||
}
|
||||
|
|
@ -482,12 +465,15 @@ gchar *qtest_qemu_args(const char *extra_args)
|
|||
"-display none "
|
||||
"-audio none "
|
||||
"%s"
|
||||
"%s"
|
||||
" -accel qtest",
|
||||
|
||||
tracearg,
|
||||
socket_path,
|
||||
getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL,
|
||||
qmp_socket_path,
|
||||
can_exit_with_parent() ?
|
||||
"-run-with exit-with-parent=on " : "",
|
||||
extra_args ?: "");
|
||||
|
||||
return args;
|
||||
|
|
|
|||
|
|
@ -110,9 +110,6 @@ if have_block
|
|||
if pam.found()
|
||||
tests += {'test-authz-pam': [authz]}
|
||||
endif
|
||||
if xts == 'private'
|
||||
tests += {'test-crypto-xts': [crypto, io]}
|
||||
endif
|
||||
if host_os != 'windows'
|
||||
tests += {
|
||||
'test-image-locking': [testblock],
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@
|
|||
#endif
|
||||
|
||||
#if (defined(_WIN32) || defined RUSAGE_THREAD) && \
|
||||
(defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT) || \
|
||||
defined(CONFIG_GNUTLS_CRYPTO))
|
||||
(defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT))
|
||||
#define TEST_LUKS
|
||||
#else
|
||||
#undef TEST_LUKS
|
||||
|
|
|
|||
|
|
@ -95,16 +95,16 @@ static void test_tls_creds(const void *opaque)
|
|||
if (access(data->crt, R_OK) == 0) {
|
||||
g_assert(link(data->crt,
|
||||
CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_CERT) == 0);
|
||||
g_assert(link(KEYFILE,
|
||||
CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
|
||||
}
|
||||
g_assert(link(KEYFILE,
|
||||
CERT_DIR QCRYPTO_TLS_CREDS_X509_SERVER_KEY) == 0);
|
||||
} else {
|
||||
if (access(data->crt, R_OK) == 0) {
|
||||
g_assert(link(data->crt,
|
||||
CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_CERT) == 0);
|
||||
g_assert(link(KEYFILE,
|
||||
CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
|
||||
}
|
||||
g_assert(link(KEYFILE,
|
||||
CERT_DIR QCRYPTO_TLS_CREDS_X509_CLIENT_KEY) == 0);
|
||||
}
|
||||
|
||||
creds = test_tls_creds_create(
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
#define KEYFILE WORKDIR "key-ctx.pem"
|
||||
|
||||
static ssize_t
|
||||
testWrite(const char *buf, size_t len, void *opaque, Error **errp)
|
||||
testWrite(const void *buf, size_t len, void *opaque, Error **errp)
|
||||
{
|
||||
int *fd = opaque;
|
||||
int ret;
|
||||
|
|
@ -54,7 +54,7 @@ testWrite(const char *buf, size_t len, void *opaque, Error **errp)
|
|||
}
|
||||
|
||||
static ssize_t
|
||||
testRead(char *buf, size_t len, void *opaque, Error **errp)
|
||||
testRead(void *buf, size_t len, void *opaque, Error **errp)
|
||||
{
|
||||
int *fd = opaque;
|
||||
int ret;
|
||||
|
|
|
|||
|
|
@ -1,529 +0,0 @@
|
|||
/*
|
||||
* QEMU Crypto XTS cipher mode
|
||||
*
|
||||
* Copyright (c) 2015-2018 Red Hat, Inc.
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* This code is originally derived from public domain / WTFPL code in
|
||||
* LibTomCrypt crytographic library http://libtom.org. The XTS code
|
||||
* was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
|
||||
* to the LibTom Projects
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "crypto/init.h"
|
||||
#include "crypto/xts.h"
|
||||
#include "crypto/aes.h"
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
int keylen;
|
||||
unsigned char key1[32];
|
||||
unsigned char key2[32];
|
||||
uint64_t seqnum;
|
||||
unsigned long PTLEN;
|
||||
unsigned char PTX[512], CTX[512];
|
||||
} QCryptoXTSTestData;
|
||||
|
||||
static const QCryptoXTSTestData test_data[] = {
|
||||
/* #1 32 byte key, 32 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-1-key-32-ptx-32",
|
||||
32,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
0,
|
||||
32,
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x91, 0x7c, 0xf6, 0x9e, 0xbd, 0x68, 0xb2, 0xec,
|
||||
0x9b, 0x9f, 0xe9, 0xa3, 0xea, 0xdd, 0xa6, 0x92,
|
||||
0xcd, 0x43, 0xd2, 0xf5, 0x95, 0x98, 0xed, 0x85,
|
||||
0x8c, 0x02, 0xc2, 0x65, 0x2f, 0xbf, 0x92, 0x2e },
|
||||
},
|
||||
|
||||
/* #2, 32 byte key, 32 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-2-key-32-ptx-32",
|
||||
32,
|
||||
{ 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 },
|
||||
{ 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
|
||||
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 },
|
||||
0x3333333333LL,
|
||||
32,
|
||||
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
|
||||
{ 0xc4, 0x54, 0x18, 0x5e, 0x6a, 0x16, 0x93, 0x6e,
|
||||
0x39, 0x33, 0x40, 0x38, 0xac, 0xef, 0x83, 0x8b,
|
||||
0xfb, 0x18, 0x6f, 0xff, 0x74, 0x80, 0xad, 0xc4,
|
||||
0x28, 0x93, 0x82, 0xec, 0xd6, 0xd3, 0x94, 0xf0 },
|
||||
},
|
||||
|
||||
/* #5 from xts.7, 32 byte key, 32 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-5-key-32-ptx-32",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
32,
|
||||
{ 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
|
||||
0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 },
|
||||
{ 0xb0, 0x1f, 0x86, 0xf8, 0xed, 0xc1, 0x86, 0x37,
|
||||
0x06, 0xfa, 0x8a, 0x42, 0x53, 0xe3, 0x4f, 0x28,
|
||||
0xaf, 0x31, 0x9d, 0xe3, 0x83, 0x34, 0x87, 0x0f,
|
||||
0x4d, 0xd1, 0xf9, 0x4c, 0xbe, 0x98, 0x32, 0xf1 },
|
||||
},
|
||||
|
||||
/* #4, 32 byte key, 512 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-4-key-32-ptx-512",
|
||||
32,
|
||||
{ 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45,
|
||||
0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26 },
|
||||
{ 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93,
|
||||
0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95 },
|
||||
0,
|
||||
512,
|
||||
{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
},
|
||||
{
|
||||
0x27, 0xa7, 0x47, 0x9b, 0xef, 0xa1, 0xd4, 0x76,
|
||||
0x48, 0x9f, 0x30, 0x8c, 0xd4, 0xcf, 0xa6, 0xe2,
|
||||
0xa9, 0x6e, 0x4b, 0xbe, 0x32, 0x08, 0xff, 0x25,
|
||||
0x28, 0x7d, 0xd3, 0x81, 0x96, 0x16, 0xe8, 0x9c,
|
||||
0xc7, 0x8c, 0xf7, 0xf5, 0xe5, 0x43, 0x44, 0x5f,
|
||||
0x83, 0x33, 0xd8, 0xfa, 0x7f, 0x56, 0x00, 0x00,
|
||||
0x05, 0x27, 0x9f, 0xa5, 0xd8, 0xb5, 0xe4, 0xad,
|
||||
0x40, 0xe7, 0x36, 0xdd, 0xb4, 0xd3, 0x54, 0x12,
|
||||
0x32, 0x80, 0x63, 0xfd, 0x2a, 0xab, 0x53, 0xe5,
|
||||
0xea, 0x1e, 0x0a, 0x9f, 0x33, 0x25, 0x00, 0xa5,
|
||||
0xdf, 0x94, 0x87, 0xd0, 0x7a, 0x5c, 0x92, 0xcc,
|
||||
0x51, 0x2c, 0x88, 0x66, 0xc7, 0xe8, 0x60, 0xce,
|
||||
0x93, 0xfd, 0xf1, 0x66, 0xa2, 0x49, 0x12, 0xb4,
|
||||
0x22, 0x97, 0x61, 0x46, 0xae, 0x20, 0xce, 0x84,
|
||||
0x6b, 0xb7, 0xdc, 0x9b, 0xa9, 0x4a, 0x76, 0x7a,
|
||||
0xae, 0xf2, 0x0c, 0x0d, 0x61, 0xad, 0x02, 0x65,
|
||||
0x5e, 0xa9, 0x2d, 0xc4, 0xc4, 0xe4, 0x1a, 0x89,
|
||||
0x52, 0xc6, 0x51, 0xd3, 0x31, 0x74, 0xbe, 0x51,
|
||||
0xa1, 0x0c, 0x42, 0x11, 0x10, 0xe6, 0xd8, 0x15,
|
||||
0x88, 0xed, 0xe8, 0x21, 0x03, 0xa2, 0x52, 0xd8,
|
||||
0xa7, 0x50, 0xe8, 0x76, 0x8d, 0xef, 0xff, 0xed,
|
||||
0x91, 0x22, 0x81, 0x0a, 0xae, 0xb9, 0x9f, 0x91,
|
||||
0x72, 0xaf, 0x82, 0xb6, 0x04, 0xdc, 0x4b, 0x8e,
|
||||
0x51, 0xbc, 0xb0, 0x82, 0x35, 0xa6, 0xf4, 0x34,
|
||||
0x13, 0x32, 0xe4, 0xca, 0x60, 0x48, 0x2a, 0x4b,
|
||||
0xa1, 0xa0, 0x3b, 0x3e, 0x65, 0x00, 0x8f, 0xc5,
|
||||
0xda, 0x76, 0xb7, 0x0b, 0xf1, 0x69, 0x0d, 0xb4,
|
||||
0xea, 0xe2, 0x9c, 0x5f, 0x1b, 0xad, 0xd0, 0x3c,
|
||||
0x5c, 0xcf, 0x2a, 0x55, 0xd7, 0x05, 0xdd, 0xcd,
|
||||
0x86, 0xd4, 0x49, 0x51, 0x1c, 0xeb, 0x7e, 0xc3,
|
||||
0x0b, 0xf1, 0x2b, 0x1f, 0xa3, 0x5b, 0x91, 0x3f,
|
||||
0x9f, 0x74, 0x7a, 0x8a, 0xfd, 0x1b, 0x13, 0x0e,
|
||||
0x94, 0xbf, 0xf9, 0x4e, 0xff, 0xd0, 0x1a, 0x91,
|
||||
0x73, 0x5c, 0xa1, 0x72, 0x6a, 0xcd, 0x0b, 0x19,
|
||||
0x7c, 0x4e, 0x5b, 0x03, 0x39, 0x36, 0x97, 0xe1,
|
||||
0x26, 0x82, 0x6f, 0xb6, 0xbb, 0xde, 0x8e, 0xcc,
|
||||
0x1e, 0x08, 0x29, 0x85, 0x16, 0xe2, 0xc9, 0xed,
|
||||
0x03, 0xff, 0x3c, 0x1b, 0x78, 0x60, 0xf6, 0xde,
|
||||
0x76, 0xd4, 0xce, 0xcd, 0x94, 0xc8, 0x11, 0x98,
|
||||
0x55, 0xef, 0x52, 0x97, 0xca, 0x67, 0xe9, 0xf3,
|
||||
0xe7, 0xff, 0x72, 0xb1, 0xe9, 0x97, 0x85, 0xca,
|
||||
0x0a, 0x7e, 0x77, 0x20, 0xc5, 0xb3, 0x6d, 0xc6,
|
||||
0xd7, 0x2c, 0xac, 0x95, 0x74, 0xc8, 0xcb, 0xbc,
|
||||
0x2f, 0x80, 0x1e, 0x23, 0xe5, 0x6f, 0xd3, 0x44,
|
||||
0xb0, 0x7f, 0x22, 0x15, 0x4b, 0xeb, 0xa0, 0xf0,
|
||||
0x8c, 0xe8, 0x89, 0x1e, 0x64, 0x3e, 0xd9, 0x95,
|
||||
0xc9, 0x4d, 0x9a, 0x69, 0xc9, 0xf1, 0xb5, 0xf4,
|
||||
0x99, 0x02, 0x7a, 0x78, 0x57, 0x2a, 0xee, 0xbd,
|
||||
0x74, 0xd2, 0x0c, 0xc3, 0x98, 0x81, 0xc2, 0x13,
|
||||
0xee, 0x77, 0x0b, 0x10, 0x10, 0xe4, 0xbe, 0xa7,
|
||||
0x18, 0x84, 0x69, 0x77, 0xae, 0x11, 0x9f, 0x7a,
|
||||
0x02, 0x3a, 0xb5, 0x8c, 0xca, 0x0a, 0xd7, 0x52,
|
||||
0xaf, 0xe6, 0x56, 0xbb, 0x3c, 0x17, 0x25, 0x6a,
|
||||
0x9f, 0x6e, 0x9b, 0xf1, 0x9f, 0xdd, 0x5a, 0x38,
|
||||
0xfc, 0x82, 0xbb, 0xe8, 0x72, 0xc5, 0x53, 0x9e,
|
||||
0xdb, 0x60, 0x9e, 0xf4, 0xf7, 0x9c, 0x20, 0x3e,
|
||||
0xbb, 0x14, 0x0f, 0x2e, 0x58, 0x3c, 0xb2, 0xad,
|
||||
0x15, 0xb4, 0xaa, 0x5b, 0x65, 0x50, 0x16, 0xa8,
|
||||
0x44, 0x92, 0x77, 0xdb, 0xd4, 0x77, 0xef, 0x2c,
|
||||
0x8d, 0x6c, 0x01, 0x7d, 0xb7, 0x38, 0xb1, 0x8d,
|
||||
0xeb, 0x4a, 0x42, 0x7d, 0x19, 0x23, 0xce, 0x3f,
|
||||
0xf2, 0x62, 0x73, 0x57, 0x79, 0xa4, 0x18, 0xf2,
|
||||
0x0a, 0x28, 0x2d, 0xf9, 0x20, 0x14, 0x7b, 0xea,
|
||||
0xbe, 0x42, 0x1e, 0xe5, 0x31, 0x9d, 0x05, 0x68,
|
||||
}
|
||||
},
|
||||
|
||||
/* #7, 32 byte key, 17 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-7-key-32-ptx-17",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
17,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 },
|
||||
{ 0x6c, 0x16, 0x25, 0xdb, 0x46, 0x71, 0x52, 0x2d,
|
||||
0x3d, 0x75, 0x99, 0x60, 0x1d, 0xe7, 0xca, 0x09, 0xed },
|
||||
},
|
||||
|
||||
/* #15, 32 byte key, 25 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-15-key-32-ptx-25",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
25,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 },
|
||||
{ 0x8f, 0x4d, 0xcb, 0xad, 0x55, 0x55, 0x8d, 0x7b,
|
||||
0x4e, 0x01, 0xd9, 0x37, 0x9c, 0xd4, 0xea, 0x22,
|
||||
0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a, 0x73 },
|
||||
},
|
||||
|
||||
/* #21, 32 byte key, 31 byte PTX */
|
||||
{
|
||||
"/crypto/xts/t-21-key-32-ptx-31",
|
||||
32,
|
||||
{ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0 },
|
||||
{ 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0 },
|
||||
0x123456789aLL,
|
||||
31,
|
||||
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e },
|
||||
{ 0xd0, 0x5b, 0xc0, 0x90, 0xa8, 0xe0, 0x4f, 0x1b,
|
||||
0x3d, 0x3e, 0xcd, 0xd5, 0xba, 0xec, 0x0f, 0xd4,
|
||||
0xed, 0xbf, 0x9d, 0xac, 0xe4, 0x5d, 0x6f, 0x6a,
|
||||
0x73, 0x06, 0xe6, 0x4b, 0xe5, 0xdd, 0x82 },
|
||||
},
|
||||
};
|
||||
|
||||
#define STORE64L(x, y) \
|
||||
do { \
|
||||
(y)[7] = (unsigned char)(((x) >> 56) & 255); \
|
||||
(y)[6] = (unsigned char)(((x) >> 48) & 255); \
|
||||
(y)[5] = (unsigned char)(((x) >> 40) & 255); \
|
||||
(y)[4] = (unsigned char)(((x) >> 32) & 255); \
|
||||
(y)[3] = (unsigned char)(((x) >> 24) & 255); \
|
||||
(y)[2] = (unsigned char)(((x) >> 16) & 255); \
|
||||
(y)[1] = (unsigned char)(((x) >> 8) & 255); \
|
||||
(y)[0] = (unsigned char)((x) & 255); \
|
||||
} while (0)
|
||||
|
||||
struct TestAES {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
|
||||
static void test_xts_aes_encrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const struct TestAES *aesctx = ctx;
|
||||
|
||||
AES_encrypt(src, dst, &aesctx->enc);
|
||||
}
|
||||
|
||||
|
||||
static void test_xts_aes_decrypt(const void *ctx,
|
||||
size_t length,
|
||||
uint8_t *dst,
|
||||
const uint8_t *src)
|
||||
{
|
||||
const struct TestAES *aesctx = ctx;
|
||||
|
||||
AES_decrypt(src, dst, &aesctx->dec);
|
||||
}
|
||||
|
||||
|
||||
static void test_xts(const void *opaque)
|
||||
{
|
||||
const QCryptoXTSTestData *data = opaque;
|
||||
uint8_t out[512], Torg[16], T[16];
|
||||
uint64_t seq;
|
||||
struct TestAES aesdata;
|
||||
struct TestAES aestweak;
|
||||
|
||||
AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
|
||||
AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
|
||||
AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
|
||||
AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
|
||||
|
||||
seq = data->seqnum;
|
||||
STORE64L(seq, Torg);
|
||||
memset(Torg + 8, 0, 8);
|
||||
|
||||
memcpy(T, Torg, sizeof(T));
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, out, data->PTX);
|
||||
|
||||
g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
|
||||
|
||||
memcpy(T, Torg, sizeof(T));
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, out, data->CTX);
|
||||
|
||||
g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
|
||||
}
|
||||
|
||||
|
||||
static void test_xts_split(const void *opaque)
|
||||
{
|
||||
const QCryptoXTSTestData *data = opaque;
|
||||
uint8_t out[512], Torg[16], T[16];
|
||||
uint64_t seq;
|
||||
unsigned long len = data->PTLEN / 2;
|
||||
struct TestAES aesdata;
|
||||
struct TestAES aestweak;
|
||||
|
||||
AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
|
||||
AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
|
||||
AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
|
||||
AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
|
||||
|
||||
seq = data->seqnum;
|
||||
STORE64L(seq, Torg);
|
||||
memset(Torg + 8, 0, 8);
|
||||
|
||||
memcpy(T, Torg, sizeof(T));
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, out, data->PTX);
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, &out[len], &data->PTX[len]);
|
||||
|
||||
g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
|
||||
|
||||
memcpy(T, Torg, sizeof(T));
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, out, data->CTX);
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, len, &out[len], &data->CTX[len]);
|
||||
|
||||
g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
|
||||
}
|
||||
|
||||
|
||||
static void test_xts_unaligned(const void *opaque)
|
||||
{
|
||||
#define BAD_ALIGN 3
|
||||
const QCryptoXTSTestData *data = opaque;
|
||||
uint8_t in[512 + BAD_ALIGN], out[512 + BAD_ALIGN];
|
||||
uint8_t Torg[16], T[16 + BAD_ALIGN];
|
||||
uint64_t seq;
|
||||
struct TestAES aesdata;
|
||||
struct TestAES aestweak;
|
||||
|
||||
AES_set_encrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.enc);
|
||||
AES_set_decrypt_key(data->key1, data->keylen / 2 * 8, &aesdata.dec);
|
||||
AES_set_encrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.enc);
|
||||
AES_set_decrypt_key(data->key2, data->keylen / 2 * 8, &aestweak.dec);
|
||||
|
||||
seq = data->seqnum;
|
||||
STORE64L(seq, Torg);
|
||||
memset(Torg + 8, 0, 8);
|
||||
|
||||
/* IV not aligned */
|
||||
memcpy(T + BAD_ALIGN, Torg, 16);
|
||||
memcpy(in, data->PTX, data->PTLEN);
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T + BAD_ALIGN, data->PTLEN, out, in);
|
||||
|
||||
g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
|
||||
|
||||
/* plain text not aligned */
|
||||
memcpy(T, Torg, 16);
|
||||
memcpy(in + BAD_ALIGN, data->PTX, data->PTLEN);
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, out, in + BAD_ALIGN);
|
||||
|
||||
g_assert(memcmp(out, data->CTX, data->PTLEN) == 0);
|
||||
|
||||
/* cipher text not aligned */
|
||||
memcpy(T, Torg, 16);
|
||||
memcpy(in, data->PTX, data->PTLEN);
|
||||
xts_encrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, out + BAD_ALIGN, in);
|
||||
|
||||
g_assert(memcmp(out + BAD_ALIGN, data->CTX, data->PTLEN) == 0);
|
||||
|
||||
|
||||
/* IV not aligned */
|
||||
memcpy(T + BAD_ALIGN, Torg, 16);
|
||||
memcpy(in, data->CTX, data->PTLEN);
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T + BAD_ALIGN, data->PTLEN, out, in);
|
||||
|
||||
g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
|
||||
|
||||
/* cipher text not aligned */
|
||||
memcpy(T, Torg, 16);
|
||||
memcpy(in + BAD_ALIGN, data->CTX, data->PTLEN);
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, out, in + BAD_ALIGN);
|
||||
|
||||
g_assert(memcmp(out, data->PTX, data->PTLEN) == 0);
|
||||
|
||||
/* plain text not aligned */
|
||||
memcpy(T, Torg, 16);
|
||||
memcpy(in, data->CTX, data->PTLEN);
|
||||
xts_decrypt(&aesdata, &aestweak,
|
||||
test_xts_aes_encrypt,
|
||||
test_xts_aes_decrypt,
|
||||
T, data->PTLEN, out + BAD_ALIGN, in);
|
||||
|
||||
g_assert(memcmp(out + BAD_ALIGN, data->PTX, data->PTLEN) == 0);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
g_assert(qcrypto_init(NULL) == 0);
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
gchar *path = g_strdup_printf("%s/basic", test_data[i].path);
|
||||
g_test_add_data_func(path, &test_data[i], test_xts);
|
||||
g_free(path);
|
||||
|
||||
/* skip the cases where the length is smaller than 2*blocklen
|
||||
* or the length is not a multiple of 32
|
||||
*/
|
||||
if ((test_data[i].PTLEN >= 32) && !(test_data[i].PTLEN % 32)) {
|
||||
path = g_strdup_printf("%s/split", test_data[i].path);
|
||||
g_test_add_data_func(path, &test_data[i], test_xts_split);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
path = g_strdup_printf("%s/unaligned", test_data[i].path);
|
||||
g_test_add_data_func(path, &test_data[i], test_xts_unaligned);
|
||||
g_free(path);
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
9
ui/vnc.c
9
ui/vnc.c
|
|
@ -578,7 +578,6 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
|
|||
bool vnc_display_reload_certs(const char *id, Error **errp)
|
||||
{
|
||||
VncDisplay *vd = vnc_display_find(id);
|
||||
QCryptoTLSCredsClass *creds = NULL;
|
||||
|
||||
if (!vd) {
|
||||
error_setg(errp, "Can not find vnc display");
|
||||
|
|
@ -590,13 +589,7 @@ bool vnc_display_reload_certs(const char *id, Error **errp)
|
|||
return false;
|
||||
}
|
||||
|
||||
creds = QCRYPTO_TLS_CREDS_GET_CLASS(OBJECT(vd->tlscreds));
|
||||
if (creds->reload == NULL) {
|
||||
error_setg(errp, "%s doesn't support to reload TLS credential",
|
||||
object_get_typename(OBJECT(vd->tlscreds)));
|
||||
return false;
|
||||
}
|
||||
if (!creds->reload(vd->tlscreds, errp)) {
|
||||
if (!qcrypto_tls_creds_reload(vd->tlscreds, errp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue