Merge misc, crypto and I/O subsystems changes

* Fix use after free in websocket handshake (CVE-2025-11234)
  * Improved stack traces fatal errors/aborts raised for
    user creatable objects
  * Stop requiring 'key encipherment' usage in x509 certs
  * Only sanity check CA certs needed in the chain of trust
  * Allow intermediate CA certs to be present in client/server
    cert file
  * Fix regression propagating errors in premature shutdown
    of TLS connections
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmj7nZQACgkQvobrtBUQ
 T9+ezBAAsgKl5O/8FYGoSAaVHq4dzbXl/Q0NzHzX7NJ7W8K6LvNy4w8zpuPZEWIt
 luo3uAeRFmWGCE5kAe/rfySwvNAYfKTJWbd4+c/DN6spK8MViMfY/mL2Zows3LsJ
 LDkmi7OVZpTO+JTDt9O0LpjXmtRGunDsm1Wq8WZcrLtsMe0KatVaQen0nFqc8aUf
 uwAgMrZiMpsGp23PLlxaqQVBV2lzXGQHb1Y2UR0DkMBn19861ovPeNRgODc1SpmV
 pvqoeXNVu3Mw4CmY3jb0fArRD8G6g8y0USahVNfXV3cYFXp1/SaEL4sNbYU3VhxG
 MJXvA+uVir6HHJWiDbjiAG+6zjoggaPAwkp5f4M89fnPGgX9sRRAsCdJnR5IIEDo
 58bc1WWni+KzkDXY/GJ1lMQ6jJuQxavIcpW/zi/sSLu1ceK+j+JqLmjGzpr1mPrk
 D63MvLSOsKFgJNP51OeC5s3GN9UOo6jO/wOMyLTDUTdhc/WOz3Q+f5/E/bRXtaE0
 S+NxMTHJdwDfeRpDXMglL9f5K1ApBo7GAMmjhwXCD3XqUb1pD7RbFNu+QKMqgT4Z
 Jv/Rsik3XOHMFNoMtm+fSaUfeETASJBQQancnLyUcCUrWR9MTKBAtlm0fJypxaBp
 787FL5LthIX5u7tNf5Btl67BJalHFICVEQrFe/gPq5YnuIRDmwo=
 =WY6C
 -----END PGP SIGNATURE-----

Merge tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu into staging

Merge misc, crypto and I/O subsystems changes

 * Fix use after free in websocket handshake (CVE-2025-11234)
 * Improved stack traces fatal errors/aborts raised for
   user creatable objects
 * Stop requiring 'key encipherment' usage in x509 certs
 * Only sanity check CA certs needed in the chain of trust
 * Allow intermediate CA certs to be present in client/server
   cert file
 * Fix regression propagating errors in premature shutdown
   of TLS connections

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmj7nZQACgkQvobrtBUQ
# T9+ezBAAsgKl5O/8FYGoSAaVHq4dzbXl/Q0NzHzX7NJ7W8K6LvNy4w8zpuPZEWIt
# luo3uAeRFmWGCE5kAe/rfySwvNAYfKTJWbd4+c/DN6spK8MViMfY/mL2Zows3LsJ
# LDkmi7OVZpTO+JTDt9O0LpjXmtRGunDsm1Wq8WZcrLtsMe0KatVaQen0nFqc8aUf
# uwAgMrZiMpsGp23PLlxaqQVBV2lzXGQHb1Y2UR0DkMBn19861ovPeNRgODc1SpmV
# pvqoeXNVu3Mw4CmY3jb0fArRD8G6g8y0USahVNfXV3cYFXp1/SaEL4sNbYU3VhxG
# MJXvA+uVir6HHJWiDbjiAG+6zjoggaPAwkp5f4M89fnPGgX9sRRAsCdJnR5IIEDo
# 58bc1WWni+KzkDXY/GJ1lMQ6jJuQxavIcpW/zi/sSLu1ceK+j+JqLmjGzpr1mPrk
# D63MvLSOsKFgJNP51OeC5s3GN9UOo6jO/wOMyLTDUTdhc/WOz3Q+f5/E/bRXtaE0
# S+NxMTHJdwDfeRpDXMglL9f5K1ApBo7GAMmjhwXCD3XqUb1pD7RbFNu+QKMqgT4Z
# Jv/Rsik3XOHMFNoMtm+fSaUfeETASJBQQancnLyUcCUrWR9MTKBAtlm0fJypxaBp
# 787FL5LthIX5u7tNf5Btl67BJalHFICVEQrFe/gPq5YnuIRDmwo=
# =WY6C
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 24 Oct 2025 05:39:00 PM CEST
# gpg:                using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [unknown]
# gpg:                 aka "Daniel P. Berrange <berrange@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E  8E3F BE86 EBB4 1510 4FDF

