Crypto patches

* Drop unused 'detached-header' QAPI field from LUKS create options
 * Improve tracing of TLS sockets and TLS chardevs
 * Improve error messages from TLS I/O failures
 * Add docs about use of LUKS detached header options
 * Allow building without libtasn1, but with GNUTLS
 * Fix detection of libgcrypt when libgcrypt-config is absent
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmagzXUACgkQvobrtBUQ
 T9++chAAhCFgo5A/UjQGdl9UAOW/sdgOoHGE3E8Y6sSTQyv+EfHf1DO89JtAh4ft
 d8Hz7Taul4k1wRm6Dxv2aCqH5iS1tgDE2ghGDNwn/zDtHNnjFx3+HcxBaAEcpt3O
 FqvGeG6KdFO1t2UR2DMh1XbhfwygrHiIcSB2y8jrgi46ncS6JvLrFavjLTe7JBn9
 J3y/iYgQiVPN6UlIwUs1EquGdoTI/0SpHVirqHN/2yyrdRsGBsXZq5WI6Oli8zFL
 VqJNmc5Dzo7ushoYG5Rpk83mmC26VuXO/JmXyJ/c7FeADLWUfc/SPPyAMxPGuwFr
 DKg84ovRtq3yZIw8LPoUJOtbcu4Y7BSGwlolQjWegvsVTU6Bdk+teZVR9X64QbM2
 YBXzMkRHUKzR3rb0LewAKehP3n93aBypLln9ZMgg7wj92Rj8Dl/sylaBhDEkH/HQ
 2pMdSdAWqMnGHfnKPxyjflNO2PIsOenZUkDZwf9i7Ow6fU5n3fqvudVDTWjXpWPn
 V7v9JGNPHocScJFRUqHSVqd2ZWaZX4F1TsvG6SGOmzDGR0IjBRlqos7OEdbAAH1x
 IglizbTxD6M9ZWJrGt1sl6LSAwEp3oXgsWNdejq2+7I6H4BeUm4ACDbdrEjqG9aG
 Ya/HpNT0PEzbGXm6qsuHY5z0agGtaPwdXLcSGnsv+a0rP/9nthY=
 =ccYf
 -----END PGP SIGNATURE-----

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

Crypto patches

* Drop unused 'detached-header' QAPI field from LUKS create options
* Improve tracing of TLS sockets and TLS chardevs
* Improve error messages from TLS I/O failures
* Add docs about use of LUKS detached header options
* Allow building without libtasn1, but with GNUTLS
* Fix detection of libgcrypt when libgcrypt-config is absent

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmagzXUACgkQvobrtBUQ
# T9++chAAhCFgo5A/UjQGdl9UAOW/sdgOoHGE3E8Y6sSTQyv+EfHf1DO89JtAh4ft
# d8Hz7Taul4k1wRm6Dxv2aCqH5iS1tgDE2ghGDNwn/zDtHNnjFx3+HcxBaAEcpt3O
# FqvGeG6KdFO1t2UR2DMh1XbhfwygrHiIcSB2y8jrgi46ncS6JvLrFavjLTe7JBn9
# J3y/iYgQiVPN6UlIwUs1EquGdoTI/0SpHVirqHN/2yyrdRsGBsXZq5WI6Oli8zFL
# VqJNmc5Dzo7ushoYG5Rpk83mmC26VuXO/JmXyJ/c7FeADLWUfc/SPPyAMxPGuwFr
# DKg84ovRtq3yZIw8LPoUJOtbcu4Y7BSGwlolQjWegvsVTU6Bdk+teZVR9X64QbM2
# YBXzMkRHUKzR3rb0LewAKehP3n93aBypLln9ZMgg7wj92Rj8Dl/sylaBhDEkH/HQ
# 2pMdSdAWqMnGHfnKPxyjflNO2PIsOenZUkDZwf9i7Ow6fU5n3fqvudVDTWjXpWPn
# V7v9JGNPHocScJFRUqHSVqd2ZWaZX4F1TsvG6SGOmzDGR0IjBRlqos7OEdbAAH1x
# IglizbTxD6M9ZWJrGt1sl6LSAwEp3oXgsWNdejq2+7I6H4BeUm4ACDbdrEjqG9aG
# Ya/HpNT0PEzbGXm6qsuHY5z0agGtaPwdXLcSGnsv+a0rP/9nthY=
# =ccYf
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 24 Jul 2024 07:46:29 PM AEST
# gpg:                using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full]
# gpg:                 aka "Daniel P. Berrange <berrange@redhat.com>" [full]

