diff --git a/crypto/cipher-gnutls.c.inc b/crypto/cipher-gnutls.c.inc index b9450d48b0..a8263fff6d 100644 --- a/crypto/cipher-gnutls.c.inc +++ b/crypto/cipher-gnutls.c.inc @@ -23,10 +23,6 @@ #include -#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: diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc index ae91363772..1afdc391b4 100644 --- a/crypto/cipher-nettle.c.inc +++ b/crypto/cipher-nettle.c.inc @@ -18,10 +18,6 @@ * */ -#ifdef CONFIG_QEMU_PRIVATE_XTS -#include "crypto/xts.h" -#endif - #include #include #include @@ -30,9 +26,7 @@ #include #include #include -#ifndef CONFIG_QEMU_PRIVATE_XTS #include -#endif #ifdef CONFIG_CRYPTO_SM4 #include #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); \ diff --git a/crypto/cipher.c b/crypto/cipher.c index 229710f76b..515165e0dc 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -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" diff --git a/crypto/hash.c b/crypto/hash.c index 7513769e42..6ffb88bf54 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -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); } diff --git a/crypto/hmac.c b/crypto/hmac.c index 422e005182..2f0d044cf2 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -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 }; diff --git a/crypto/meson.build b/crypto/meson.build index 735635de1f..b51597a879 100644 --- a/crypto/meson.build +++ b/crypto/meson.build @@ -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')) diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c index 9e59594d67..fb09e295a6 100644 --- a/crypto/tlscreds.c +++ b/crypto/tlscreds.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 : ""); - 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, diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index 44af9e6c9a..1551382e1f 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -27,15 +27,19 @@ #include "trace.h" +struct QCryptoTLSCredsAnon { + QCryptoTLSCreds parent_obj; +}; + #ifdef CONFIG_GNUTLS #include - 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 : ""); 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[]) { diff --git a/crypto/tlscredsbox.c b/crypto/tlscredsbox.c new file mode 100644 index 0000000000..b8d9846af8 --- /dev/null +++ b/crypto/tlscredsbox.c @@ -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); + } + +} + diff --git a/crypto/tlscredsbox.h b/crypto/tlscredsbox.h new file mode 100644 index 0000000000..eeb54d1eeb --- /dev/null +++ b/crypto/tlscredsbox.h @@ -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 +#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 */ diff --git a/crypto/tlscredspriv.h b/crypto/tlscredspriv.h index df9815a286..8f2d096c7f 100644 --- a/crypto/tlscredspriv.h +++ b/crypto/tlscredspriv.h @@ -22,6 +22,7 @@ #define QCRYPTO_TLSCREDSPRIV_H #include "crypto/tlscreds.h" +#include "crypto/tlscredsbox.h" #ifdef CONFIG_GNUTLS #include @@ -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, diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 5b68a6b7ba..e1b1e1a613 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -27,6 +27,11 @@ #include "trace.h" +struct QCryptoTLSCredsPSK { + QCryptoTLSCreds parent_obj; + char *username; +}; + #ifdef CONFIG_GNUTLS #include @@ -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 : ""); + 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, diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index db2b74bafa..b8d0cd2f18 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -28,12 +28,81 @@ #include "trace.h" +struct QCryptoTLSCredsX509 { + QCryptoTLSCreds parent_obj; + bool sanityCheck; + char *passwordid; +}; + #ifdef CONFIG_GNUTLS #include #include +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 : ""); + 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); } diff --git a/crypto/tlssession.c b/crypto/tlssession.c index 92fe4f0380..314e3e96ba 100644 --- a/crypto/tlssession.c +++ b/crypto/tlssession.c @@ -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; diff --git a/crypto/trace-events b/crypto/trace-events index d0e33427fa..771f9b8a6e 100644 --- a/crypto/trace-events +++ b/crypto/trace-events @@ -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" diff --git a/crypto/xts.c b/crypto/xts.c deleted file mode 100644 index d4a49fdb70..0000000000 --- a/crypto/xts.c +++ /dev/null @@ -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 . - * - * 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); -} diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 4ee98d6646..03e29915f0 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -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 -------------- diff --git a/docs/system/tls.rst b/docs/system/tls.rst index a4f6781d62..03fa1d8166 100644 --- a/docs/system/tls.rst +++ b/docs/system/tls.rst @@ -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) ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 1868d4a0f7..43525098c5 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -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); diff --git a/include/crypto/hmac.h b/include/crypto/hmac.h index af3d5f8feb..0885ae22d1 100644 --- a/include/crypto/hmac.h +++ b/include/crypto/hmac.h @@ -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); diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h index 2a8a857010..bb9280ed1a 100644 --- a/include/crypto/tlscreds.h +++ b/include/crypto/tlscreds.h @@ -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 */ diff --git a/include/crypto/tlscredsx509.h b/include/crypto/tlscredsx509.h index c4daba21a6..61b7f73573 100644 --- a/include/crypto/tlscredsx509.h +++ b/include/crypto/tlscredsx509.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: diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h index 2e9fe11cf6..28e419681e 100644 --- a/include/crypto/tlssession.h +++ b/include/crypto/tlssession.h @@ -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); diff --git a/include/crypto/xts.h b/include/crypto/xts.h deleted file mode 100644 index f267b7824a..0000000000 --- a/include/crypto/xts.h +++ /dev/null @@ -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 . - * - * 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 */ diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h index a88cf8b3a9..fcfd489c6c 100644 --- a/include/io/channel-socket.h +++ b/include/io/channel-socket.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; }; diff --git a/include/io/channel.h b/include/io/channel.h index 0f25ae0069..db893a3628 100644 --- a/include/io/channel.h +++ b/include/io/channel.h @@ -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); /** diff --git a/include/qemu/exit-with-parent.h b/include/qemu/exit-with-parent.h new file mode 100644 index 0000000000..c00b863fe9 --- /dev/null +++ b/include/qemu/exit-with-parent.h @@ -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 */ diff --git a/io/channel-socket.c b/io/channel-socket.c index 712b793eaf..3053b35ad8 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -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; diff --git a/io/channel-tls.c b/io/channel-tls.c index ce041795c1..b0cec27cb9 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -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) diff --git a/io/channel.c b/io/channel.c index 852e684938..8e8bd2efa8 100644 --- a/io/channel.c +++ b/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 = { diff --git a/meson.build b/meson.build index df876c72f0..b8c1296d3b 100644 --- a/meson.build +++ b/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 - 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 - 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} diff --git a/qemu-options.hx b/qemu-options.hx index 0223ceffeb..fca2b7bc74 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -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 diff --git a/system/exit-with-parent.c b/system/exit-with-parent.c new file mode 100644 index 0000000000..df65d2231a --- /dev/null +++ b/system/exit-with-parent.c @@ -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 + +/* + * 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 + +/* + * 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 + +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 diff --git a/system/meson.build b/system/meson.build index 6d21ff9faa..4b69ef0f5f 100644 --- a/system/meson.build +++ b/system/meson.build @@ -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', diff --git a/system/vl.c b/system/vl.c index 29f5389151..5091fe52d9 100644 --- a/system/vl.c +++ b/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)) { diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 933d085869..622464e365 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -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; diff --git a/tests/unit/meson.build b/tests/unit/meson.build index d5248ae51d..bd58029060 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -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], diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c index 3ac7f17b2a..218e585f98 100644 --- a/tests/unit/test-crypto-block.c +++ b/tests/unit/test-crypto-block.c @@ -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 diff --git a/tests/unit/test-crypto-tlscredsx509.c b/tests/unit/test-crypto-tlscredsx509.c index a5f21728d4..b1ad7d5c0d 100644 --- a/tests/unit/test-crypto-tlscredsx509.c +++ b/tests/unit/test-crypto-tlscredsx509.c @@ -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( diff --git a/tests/unit/test-crypto-tlssession.c b/tests/unit/test-crypto-tlssession.c index d0baf3b304..0d06a6892e 100644 --- a/tests/unit/test-crypto-tlssession.c +++ b/tests/unit/test-crypto-tlssession.c @@ -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; diff --git a/tests/unit/test-crypto-xts.c b/tests/unit/test-crypto-xts.c deleted file mode 100644 index 7acbc956fd..0000000000 --- a/tests/unit/test-crypto-xts.c +++ /dev/null @@ -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 . - * - * 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(); -} diff --git a/ui/vnc.c b/ui/vnc.c index 0094ec680c..50016ff7ab 100644 --- a/ui/vnc.c +++ b/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; }