* tag 'next-pr-pull-request' of https://gitlab.com/berrange/qemu:
  crypto: switch to newer gnutls API for distinguished name
  crypto: stop requiring "key encipherment" usage in x509 certs
  crypto: allow client/server cert chains
  crypto: fix error reporting in cert chain checks
  crypto: validate an error is reported in test expected fails
  crypto: remove extraneous pointer usage in gnutls certs
  crypto: only verify CA certs in chain of trust
  io: fix use after free in websocket handshake code
  io: move websock resource release to close method
  io: release active GSource in TLS channel finalizer
  tests: use macros for registering char tests for sockets
  qom: use ERRP_GUARD in user_creatable_complete
  crypto: propagate Error object on premature termination

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2025-10-25 10:42:55 +02:00
commit 36076d24f0
12 changed files with 338 additions and 175 deletions

View file

@ -144,7 +144,7 @@ qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds,
if (status < 0) {
if (status == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
usage = isCA ? GNUTLS_KEY_KEY_CERT_SIGN :
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT;
GNUTLS_KEY_DIGITAL_SIGNATURE;
} else {
error_setg(errp,
"Unable to query certificate %s key usage: %s",
@ -171,14 +171,6 @@ qcrypto_tls_creds_check_cert_key_usage(QCryptoTLSCredsX509 *creds,
return -1;
}
}
if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) {
if (critical) {
error_setg(errp,
"Certificate %s usage does not permit key "
"encipherment", certFile);
return -1;
}
}
}
return 0;
@ -315,9 +307,90 @@ qcrypto_tls_creds_check_cert(QCryptoTLSCredsX509 *creds,
return 0;
}
static int
qcrypto_tls_creds_check_authority_chain(QCryptoTLSCredsX509 *creds,
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];
int retval = 0;
gnutls_datum_t dn = {}, dnissuer = {};
for (int i = 0; i < (ncerts - 1); i++) {
if (!gnutls_x509_crt_check_issuer(certs[i], certs[i + 1])) {
retval = gnutls_x509_crt_get_dn2(certs[i], &dn);
if (retval < 0) {
error_setg(errp, "Unable to fetch cert DN: %s",
gnutls_strerror(retval));
return -1;
}
retval = gnutls_x509_crt_get_dn2(certs[i + 1], &dnissuer);
if (retval < 0) {
g_free(dn.data);
error_setg(errp, "Unable to fetch cert DN: %s",
gnutls_strerror(retval));
return -1;
}
error_setg(errp, "Cert '%s' does not match issuer of cert '%s'",
dnissuer.data, dn.data);
g_free(dn.data);
g_free(dnissuer.data);
return -1;
}
}
for (;;) {
gnutls_x509_crt_t cert_issuer = NULL;
if (gnutls_x509_crt_check_issuer(cert_to_check,
cert_to_check)) {
/*
* The cert is self-signed indicating we have
* reached the root of trust.
*/
return qcrypto_tls_creds_check_cert(
creds, cert_to_check, cacertFile,
isServer, isCA, errp);
}
for (int i = 0; i < ncacerts; i++) {
if (gnutls_x509_crt_check_issuer(cert_to_check,
cacerts[i])) {
cert_issuer = cacerts[i];
break;
}
}
if (!cert_issuer) {
break;
}
if (qcrypto_tls_creds_check_cert(creds, cert_issuer, cacertFile,
isServer, isCA, errp) < 0) {
return -1;
}
cert_to_check = cert_issuer;
}
retval = gnutls_x509_crt_get_dn2(cert_to_check, &dn);
if (retval < 0) {
error_setg(errp, "Unable to fetch cert DN: %s",
gnutls_strerror(retval));
return -1;
}
error_setg(errp, "Cert '%s' has no issuer in CA chain", dn.data);
g_free(dn.data);
return -1;
}
static int
qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t *certs,
size_t ncerts,
const char *certFile,
gnutls_x509_crt_t *cacerts,
size_t ncacerts,
@ -327,7 +400,7 @@ qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
{
unsigned int status;
if (gnutls_x509_crt_list_verify(&cert, 1,
if (gnutls_x509_crt_list_verify(certs, ncerts,
cacerts, ncacerts,
NULL, 0,
0, &status) < 0) {
@ -369,66 +442,14 @@ qcrypto_tls_creds_check_cert_pair(gnutls_x509_crt_t cert,
}
static gnutls_x509_crt_t
qcrypto_tls_creds_load_cert(QCryptoTLSCredsX509 *creds,
const char *certFile,
bool isServer,
Error **errp)
{
gnutls_datum_t data;
gnutls_x509_crt_t cert = NULL;
g_autofree char *buf = NULL;
gsize buflen;
GError *gerr = NULL;
int ret = -1;
int err;
trace_qcrypto_tls_creds_x509_load_cert(creds, isServer, certFile);
err = gnutls_x509_crt_init(&cert);
if (err < 0) {
error_setg(errp, "Unable to initialize certificate: %s",
gnutls_strerror(err));
goto cleanup;
}
if (!g_file_get_contents(certFile, &buf, &buflen, &gerr)) {
error_setg(errp, "Cannot load CA cert list %s: %s",
certFile, gerr->message);
g_error_free(gerr);
goto cleanup;
}
data.data = (unsigned char *)buf;
data.size = strlen(buf);
err = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM);
if (err < 0) {
error_setg(errp, isServer ?
"Unable to import server certificate %s: %s" :
"Unable to import client certificate %s: %s",
certFile,
gnutls_strerror(err));
goto cleanup;
}
ret = 0;
cleanup:
if (ret != 0) {
gnutls_x509_crt_deinit(cert);
cert = NULL;
}
return cert;
}
static int
qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
const char *certFile,
gnutls_x509_crt_t **certs,
unsigned int *ncerts,
Error **errp)
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;
@ -451,7 +472,9 @@ qcrypto_tls_creds_load_ca_cert_list(QCryptoTLSCredsX509 *creds,
if (gnutls_x509_crt_list_import2(certs, ncerts, &data,
GNUTLS_X509_FMT_PEM, 0) < 0) {
error_setg(errp,
"Unable to import CA certificate list %s",
isCA ? "Unable to import CA certificate list %s" :
(isServer ? "Unable to import server certificate %s" :
"Unable to import client certificate %s"),
certFile);
return -1;
}
@ -467,7 +490,8 @@ qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
const char *certFile,
Error **errp)
{
gnutls_x509_crt_t cert = NULL;
gnutls_x509_crt_t *certs = NULL;
unsigned int ncerts = 0;
gnutls_x509_crt_t *cacerts = NULL;
unsigned int ncacerts = 0;
size_t i;
@ -475,41 +499,48 @@ qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
if (certFile &&
access(certFile, R_OK) == 0) {
cert = qcrypto_tls_creds_load_cert(creds,
certFile, isServer,
errp);
if (!cert) {
if (qcrypto_tls_creds_load_cert_list(creds,
certFile,
&certs,
&ncerts,
isServer,
false,
errp) < 0) {
goto cleanup;
}
}
if (access(cacertFile, R_OK) == 0) {
if (qcrypto_tls_creds_load_ca_cert_list(creds,
cacertFile,
&cacerts,
&ncacerts,
errp) < 0) {
if (qcrypto_tls_creds_load_cert_list(creds,
cacertFile,
&cacerts,
&ncacerts,
isServer,
true,
errp) < 0) {
goto cleanup;
}
}
if (cert &&
qcrypto_tls_creds_check_cert(creds,
cert, certFile, isServer,
false, errp) < 0) {
for (i = 0; i < ncerts; i++) {
if (qcrypto_tls_creds_check_cert(creds,
certs[i], certFile,
isServer, i != 0, errp) < 0) {
goto cleanup;
}
}
if (ncerts &&
qcrypto_tls_creds_check_authority_chain(creds,
certs, ncerts,
cacerts, ncacerts,
cacertFile, isServer,
true, errp) < 0) {
goto cleanup;
}
for (i = 0; i < ncacerts; i++) {
if (qcrypto_tls_creds_check_cert(creds,
cacerts[i], cacertFile,
isServer, true, errp) < 0) {
goto cleanup;
}
}
if (cert && ncacerts &&
qcrypto_tls_creds_check_cert_pair(cert, certFile, cacerts,
ncacerts, cacertFile,
if (ncerts && ncacerts &&
qcrypto_tls_creds_check_cert_pair(certs, ncerts, certFile,
cacerts, ncacerts, cacertFile,
isServer, errp) < 0) {
goto cleanup;
}
@ -517,8 +548,8 @@ qcrypto_tls_creds_x509_sanity_check(QCryptoTLSCredsX509 *creds,
ret = 0;
cleanup:
if (cert) {
gnutls_x509_crt_deinit(cert);
for (i = 0; i < ncerts; i++) {
gnutls_x509_crt_deinit(certs[i]);
}
for (i = 0; i < ncacerts; i++) {
gnutls_x509_crt_deinit(cacerts[i]);

View file

@ -409,20 +409,14 @@ qcrypto_tls_session_check_certificate(QCryptoTLSSession *session,
}
if (i == 0) {
size_t dnameSize = 1024;
session->peername = g_malloc(dnameSize);
requery:
ret = gnutls_x509_crt_get_dn(cert, session->peername, &dnameSize);
gnutls_datum_t dname = {};
ret = gnutls_x509_crt_get_dn2(cert, &dname);
if (ret < 0) {
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
session->peername = g_realloc(session->peername,
dnameSize);
goto requery;
}
error_setg(errp, "Cannot get client distinguished name: %s",
gnutls_strerror(ret));
goto error;
}
session->peername = (char *)g_steal_pointer(&dname.data);
if (session->authzid) {
bool allow;
@ -569,8 +563,6 @@ qcrypto_tls_session_read(QCryptoTLSSession *session,
if (ret < 0) {
if (ret == GNUTLS_E_AGAIN) {
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else if (ret == GNUTLS_E_PREMATURE_TERMINATION) {
return QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION;
} else {
if (session->rerr) {
error_propagate(errp, session->rerr);
@ -580,7 +572,11 @@ qcrypto_tls_session_read(QCryptoTLSSession *session,
"Cannot read from TLS channel: %s",
gnutls_strerror(ret));
}
return -1;
if (ret == GNUTLS_E_PREMATURE_TERMINATION) {
return QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION;
} else {
return -1;
}
}
}

View file

@ -118,7 +118,6 @@ information for each server, and use it to issue server certificates.
ip_address = 2620:0:cafe::87
ip_address = 2001:24::92
tls_www_server
encryption_key
signing_key
EOF
# certtool --generate-privkey > server-hostNNN-key.pem
@ -134,9 +133,8 @@ the subject alt name extension data. The ``tls_www_server`` keyword is
the key purpose extension to indicate this certificate is intended for
usage in a web server. Although QEMU network services are not in fact
HTTP servers (except for VNC websockets), setting this key purpose is
still recommended. The ``encryption_key`` and ``signing_key`` keyword is
the key usage extension to indicate this certificate is intended for
usage in the data session.
still recommended. The ``signing_key`` keyword is the key usage extension
to indicate this certificate is intended for usage in the data session.
The ``server-hostNNN-key.pem`` and ``server-hostNNN-cert.pem`` files
should now be securely copied to the server for which they were
@ -171,7 +169,6 @@ certificates.
organization = Name of your organization
cn = hostNNN.foo.example.com
tls_www_client
encryption_key
signing_key
EOF
# certtool --generate-privkey > client-hostNNN-key.pem
@ -187,9 +184,8 @@ the ``dns_name`` and ``ip_address`` fields are not included. The
``tls_www_client`` keyword is the key purpose extension to indicate this
certificate is intended for usage in a web client. Although QEMU network
clients are not in fact HTTP clients, setting this key purpose is still
recommended. The ``encryption_key`` and ``signing_key`` keyword is the
key usage extension to indicate this certificate is intended for usage
in the data session.
recommended. The ``signing_key`` keyword is the key usage extension to
indicate this certificate is intended for usage in the data session.
The ``client-hostNNN-key.pem`` and ``client-hostNNN-cert.pem`` files
should now be securely copied to the client for which they were
@ -222,7 +218,6 @@ client and server instructions in one.
ip_address = 2001:24::92
tls_www_server
tls_www_client
encryption_key
signing_key
EOF
# certtool --generate-privkey > both-hostNNN-key.pem

View file

@ -61,7 +61,8 @@ struct QIOChannelWebsock {
size_t payload_remain;
size_t pong_remain;
QIOChannelWebsockMask mask;
guint io_tag;
guint hs_io_tag; /* tracking handshake task */
guint io_tag; /* tracking watch task */
Error *io_err;
gboolean io_eof;
uint8_t opcode;

View file

@ -342,6 +342,16 @@ static void qio_channel_tls_finalize(Object *obj)
{
QIOChannelTLS *ioc = QIO_CHANNEL_TLS(obj);
if (ioc->hs_ioc_tag) {
trace_qio_channel_tls_handshake_cancel(ioc);
g_clear_handle_id(&ioc->hs_ioc_tag, g_source_remove);
}
if (ioc->bye_ioc_tag) {
trace_qio_channel_tls_bye_cancel(ioc);
g_clear_handle_id(&ioc->bye_ioc_tag, g_source_remove);
}
object_unref(OBJECT(ioc->master));
qcrypto_tls_session_free(ioc->session);
}
@ -368,6 +378,7 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
int flags,
Error **errp)
{
ERRP_GUARD();
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(ioc);
size_t i;
ssize_t got = 0;
@ -384,13 +395,13 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
} else {
return QIO_CHANNEL_ERR_BLOCK;
}
} else if (ret == QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION) {
if (qio_channel_tls_allow_premature_termination(tioc, flags)) {
ret = 0;
} else {
return -1;
}
} else if (ret < 0) {
if (ret == QCRYPTO_TLS_SESSION_PREMATURE_TERMINATION &&
qio_channel_tls_allow_premature_termination(tioc, flags)) {
error_free(*errp);
*errp = NULL;
return got;
}
return -1;
}
got += ret;

View file

@ -545,6 +545,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err));
qio_task_set_error(task, err);
qio_task_complete(task);
wioc->hs_io_tag = 0;
return FALSE;
}
@ -560,6 +561,7 @@ static gboolean qio_channel_websock_handshake_send(QIOChannel *ioc,
trace_qio_channel_websock_handshake_complete(ioc);
qio_task_complete(task);
}
wioc->hs_io_tag = 0;
return FALSE;
}
trace_qio_channel_websock_handshake_pending(ioc, G_IO_OUT);
@ -586,6 +588,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
trace_qio_channel_websock_handshake_fail(ioc, error_get_pretty(err));
qio_task_set_error(task, err);
qio_task_complete(task);
wioc->hs_io_tag = 0;
return FALSE;
}
if (ret == 0) {
@ -597,7 +600,7 @@ static gboolean qio_channel_websock_handshake_io(QIOChannel *ioc,
error_propagate(&wioc->io_err, err);
trace_qio_channel_websock_handshake_reply(ioc);
qio_channel_add_watch(
wioc->hs_io_tag = qio_channel_add_watch(
wioc->master,
G_IO_OUT,
qio_channel_websock_handshake_send,
@ -907,11 +910,12 @@ void qio_channel_websock_handshake(QIOChannelWebsock *ioc,
trace_qio_channel_websock_handshake_start(ioc);
trace_qio_channel_websock_handshake_pending(ioc, G_IO_IN);
qio_channel_add_watch(ioc->master,
G_IO_IN,
qio_channel_websock_handshake_io,
task,
NULL);
ioc->hs_io_tag = qio_channel_add_watch(
ioc->master,
G_IO_IN,
qio_channel_websock_handshake_io,
task,
NULL);
}
@ -922,13 +926,16 @@ static void qio_channel_websock_finalize(Object *obj)
buffer_free(&ioc->encinput);
buffer_free(&ioc->encoutput);
buffer_free(&ioc->rawinput);
object_unref(OBJECT(ioc->master));
if (ioc->hs_io_tag) {
g_source_remove(ioc->hs_io_tag);
}
if (ioc->io_tag) {
g_source_remove(ioc->io_tag);
}
if (ioc->io_err) {
error_free(ioc->io_err);
}
object_unref(OBJECT(ioc->master));
}
@ -1218,6 +1225,18 @@ static int qio_channel_websock_close(QIOChannel *ioc,
QIOChannelWebsock *wioc = QIO_CHANNEL_WEBSOCK(ioc);
trace_qio_channel_websock_close(ioc);
buffer_free(&wioc->encinput);
buffer_free(&wioc->encoutput);
buffer_free(&wioc->rawinput);
if (wioc->hs_io_tag) {
g_clear_handle_id(&wioc->hs_io_tag, g_source_remove);
}
if (wioc->io_tag) {
g_clear_handle_id(&wioc->io_tag, g_source_remove);
}
if (wioc->io_err) {
g_clear_pointer(&wioc->io_err, error_free);
}
return qio_channel_close(wioc->master, errp);
}

View file

@ -24,13 +24,12 @@
bool user_creatable_complete(UserCreatable *uc, Error **errp)
{
UserCreatableClass *ucc = USER_CREATABLE_GET_CLASS(uc);
Error *err = NULL;
ERRP_GUARD();
if (ucc->complete) {
ucc->complete(uc, &err);
error_propagate(errp, err);
ucc->complete(uc, errp);
}
return !err;
return !*errp;
}
bool user_creatable_can_be_deleted(UserCreatable *uc)

View file

@ -148,8 +148,7 @@ void test_tls_cleanup(const char *keyfile);
.basicConstraintsIsCA = false, \
.keyUsageEnable = true, \
.keyUsageCritical = true, \
.keyUsageValue = \
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \
.keyUsageValue = GNUTLS_KEY_DIGITAL_SIGNATURE, \
.keyPurposeEnable = true, \
.keyPurposeCritical = true, \
.keyPurposeOID1 = GNUTLS_KP_TLS_WWW_CLIENT, \
@ -168,8 +167,7 @@ void test_tls_cleanup(const char *keyfile);
.basicConstraintsIsCA = false, \
.keyUsageEnable = true, \
.keyUsageCritical = true, \
.keyUsageValue = \
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT, \
.keyUsageValue = GNUTLS_KEY_DIGITAL_SIGNATURE, \
.keyPurposeEnable = true, \
.keyPurposeCritical = true, \
.keyPurposeOID1 = GNUTLS_KP_TLS_WWW_SERVER, \

View file

@ -1934,7 +1934,9 @@ int main(int argc, char **argv)
g_test_add_data_func("/char/socket/server/mainloop-fdpass/" # name, \
&server3 ##name, char_socket_server_test); \
g_test_add_data_func("/char/socket/server/wait-conn-fdpass/" # name, \
&server4 ##name, char_socket_server_test)
&server4 ##name, char_socket_server_test); \
g_test_add_data_func("/char/socket/server/two-clients/" # name, \
addr, char_socket_server_two_clients_test)
#define SOCKET_CLIENT_TEST(name, addr) \
static CharSocketClientTestConfig client1 ## name = \
@ -1974,14 +1976,10 @@ int main(int argc, char **argv)
if (has_ipv4) {
SOCKET_SERVER_TEST(tcp, &tcpaddr);
SOCKET_CLIENT_TEST(tcp, &tcpaddr);
g_test_add_data_func("/char/socket/server/two-clients/tcp", &tcpaddr,
char_socket_server_two_clients_test);
}
#ifndef WIN32
SOCKET_SERVER_TEST(unix, &unixaddr);
SOCKET_CLIENT_TEST(unix, &unixaddr);
g_test_add_data_func("/char/socket/server/two-clients/unix", &unixaddr,
char_socket_server_two_clients_test);
#endif
g_test_add_func("/char/udp", char_udp_test);

View file

@ -73,6 +73,7 @@ static void test_tls_creds(const void *opaque)
struct QCryptoTLSCredsTestData *data =
(struct QCryptoTLSCredsTestData *)opaque;
QCryptoTLSCreds *creds;
Error *err = NULL;
#define CERT_DIR "tests/test-crypto-tlscredsx509-certs/"
g_mkdir_with_parents(CERT_DIR, 0700);
@ -111,10 +112,12 @@ static void test_tls_creds(const void *opaque)
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER :
QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT),
CERT_DIR,
data->expectFail ? NULL : &error_abort);
data->expectFail ? &err : &error_abort);
if (data->expectFail) {
g_assert(creds == NULL);
g_assert(err != NULL);
error_free(err);
} else {
g_assert(creds != NULL);
}
@ -166,14 +169,14 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(clientcertreq, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, 0);
@ -196,7 +199,7 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
@ -211,7 +214,7 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
@ -226,7 +229,7 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
@ -250,7 +253,7 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
/* no-basic */
@ -264,7 +267,7 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
/* Key usage:dig-sig:critical */
@ -278,7 +281,7 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
@ -303,7 +306,7 @@ int main(int argc, char **argv)
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT |
GNUTLS_KEY_DIGITAL_SIGNATURE |
GNUTLS_KEY_KEY_CERT_SIGN,
false, false, NULL, NULL,
0, 0);
@ -406,7 +409,7 @@ int main(int argc, char **argv)
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT |
GNUTLS_KEY_DIGITAL_SIGNATURE |
GNUTLS_KEY_KEY_CERT_SIGN,
false, false, NULL, NULL,
0, 0);
@ -508,21 +511,21 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(servercertexp1req, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, -1);
TLS_CERT_REQ(clientcertexp1req, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, -1);
@ -546,21 +549,21 @@ int main(int argc, char **argv)
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(servercertnew1req, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
1, 2);
TLS_CERT_REQ(clientcertnew1req, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
1, 2);
@ -577,6 +580,12 @@ int main(int argc, char **argv)
true, true, GNUTLS_KEY_KEY_CERT_SIGN,
false, false, NULL, NULL,
0, 0);
TLS_ROOT_REQ(someotherrootreq,
"UK", "some other random CA", NULL, NULL, NULL, NULL,
true, true, true,
true, true, GNUTLS_KEY_KEY_CERT_SIGN,
false, false, NULL, NULL,
0, 0);
TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
"UK", "qemu level 1a", NULL, NULL, NULL, NULL,
true, true, true,
@ -589,6 +598,12 @@ int main(int argc, char **argv)
true, true, GNUTLS_KEY_KEY_CERT_SIGN,
false, false, NULL, NULL,
0, 0);
TLS_CERT_REQ(cacertlevel1creq_invalid, cacertrootreq,
"UK", "qemu level 1c invalid", NULL, NULL, NULL, NULL,
true, true, true,
true, true, GNUTLS_KEY_KEY_CERT_SIGN,
false, false, NULL, NULL,
360, 400);
TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
"UK", "qemu level 2a", NULL, NULL, NULL, NULL,
true, true, true,
@ -599,14 +614,14 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
"UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, 0);
@ -617,16 +632,110 @@ int main(int argc, char **argv)
cacertlevel2areq.crt,
};
gnutls_x509_crt_t cabundle[] = {
someotherrootreq.crt,
cacertrootreq.crt,
};
gnutls_x509_crt_t servercertchain[] = {
servercertlevel3areq.crt,
cacertlevel2areq.crt,
cacertlevel1areq.crt,
};
gnutls_x509_crt_t servercertchain_incomplete[] = {
servercertlevel3areq.crt,
cacertlevel2areq.crt,
};
gnutls_x509_crt_t servercertchain_unsorted[] = {
servercertlevel3areq.crt,
cacertlevel1areq.crt,
cacertlevel2areq.crt,
};
gnutls_x509_crt_t clientcertchain[] = {
clientcertlevel2breq.crt,
cacertlevel1breq.crt,
};
test_tls_write_cert_chain(WORKDIR "cacertchain-ctx.pem",
certchain,
G_N_ELEMENTS(certchain));
gnutls_x509_crt_t certchain_with_invalid[] = {
cacertrootreq.crt,
cacertlevel1areq.crt,
cacertlevel1breq.crt,
cacertlevel1creq_invalid.crt,
cacertlevel2areq.crt,
};
test_tls_write_cert_chain(WORKDIR "cacertchain-with-invalid-ctx.pem",
certchain_with_invalid,
G_N_ELEMENTS(certchain_with_invalid));
gnutls_x509_crt_t certchain_incomplete[] = {
cacertrootreq.crt,
cacertlevel2areq.crt,
};
test_tls_write_cert_chain(WORKDIR "cacertchain-incomplete-ctx.pem",
certchain_incomplete,
G_N_ELEMENTS(certchain_incomplete));
TLS_TEST_REG(chain1, true,
WORKDIR "cacertchain-ctx.pem",
servercertlevel3areq.filename, false);
TLS_TEST_REG(chain2, false,
WORKDIR "cacertchain-ctx.pem",
clientcertlevel2breq.filename, false);
TLS_TEST_REG(certchainwithexpiredcert, false,
WORKDIR "cacertchain-with-invalid-ctx.pem",
clientcertlevel2breq.filename, false);
TLS_TEST_REG(chainincomplete, true,
WORKDIR "cacertchain-incomplete-ctx.pem",
servercertlevel3areq.filename, true);
test_tls_write_cert_chain(WORKDIR "servercertchain-ctx.pem",
servercertchain,
G_N_ELEMENTS(servercertchain));
TLS_TEST_REG(serverchain, true,
cacertrootreq.filename,
WORKDIR "servercertchain-ctx.pem", false);
test_tls_write_cert_chain(WORKDIR "cabundle-ctx.pem",
cabundle,
G_N_ELEMENTS(cabundle));
TLS_TEST_REG(multiplecaswithchain, true,
WORKDIR "cabundle-ctx.pem",
WORKDIR "servercertchain-ctx.pem", false);
test_tls_write_cert_chain(WORKDIR "servercertchain_incomplete-ctx.pem",
servercertchain_incomplete,
G_N_ELEMENTS(servercertchain_incomplete));
TLS_TEST_REG(incompleteserverchain, true,
cacertrootreq.filename,
WORKDIR "servercertchain_incomplete-ctx.pem", true);
test_tls_write_cert_chain(WORKDIR "servercertchain_unsorted-ctx.pem",
servercertchain_unsorted,
G_N_ELEMENTS(servercertchain_unsorted));
TLS_TEST_REG(unsortedserverchain, true,
cacertrootreq.filename,
WORKDIR "servercertchain_unsorted-ctx.pem", true);
test_tls_write_cert_chain(WORKDIR "clientcertchain-ctx.pem",
clientcertchain,
G_N_ELEMENTS(clientcertchain));
TLS_TEST_REG(clientchain, false,
cacertrootreq.filename,
WORKDIR "clientcertchain-ctx.pem", false);
/* Some missing certs - first two are fatal, the last
* is ok
@ -640,7 +749,6 @@ int main(int argc, char **argv)
TLS_TEST_REG(missingclient, false,
cacert1req.filename,
"clientcertdoesnotexist.pem", false);
ret = g_test_run();
test_tls_discard_cert(&cacertreq);
@ -694,10 +802,17 @@ int main(int argc, char **argv)
test_tls_discard_cert(&cacertrootreq);
test_tls_discard_cert(&cacertlevel1areq);
test_tls_discard_cert(&cacertlevel1breq);
test_tls_discard_cert(&cacertlevel1creq_invalid);
test_tls_discard_cert(&cacertlevel2areq);
test_tls_discard_cert(&servercertlevel3areq);
test_tls_discard_cert(&clientcertlevel2breq);
test_tls_discard_cert(&someotherrootreq);
unlink(WORKDIR "cacertchain-ctx.pem");
unlink(WORKDIR "cacertchain-with-invalid-ctx.pem");
unlink(WORKDIR "servercertchain-ctx.pem");
unlink(WORKDIR "servercertchain_incomplete-ctx.pem");
unlink(WORKDIR "servercertchain_unsorted-ctx.pem");
unlink(WORKDIR "clientcertchain-ctx.pem");
test_tls_cleanup(KEYFILE);
rmdir(WORKDIR);

View file

@ -472,14 +472,14 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(clientcertreq, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, 0);
@ -487,7 +487,7 @@ int main(int argc, char **argv)
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, 0);
@ -506,7 +506,7 @@ int main(int argc, char **argv)
"192.168.122.1", "fec0::dead:beaf",
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
/* This intentionally doesn't replicate */
@ -515,7 +515,7 @@ int main(int argc, char **argv)
"192.168.122.1", "fec0::dead:beaf",
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
@ -619,14 +619,14 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
"UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, 0);

View file

@ -302,14 +302,14 @@ int main(int argc, char **argv)
"UK", "qemu.org", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
0, 0);
TLS_CERT_REQ(clientcertreq, cacertreq,
"UK", "qemu", NULL, NULL, NULL, NULL,
true, true, false,
true, true,
GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
GNUTLS_KEY_DIGITAL_SIGNATURE,
true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
0, 0);