* tag 'misc-fixes-pull-request' of https://gitlab.com/berrange/qemu:
  crypto: propagate errors from TLS session I/O callbacks
  crypto: push error reporting into TLS session I/O APIs
  crypto: drop gnutls debug logging support
  chardev: add tracing of socket error conditions
  meson: build chardev trace files when have_block
  qapi: drop unused QCryptoBlockCreateOptionsLUKS.detached-header
  meson.build: fix libgcrypt detection on system without libgcrypt-config
  docs/devel: Add introduction to LUKS volume with detached header
  crypto: Allow building with GnuTLS but without Libtasn1
  crypto: Restrict pkix_asn1_tab[] to crypto-tls-x509-helpers.c
  crypto: Remove 'crypto-tls-x509-helpers.h' from crypto-tls-psk-helpers.c

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2024-07-24 21:35:10 +10:00
commit 9726687f2f
19 changed files with 418 additions and 126 deletions

View File

@ -3451,6 +3451,7 @@ Detached LUKS header
M: Hyman Huang <yong.huang@smartx.com>
S: Maintained
F: tests/qemu-iotests/tests/luks-detached-header
F: docs/devel/luks-detached-header.rst
D-Bus
M: Marc-André Lureau <marcandre.lureau@redhat.com>
@ -3484,7 +3485,7 @@ F: qapi/crypto.json
F: tests/unit/test-crypto-*
F: tests/bench/benchmark-crypto-*
F: tests/unit/crypto-tls-*
F: tests/unit/pkix_asn1_tab.c
F: tests/unit/pkix_asn1_tab.c.inc
F: qemu.sasl
Coroutines

View File

@ -33,6 +33,7 @@
#include "qapi/clone-visitor.h"
#include "qapi/qapi-visit-sockets.h"
#include "qemu/yank.h"
#include "trace.h"
#include "chardev/char-io.h"
#include "chardev/char-socket.h"
@ -126,6 +127,7 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
if (ret < 0 && errno != EAGAIN) {
if (tcp_chr_read_poll(chr) <= 0) {
/* Perform disconnect and return error. */
trace_chr_socket_poll_err(chr, chr->label);
tcp_chr_disconnect_locked(chr);
} /* else let the read handler finish it properly */
}
@ -279,15 +281,16 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
size_t i;
int *msgfds = NULL;
size_t msgfds_num = 0;
Error *err = NULL;
if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
ret = qio_channel_readv_full(s->ioc, &iov, 1,
&msgfds, &msgfds_num,
0, NULL);
0, &err);
} else {
ret = qio_channel_readv_full(s->ioc, &iov, 1,
NULL, NULL,
0, NULL);
0, &err);
}
if (msgfds_num) {
@ -322,7 +325,11 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
errno = EAGAIN;
ret = -1;
} else if (ret == -1) {
trace_chr_socket_recv_err(chr, chr->label, error_get_pretty(err));
error_free(err);
errno = EIO;
} else if (ret == 0) {
trace_chr_socket_recv_eof(chr, chr->label);
}
return ret;
@ -463,6 +470,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
trace_chr_socket_disconnect(chr, chr->label);
tcp_chr_free_connection(chr);
if (s->listener) {
@ -521,6 +529,7 @@ static gboolean tcp_chr_hup(QIOChannel *channel,
void *opaque)
{
Chardev *chr = CHARDEV(opaque);
trace_chr_socket_hangup(chr, chr->label);
tcp_chr_disconnect(chr);
return G_SOURCE_REMOVE;
}
@ -672,15 +681,18 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
SocketChardev *s = user_data;
Chardev *chr = CHARDEV(s);
TCPChardevTelnetInit *init = s->telnet_init;
Error *err = NULL;
ssize_t ret;
assert(init);
ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
ret = qio_channel_write(ioc, init->buf, init->buflen, &err);
if (ret < 0) {
if (ret == QIO_CHANNEL_ERR_BLOCK) {
ret = 0;
} else {
trace_chr_socket_write_err(chr, chr->label, error_get_pretty(err));
error_free(err);
tcp_chr_disconnect(chr);
goto end;
}
@ -765,9 +777,9 @@ static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
error_reportf_err(err,
"websock handshake of character device %s failed: ",
chr->label);
trace_chr_socket_ws_handshake_err(chr, chr->label,
error_get_pretty(err));
error_free(err);
tcp_chr_disconnect(chr);
} else {
if (s->do_telnetopt) {
@ -805,9 +817,9 @@ static void tcp_chr_tls_handshake(QIOTask *task,
Error *err = NULL;
if (qio_task_propagate_error(task, &err)) {
error_reportf_err(err,
"TLS handshake of character device %s failed: ",
chr->label);
trace_chr_socket_tls_handshake_err(chr, chr->label,
error_get_pretty(err));
error_free(err);
tcp_chr_disconnect(chr);
} else {
if (s->is_websock) {
@ -826,19 +838,22 @@ static void tcp_chr_tls_init(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
QIOChannelTLS *tioc;
gchar *name;
Error *err = NULL;
if (s->is_listen) {
tioc = qio_channel_tls_new_server(
s->ioc, s->tls_creds,
s->tls_authz,
NULL);
&err);
} else {
tioc = qio_channel_tls_new_client(
s->ioc, s->tls_creds,
s->addr->u.inet.host,
NULL);
&err);
}
if (tioc == NULL) {
trace_chr_socket_tls_init_err(chr, chr->label, error_get_pretty(err));
error_free(err);
tcp_chr_disconnect(chr);
return;
}

View File

@ -17,3 +17,13 @@ spice_vmc_register_interface(void *scd) "spice vmc registered interface %p"
spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p"
spice_vmc_event(int event) "spice vmc event %d"
# char-socket.c
chr_socket_poll_err(void *chrdev, const char *label) "chardev socket poll error %p (%s)"
chr_socket_recv_err(void *chrdev, const char *label, const char *err) "chardev socket recv error %p (%s): %s"
chr_socket_recv_eof(void *chrdev, const char *label) "chardev socket recv end-of-file %p (%s)"
chr_socket_write_err(void *chrdev, const char *label, const char *err) "chardev socket write error %p (%s): %s"
chr_socket_disconnect(void *chrdev, const char *label) "chardev socket disconnect %p (%s)"
chr_socket_hangup(void *chrdev, const char *label) "chardev socket hangup %p (%s)"
chr_socket_ws_handshake_err(void *chrdev, const char *label, const char *err) "chardev socket websock handshake error %p (%s): %s"
chr_socket_tls_handshake_err(void *chrdev, const char *label, const char *err) "chardev socket TLS handshake error %p (%s): %s"
chr_socket_tls_init_err(void *chrdev, const char *label, const char *err) "chardev socket TLS init error %p (%s): %s"

View File

@ -34,14 +34,11 @@
#include "crypto/random.h"
/* #define DEBUG_GNUTLS */
#ifdef DEBUG_GNUTLS
static void qcrypto_gnutls_log(int level, const char *str)
{
fprintf(stderr, "%d: %s", level, str);
}
#endif
/*
* To debug GNUTLS see env vars listed in
* https://gnutls.org/manual/html_node/Debugging-and-auditing.html
*/
int qcrypto_init(Error **errp)
{
#ifdef CONFIG_GNUTLS
@ -53,10 +50,6 @@ int qcrypto_init(Error **errp)
gnutls_strerror(ret));
return -1;
}
#ifdef DEBUG_GNUTLS
gnutls_global_set_log_level(10);
gnutls_global_set_log_function(qcrypto_gnutls_log);
#endif
#endif
#ifdef CONFIG_GCRYPT

View File

@ -44,6 +44,13 @@ struct QCryptoTLSSession {
QCryptoTLSSessionReadFunc readFunc;
void *opaque;
char *peername;
/*
* Allow concurrent reads and writes, so track
* errors separately
*/
Error *rerr;
Error *werr;
};
@ -54,6 +61,9 @@ qcrypto_tls_session_free(QCryptoTLSSession *session)
return;
}
error_free(session->rerr);
error_free(session->werr);
gnutls_deinit(session->handle);
g_free(session->hostname);
g_free(session->peername);
@ -67,13 +77,26 @@ static ssize_t
qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
{
QCryptoTLSSession *session = opaque;
ssize_t ret;
if (!session->writeFunc) {
errno = EIO;
return -1;
};
return session->writeFunc(buf, len, session->opaque);
error_free(session->werr);
session->werr = NULL;
ret = session->writeFunc(buf, len, session->opaque, &session->werr);
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
errno = EAGAIN;
return -1;
} else if (ret < 0) {
errno = EIO;
return -1;
} else {
return ret;
}
}
@ -81,13 +104,26 @@ static ssize_t
qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
{
QCryptoTLSSession *session = opaque;
ssize_t ret;
if (!session->readFunc) {
errno = EIO;
return -1;
};
return session->readFunc(buf, len, session->opaque);
error_free(session->rerr);
session->rerr = NULL;
ret = session->readFunc(buf, len, session->opaque, &session->rerr);
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
errno = EAGAIN;
return -1;
} else if (ret < 0) {
errno = EIO;
return -1;
} else {
return ret;
}
}
#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
@ -441,23 +477,25 @@ qcrypto_tls_session_set_callbacks(QCryptoTLSSession *session,
ssize_t
qcrypto_tls_session_write(QCryptoTLSSession *session,
const char *buf,
size_t len)
size_t len,
Error **errp)
{
ssize_t ret = gnutls_record_send(session->handle, buf, len);
if (ret < 0) {
switch (ret) {
case GNUTLS_E_AGAIN:
errno = EAGAIN;
break;
case GNUTLS_E_INTERRUPTED:
errno = EINTR;
break;
default:
errno = EIO;
break;
if (ret == GNUTLS_E_AGAIN) {
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else {
if (session->werr) {
error_propagate(errp, session->werr);
session->werr = NULL;
} else {
error_setg(errp,
"Cannot write to TLS channel: %s",
gnutls_strerror(ret));
}
return -1;
}
ret = -1;
}
return ret;
@ -467,26 +505,29 @@ qcrypto_tls_session_write(QCryptoTLSSession *session,
ssize_t
qcrypto_tls_session_read(QCryptoTLSSession *session,
char *buf,
size_t len)
size_t len,
bool gracefulTermination,
Error **errp)
{
ssize_t ret = gnutls_record_recv(session->handle, buf, len);
if (ret < 0) {
switch (ret) {
case GNUTLS_E_AGAIN:
errno = EAGAIN;
break;
case GNUTLS_E_INTERRUPTED:
errno = EINTR;
break;
case GNUTLS_E_PREMATURE_TERMINATION:
errno = ECONNABORTED;
break;
default:
errno = EIO;
break;
if (ret == GNUTLS_E_AGAIN) {
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else if ((ret == GNUTLS_E_PREMATURE_TERMINATION) &&
gracefulTermination){
return 0;
} else {
if (session->rerr) {
error_propagate(errp, session->rerr);
session->rerr = NULL;
} else {
error_setg(errp,
"Cannot read from TLS channel: %s",
gnutls_strerror(ret));
}
return -1;
}
ret = -1;
}
return ret;
@ -512,11 +553,21 @@ qcrypto_tls_session_handshake(QCryptoTLSSession *session,
ret == GNUTLS_E_AGAIN) {
ret = 1;
} else {
error_setg(errp, "TLS handshake failed: %s",
gnutls_strerror(ret));
if (session->rerr || session->werr) {
error_setg(errp, "TLS handshake failed: %s: %s",
gnutls_strerror(ret),
error_get_pretty(session->rerr ?
session->rerr : session->werr));
} else {
error_setg(errp, "TLS handshake failed: %s",
gnutls_strerror(ret));
}
ret = -1;
}
}
error_free(session->rerr);
error_free(session->werr);
session->rerr = session->werr = NULL;
return ret;
}
@ -605,9 +656,10 @@ qcrypto_tls_session_set_callbacks(
ssize_t
qcrypto_tls_session_write(QCryptoTLSSession *sess,
const char *buf,
size_t len)
size_t len,
Error **errp)
{
errno = -EIO;
error_setg(errp, "TLS requires GNUTLS support");
return -1;
}
@ -615,9 +667,11 @@ qcrypto_tls_session_write(QCryptoTLSSession *sess,
ssize_t
qcrypto_tls_session_read(QCryptoTLSSession *sess,
char *buf,
size_t len)
size_t len,
bool gracefulTermination,
Error **errp)
{
errno = -EIO;
error_setg(errp, "TLS requires GNUTLS support");
return -1;
}

10
docs/devel/crypto.rst Normal file
View File

@ -0,0 +1,10 @@
.. _crypto-ref:
====================
Cryptography in QEMU
====================
.. toctree::
:maxdepth: 2
luks-detached-header

View File

@ -20,3 +20,4 @@ Details about QEMU's various subsystems including how to add features to them.
vfio-iommufd
writing-monitor-commands
virtio-backends
crypto

View File

@ -0,0 +1,182 @@
================================
LUKS volume with detached header
================================
Introduction
============
This document gives an overview of the design of LUKS volume with detached
header and how to use it.
Background
==========
The LUKS format has ability to store the header in a separate volume from
the payload. We could extend the LUKS driver in QEMU to support this use
case.
Normally a LUKS volume has a layout:
::
+-----------------------------------------------+
| | | |
disk | header | key material | disk payload data |
| | | |
+-----------------------------------------------+
With a detached LUKS header, you need 2 disks so getting:
::
+--------------------------+
disk1 | header | key material |
+--------------------------+
+---------------------+
disk2 | disk payload data |
+---------------------+
There are a variety of benefits to doing this:
* Secrecy - the disk2 cannot be identified as containing LUKS
volume since there's no header
* Control - if access to the disk1 is restricted, then even
if someone has access to disk2 they can't unlock
it. Might be useful if you have disks on NFS but
want to restrict which host can launch a VM
instance from it, by dynamically providing access
to the header to a designated host
* Flexibility - your application data volume may be a given
size and it is inconvenient to resize it to
add encryption.You can store the LUKS header
separately and use the existing storage
volume for payload
* Recovery - corruption of a bit in the header may make the
entire payload inaccessible. It might be
convenient to take backups of the header. If
your primary disk header becomes corrupt, you
can unlock the data still by pointing to the
backup detached header
Architecture
============
Take the qcow2 encryption, for example. The architecture of the
LUKS volume with detached header is shown in the diagram below.
There are two children of the root node: a file and a header.
Data from the disk payload is stored in the file node. The
LUKS header and key material are located in the header node,
as previously mentioned.
::
+-----------------------------+
Root node | foo[luks] |
+-----------------------------+
| |
file | header |
| |
+---------------------+ +------------------+
Child node |payload-format[qcow2]| |header-format[raw]|
+---------------------+ +------------------+
| |
file | file |
| |
+----------------------+ +---------------------+
Child node |payload-protocol[file]| |header-protocol[file]|
+----------------------+ +---------------------+
| |
| |
| |
Host storage Host storage
Usage
=====
Create a LUKS disk with a detached header using qemu-img
--------------------------------------------------------
Shell commandline::
# qemu-img create --object secret,id=sec0,data=abc123 -f luks \
-o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0 \
-o detached-header=true test-header.img
# qemu-img create -f qcow2 test-payload.qcow2 200G
# qemu-img info 'json:{"driver":"luks","file":{"filename": \
"test-payload.img"},"header":{"filename":"test-header.img"}}'
Set up a VM's LUKS volume with a detached header
------------------------------------------------
Qemu commandline::
# qemu-system-x86_64 ... \
-object '{"qom-type":"secret","id":"libvirt-3-format-secret", \
"data":"abc123"}' \
-blockdev '{"driver":"file","filename":"/path/to/test-header.img", \
"node-name":"libvirt-1-storage"}' \
-blockdev '{"node-name":"libvirt-1-format","read-only":false, \
"driver":"raw","file":"libvirt-1-storage"}' \
-blockdev '{"driver":"file","filename":"/path/to/test-payload.qcow2", \
"node-name":"libvirt-2-storage"}' \
-blockdev '{"node-name":"libvirt-2-format","read-only":false, \
"driver":"qcow2","file":"libvirt-2-storage"}' \
-blockdev '{"node-name":"libvirt-3-format","driver":"luks", \
"file":"libvirt-2-format","header":"libvirt-1-format","key-secret": \
"libvirt-3-format-secret"}' \
-device '{"driver":"virtio-blk-pci","bus":XXX,"addr":YYY,"drive": \
"libvirt-3-format","id":"virtio-disk1"}'
Add LUKS volume to a VM with a detached header
----------------------------------------------
1. object-add the secret for decrypting the cipher stored in
LUKS header above::
# virsh qemu-monitor-command vm '{"execute":"object-add", \
"arguments":{"qom-type":"secret", "id": \
"libvirt-4-format-secret", "data":"abc123"}}'
2. block-add the protocol node for LUKS header::
# virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
"arguments":{"node-name":"libvirt-1-storage", "driver":"file", \
"filename": "/path/to/test-header.img" }}'
3. block-add the raw-drived node for LUKS header::
# virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
"arguments":{"node-name":"libvirt-1-format", "driver":"raw", \
"file":"libvirt-1-storage"}}'
4. block-add the protocol node for disk payload image::
# virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
"arguments":{"node-name":"libvirt-2-storage", "driver":"file", \
"filename":"/path/to/test-payload.qcow2"}}'
5. block-add the qcow2-drived format node for disk payload data::
# virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
"arguments":{"node-name":"libvirt-2-format", "driver":"qcow2", \
"file":"libvirt-2-storage"}}'
6. block-add the luks-drived format node to link the qcow2 disk
with the LUKS header by specifying the field "header"::
# virsh qemu-monitor-command vm '{"execute":"blockdev-add", \
"arguments":{"node-name":"libvirt-3-format", "driver":"luks", \
"file":"libvirt-2-format", "header":"libvirt-1-format", \
"key-secret":"libvirt-2-format-secret"}}'
7. hot-plug the virtio-blk device finally::
# virsh qemu-monitor-command vm '{"execute":"device_add", \
"arguments": {"driver":"virtio-blk-pci", \
"drive": "libvirt-3-format", "id":"virtio-disk2"}}
TODO
====
1. Support the shared detached LUKS header within the VM.

View File

@ -107,6 +107,7 @@
typedef struct QCryptoTLSSession QCryptoTLSSession;
#define QCRYPTO_TLS_SESSION_ERR_BLOCK -2
/**
* qcrypto_tls_session_new:
@ -177,12 +178,18 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
Error **errp);
/*
* 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,
size_t len,
void *opaque);
void *opaque,
Error **errp);
typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
size_t len,
void *opaque);
void *opaque,
Error **errp);
/**
* qcrypto_tls_session_set_callbacks:
@ -212,6 +219,7 @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
* @sess: the TLS session object
* @buf: the plain text to send
* @len: the length of @buf
* @errp: pointer to hold returned error object
*
* Encrypt @len bytes of the data in @buf and send
* it to the remote peer using the callback previously
@ -221,32 +229,45 @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
* qcrypto_tls_session_get_handshake_status() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
* Returns: the number of bytes sent, or -1 on error
* Returns: the number of bytes sent,
* or QCRYPTO_TLS_SESSION_ERR_BLOCK if the write would block,
* or -1 on error.
*/
ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
const char *buf,
size_t len);
size_t len,
Error **errp);
/**
* qcrypto_tls_session_read:
* @sess: the TLS session object
* @buf: to fill with plain text received
* @len: the length of @buf
* @gracefulTermination: treat premature termination as graceful EOF
* @errp: pointer to hold returned error object
*
* Receive up to @len bytes of data from the remote peer
* using the callback previously registered with
* qcrypto_tls_session_set_callbacks(), decrypt it and
* store it in @buf.
*
* If @gracefulTermination is true, then a premature termination
* of the TLS session will be treated as indicating EOF, as
* opposed to an error.
*
* It is an error to call this before
* qcrypto_tls_session_get_handshake_status() returns
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
*
* Returns: the number of bytes received, or -1 on error
* Returns: the number of bytes received,
* or QCRYPTO_TLS_SESSION_ERR_BLOCK if the receive would block,
* or -1 on error.
*/
ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
char *buf,
size_t len);
size_t len,
bool gracefulTermination,
Error **errp);
/**
* qcrypto_tls_session_check_pending:

View File

@ -28,17 +28,16 @@
static ssize_t qio_channel_tls_write_handler(const char *buf,
size_t len,
void *opaque)
void *opaque,
Error **errp)
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
ssize_t ret;
ret = qio_channel_write(tioc->master, buf, len, NULL);
ret = qio_channel_write(tioc->master, buf, len, errp);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
errno = EAGAIN;
return -1;
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else if (ret < 0) {
errno = EIO;
return -1;
}
return ret;
@ -46,17 +45,16 @@ static ssize_t qio_channel_tls_write_handler(const char *buf,
static ssize_t qio_channel_tls_read_handler(char *buf,
size_t len,
void *opaque)
void *opaque,
Error **errp)
{
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
ssize_t ret;
ret = qio_channel_read(tioc->master, buf, len, NULL);
ret = qio_channel_read(tioc->master, buf, len, errp);
if (ret == QIO_CHANNEL_ERR_BLOCK) {
errno = EAGAIN;
return -1;
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else if (ret < 0) {
errno = EIO;
return -1;
}
return ret;
@ -277,24 +275,19 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
ssize_t got = 0;
for (i = 0 ; i < niov ; i++) {
ssize_t ret = qcrypto_tls_session_read(tioc->session,
iov[i].iov_base,
iov[i].iov_len);
if (ret < 0) {
if (errno == EAGAIN) {
if (got) {
return got;
} else {
return QIO_CHANNEL_ERR_BLOCK;
}
} else if (errno == ECONNABORTED &&
(qatomic_load_acquire(&tioc->shutdown) &
QIO_CHANNEL_SHUTDOWN_READ)) {
return 0;
ssize_t ret = qcrypto_tls_session_read(
tioc->session,
iov[i].iov_base,
iov[i].iov_len,
qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
errp);
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
if (got) {
return got;
} else {
return QIO_CHANNEL_ERR_BLOCK;
}
error_setg_errno(errp, errno,
"Cannot read from TLS channel");
} else if (ret < 0) {
return -1;
}
got += ret;
@ -321,18 +314,15 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
for (i = 0 ; i < niov ; i++) {
ssize_t ret = qcrypto_tls_session_write(tioc->session,
iov[i].iov_base,
iov[i].iov_len);
if (ret <= 0) {
if (errno == EAGAIN) {
if (done) {
return done;
} else {
return QIO_CHANNEL_ERR_BLOCK;
}
iov[i].iov_len,
errp);
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
if (done) {
return done;
} else {
return QIO_CHANNEL_ERR_BLOCK;
}
error_setg_errno(errp, errno,
"Cannot write to TLS channel");
} else if (ret < 0) {
return -1;
}
done += ret;

View File

@ -1696,7 +1696,6 @@ endif
if not gnutls_crypto.found()
if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
gcrypt = dependency('libgcrypt', version: '>=1.8',
method: 'config-tool',
required: get_option('gcrypt'))
# Debian has removed -lgpg-error from libgcrypt-config
# as it "spreads unnecessary dependencies" which in
@ -1979,6 +1978,7 @@ endif
tasn1 = not_found
if gnutls.found()
tasn1 = dependency('libtasn1',
required: false,
method: 'pkg-config')
endif
keyutils = not_found
@ -3343,6 +3343,7 @@ if have_block
trace_events_subdirs += [
'authz',
'block',
'chardev',
'io',
'nbd',
'scsi',
@ -3354,7 +3355,6 @@ if have_system
'audio',
'backends',
'backends/tpm',
'chardev',
'ebpf',
'hw/9pfs',
'hw/acpi',

View File

@ -226,8 +226,6 @@
# @iter-time: number of milliseconds to spend in PBKDF passphrase
# processing. Currently defaults to 2000. (since 2.8)
#
# @detached-header: create a detached LUKS header. (since 9.0)
#
# Since: 2.6
##
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
@ -237,8 +235,7 @@
'*ivgen-alg': 'QCryptoIVGenAlgorithm',
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
'*hash-alg': 'QCryptoHashAlgorithm',
'*iter-time': 'int',
'*detached-header': 'bool'}}
'*iter-time': 'int' }}
##
# @QCryptoBlockOpenOptions:

View File

@ -322,8 +322,7 @@ if gnutls.found()
migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls]
if tasn1.found()
migration_files += [files('../unit/crypto-tls-x509-helpers.c',
'../unit/pkix_asn1_tab.c'), tasn1]
migration_files += [files('../unit/crypto-tls-x509-helpers.c'), tasn1]
endif
endif

View File

@ -20,7 +20,6 @@
#include "qemu/osdep.h"
#include "crypto-tls-x509-helpers.h"
#include "crypto-tls-psk-helpers.h"
#include "qemu/sockets.h"

View File

@ -20,15 +20,19 @@
#include "qemu/osdep.h"
#include <libtasn1.h>
#include "crypto-tls-x509-helpers.h"
#include "crypto/init.h"
#include "qemu/sockets.h"
#include "pkix_asn1_tab.c.inc"
/*
* This stores some static data that is needed when
* encoding extensions in the x509 certs
*/
asn1_node pkix_asn1;
static asn1_node pkix_asn1;
/*
* To avoid consuming random entropy to generate keys,

View File

@ -23,7 +23,6 @@
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <libtasn1.h>
#define QCRYPTO_TLS_TEST_CLIENT_NAME "ACME QEMU Client"
@ -171,6 +170,4 @@ void test_tls_cleanup(const char *keyfile);
}; \
test_tls_generate_cert(&varname, cavarname.crt)
extern const asn1_static_node pkix_asn1_tab[];
#endif

View File

@ -99,11 +99,11 @@ if have_block
tasn1.found() and \
host_os != 'windows'
tests += {
'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c',
'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c',
tasn1, crypto, gnutls],
'test-crypto-tlssession': ['crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c', 'crypto-tls-psk-helpers.c',
'test-crypto-tlssession': ['crypto-tls-x509-helpers.c', 'crypto-tls-psk-helpers.c',
tasn1, crypto, gnutls],
'test-io-channel-tls': ['io-channel-helpers.c', 'crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c',
'test-io-channel-tls': ['io-channel-helpers.c', 'crypto-tls-x509-helpers.c',
tasn1, io, crypto, gnutls]}
endif
if pam.found()

View File

@ -3,10 +3,7 @@
* and is under copyright of various GNUTLS contributors.
*/
#include "qemu/osdep.h"
#include "crypto-tls-x509-helpers.h"
const asn1_static_node pkix_asn1_tab[] = {
static const asn1_static_node pkix_asn1_tab[] = {
{"PKIX1", 536875024, 0},
{0, 1073741836, 0},
{"id-ce", 1879048204, 0},

View File

@ -35,18 +35,40 @@
#define PSKFILE WORKDIR "keys.psk"
#define KEYFILE WORKDIR "key-ctx.pem"
static ssize_t testWrite(const char *buf, size_t len, void *opaque)
static ssize_t
testWrite(const char *buf, size_t len, void *opaque, Error **errp)
{
int *fd = opaque;
int ret;
return write(*fd, buf, len);
ret = write(*fd, buf, len);
if (ret < 0) {
if (errno == EAGAIN) {
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else {
error_setg_errno(errp, errno, "unable to write");
return -1;
}
}
return ret;
}
static ssize_t testRead(char *buf, size_t len, void *opaque)
static ssize_t
testRead(char *buf, size_t len, void *opaque, Error **errp)
{
int *fd = opaque;
int ret;
return read(*fd, buf, len);
ret = read(*fd, buf, len);
if (ret < 0) {
if (errno == EAGAIN) {
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
} else {
error_setg_errno(errp, errno, "unable to read");
return -1;
}
}
return ret;
}
static QCryptoTLSCreds *test_tls_creds_psk_create(