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:
commit
9726687f2f
@ -3451,6 +3451,7 @@ Detached LUKS header
|
|||||||
M: Hyman Huang <yong.huang@smartx.com>
|
M: Hyman Huang <yong.huang@smartx.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: tests/qemu-iotests/tests/luks-detached-header
|
F: tests/qemu-iotests/tests/luks-detached-header
|
||||||
|
F: docs/devel/luks-detached-header.rst
|
||||||
|
|
||||||
D-Bus
|
D-Bus
|
||||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||||
@ -3484,7 +3485,7 @@ F: qapi/crypto.json
|
|||||||
F: tests/unit/test-crypto-*
|
F: tests/unit/test-crypto-*
|
||||||
F: tests/bench/benchmark-crypto-*
|
F: tests/bench/benchmark-crypto-*
|
||||||
F: tests/unit/crypto-tls-*
|
F: tests/unit/crypto-tls-*
|
||||||
F: tests/unit/pkix_asn1_tab.c
|
F: tests/unit/pkix_asn1_tab.c.inc
|
||||||
F: qemu.sasl
|
F: qemu.sasl
|
||||||
|
|
||||||
Coroutines
|
Coroutines
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "qapi/clone-visitor.h"
|
#include "qapi/clone-visitor.h"
|
||||||
#include "qapi/qapi-visit-sockets.h"
|
#include "qapi/qapi-visit-sockets.h"
|
||||||
#include "qemu/yank.h"
|
#include "qemu/yank.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
#include "chardev/char-io.h"
|
#include "chardev/char-io.h"
|
||||||
#include "chardev/char-socket.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 (ret < 0 && errno != EAGAIN) {
|
||||||
if (tcp_chr_read_poll(chr) <= 0) {
|
if (tcp_chr_read_poll(chr) <= 0) {
|
||||||
/* Perform disconnect and return error. */
|
/* Perform disconnect and return error. */
|
||||||
|
trace_chr_socket_poll_err(chr, chr->label);
|
||||||
tcp_chr_disconnect_locked(chr);
|
tcp_chr_disconnect_locked(chr);
|
||||||
} /* else let the read handler finish it properly */
|
} /* 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;
|
size_t i;
|
||||||
int *msgfds = NULL;
|
int *msgfds = NULL;
|
||||||
size_t msgfds_num = 0;
|
size_t msgfds_num = 0;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
|
if (qio_channel_has_feature(s->ioc, QIO_CHANNEL_FEATURE_FD_PASS)) {
|
||||||
ret = qio_channel_readv_full(s->ioc, &iov, 1,
|
ret = qio_channel_readv_full(s->ioc, &iov, 1,
|
||||||
&msgfds, &msgfds_num,
|
&msgfds, &msgfds_num,
|
||||||
0, NULL);
|
0, &err);
|
||||||
} else {
|
} else {
|
||||||
ret = qio_channel_readv_full(s->ioc, &iov, 1,
|
ret = qio_channel_readv_full(s->ioc, &iov, 1,
|
||||||
NULL, NULL,
|
NULL, NULL,
|
||||||
0, NULL);
|
0, &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msgfds_num) {
|
if (msgfds_num) {
|
||||||
@ -322,7 +325,11 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, size_t len)
|
|||||||
errno = EAGAIN;
|
errno = EAGAIN;
|
||||||
ret = -1;
|
ret = -1;
|
||||||
} else if (ret == -1) {
|
} else if (ret == -1) {
|
||||||
|
trace_chr_socket_recv_err(chr, chr->label, error_get_pretty(err));
|
||||||
|
error_free(err);
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
|
} else if (ret == 0) {
|
||||||
|
trace_chr_socket_recv_eof(chr, chr->label);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -463,6 +470,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
|
|||||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||||
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
|
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
|
||||||
|
|
||||||
|
trace_chr_socket_disconnect(chr, chr->label);
|
||||||
tcp_chr_free_connection(chr);
|
tcp_chr_free_connection(chr);
|
||||||
|
|
||||||
if (s->listener) {
|
if (s->listener) {
|
||||||
@ -521,6 +529,7 @@ static gboolean tcp_chr_hup(QIOChannel *channel,
|
|||||||
void *opaque)
|
void *opaque)
|
||||||
{
|
{
|
||||||
Chardev *chr = CHARDEV(opaque);
|
Chardev *chr = CHARDEV(opaque);
|
||||||
|
trace_chr_socket_hangup(chr, chr->label);
|
||||||
tcp_chr_disconnect(chr);
|
tcp_chr_disconnect(chr);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
@ -672,15 +681,18 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
|
|||||||
SocketChardev *s = user_data;
|
SocketChardev *s = user_data;
|
||||||
Chardev *chr = CHARDEV(s);
|
Chardev *chr = CHARDEV(s);
|
||||||
TCPChardevTelnetInit *init = s->telnet_init;
|
TCPChardevTelnetInit *init = s->telnet_init;
|
||||||
|
Error *err = NULL;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
assert(init);
|
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 < 0) {
|
||||||
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
|
trace_chr_socket_write_err(chr, chr->label, error_get_pretty(err));
|
||||||
|
error_free(err);
|
||||||
tcp_chr_disconnect(chr);
|
tcp_chr_disconnect(chr);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@ -765,9 +777,9 @@ static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
|
|||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
if (qio_task_propagate_error(task, &err)) {
|
if (qio_task_propagate_error(task, &err)) {
|
||||||
error_reportf_err(err,
|
trace_chr_socket_ws_handshake_err(chr, chr->label,
|
||||||
"websock handshake of character device %s failed: ",
|
error_get_pretty(err));
|
||||||
chr->label);
|
error_free(err);
|
||||||
tcp_chr_disconnect(chr);
|
tcp_chr_disconnect(chr);
|
||||||
} else {
|
} else {
|
||||||
if (s->do_telnetopt) {
|
if (s->do_telnetopt) {
|
||||||
@ -805,9 +817,9 @@ static void tcp_chr_tls_handshake(QIOTask *task,
|
|||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
if (qio_task_propagate_error(task, &err)) {
|
if (qio_task_propagate_error(task, &err)) {
|
||||||
error_reportf_err(err,
|
trace_chr_socket_tls_handshake_err(chr, chr->label,
|
||||||
"TLS handshake of character device %s failed: ",
|
error_get_pretty(err));
|
||||||
chr->label);
|
error_free(err);
|
||||||
tcp_chr_disconnect(chr);
|
tcp_chr_disconnect(chr);
|
||||||
} else {
|
} else {
|
||||||
if (s->is_websock) {
|
if (s->is_websock) {
|
||||||
@ -826,19 +838,22 @@ static void tcp_chr_tls_init(Chardev *chr)
|
|||||||
SocketChardev *s = SOCKET_CHARDEV(chr);
|
SocketChardev *s = SOCKET_CHARDEV(chr);
|
||||||
QIOChannelTLS *tioc;
|
QIOChannelTLS *tioc;
|
||||||
gchar *name;
|
gchar *name;
|
||||||
|
Error *err = NULL;
|
||||||
|
|
||||||
if (s->is_listen) {
|
if (s->is_listen) {
|
||||||
tioc = qio_channel_tls_new_server(
|
tioc = qio_channel_tls_new_server(
|
||||||
s->ioc, s->tls_creds,
|
s->ioc, s->tls_creds,
|
||||||
s->tls_authz,
|
s->tls_authz,
|
||||||
NULL);
|
&err);
|
||||||
} else {
|
} else {
|
||||||
tioc = qio_channel_tls_new_client(
|
tioc = qio_channel_tls_new_client(
|
||||||
s->ioc, s->tls_creds,
|
s->ioc, s->tls_creds,
|
||||||
s->addr->u.inet.host,
|
s->addr->u.inet.host,
|
||||||
NULL);
|
&err);
|
||||||
}
|
}
|
||||||
if (tioc == NULL) {
|
if (tioc == NULL) {
|
||||||
|
trace_chr_socket_tls_init_err(chr, chr->label, error_get_pretty(err));
|
||||||
|
error_free(err);
|
||||||
tcp_chr_disconnect(chr);
|
tcp_chr_disconnect(chr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -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_unregister_interface(void *scd) "spice vmc unregistered interface %p"
|
||||||
spice_vmc_event(int event) "spice vmc event %d"
|
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"
|
||||||
|
@ -34,14 +34,11 @@
|
|||||||
|
|
||||||
#include "crypto/random.h"
|
#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)
|
int qcrypto_init(Error **errp)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_GNUTLS
|
#ifdef CONFIG_GNUTLS
|
||||||
@ -53,10 +50,6 @@ int qcrypto_init(Error **errp)
|
|||||||
gnutls_strerror(ret));
|
gnutls_strerror(ret));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_GNUTLS
|
|
||||||
gnutls_global_set_log_level(10);
|
|
||||||
gnutls_global_set_log_function(qcrypto_gnutls_log);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_GCRYPT
|
#ifdef CONFIG_GCRYPT
|
||||||
|
@ -44,6 +44,13 @@ struct QCryptoTLSSession {
|
|||||||
QCryptoTLSSessionReadFunc readFunc;
|
QCryptoTLSSessionReadFunc readFunc;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
char *peername;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error_free(session->rerr);
|
||||||
|
error_free(session->werr);
|
||||||
|
|
||||||
gnutls_deinit(session->handle);
|
gnutls_deinit(session->handle);
|
||||||
g_free(session->hostname);
|
g_free(session->hostname);
|
||||||
g_free(session->peername);
|
g_free(session->peername);
|
||||||
@ -67,13 +77,26 @@ static ssize_t
|
|||||||
qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
|
qcrypto_tls_session_push(void *opaque, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
QCryptoTLSSession *session = opaque;
|
QCryptoTLSSession *session = opaque;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
if (!session->writeFunc) {
|
if (!session->writeFunc) {
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
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)
|
qcrypto_tls_session_pull(void *opaque, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
QCryptoTLSSession *session = opaque;
|
QCryptoTLSSession *session = opaque;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
if (!session->readFunc) {
|
if (!session->readFunc) {
|
||||||
errno = EIO;
|
errno = EIO;
|
||||||
return -1;
|
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"
|
#define TLS_PRIORITY_ADDITIONAL_ANON "+ANON-DH"
|
||||||
@ -441,23 +477,25 @@ qcrypto_tls_session_set_callbacks(QCryptoTLSSession *session,
|
|||||||
ssize_t
|
ssize_t
|
||||||
qcrypto_tls_session_write(QCryptoTLSSession *session,
|
qcrypto_tls_session_write(QCryptoTLSSession *session,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
size_t len)
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
ssize_t ret = gnutls_record_send(session->handle, buf, len);
|
ssize_t ret = gnutls_record_send(session->handle, buf, len);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
switch (ret) {
|
if (ret == GNUTLS_E_AGAIN) {
|
||||||
case GNUTLS_E_AGAIN:
|
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
|
||||||
errno = EAGAIN;
|
} else {
|
||||||
break;
|
if (session->werr) {
|
||||||
case GNUTLS_E_INTERRUPTED:
|
error_propagate(errp, session->werr);
|
||||||
errno = EINTR;
|
session->werr = NULL;
|
||||||
break;
|
} else {
|
||||||
default:
|
error_setg(errp,
|
||||||
errno = EIO;
|
"Cannot write to TLS channel: %s",
|
||||||
break;
|
gnutls_strerror(ret));
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
ret = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -467,26 +505,29 @@ qcrypto_tls_session_write(QCryptoTLSSession *session,
|
|||||||
ssize_t
|
ssize_t
|
||||||
qcrypto_tls_session_read(QCryptoTLSSession *session,
|
qcrypto_tls_session_read(QCryptoTLSSession *session,
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t len)
|
size_t len,
|
||||||
|
bool gracefulTermination,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
ssize_t ret = gnutls_record_recv(session->handle, buf, len);
|
ssize_t ret = gnutls_record_recv(session->handle, buf, len);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
switch (ret) {
|
if (ret == GNUTLS_E_AGAIN) {
|
||||||
case GNUTLS_E_AGAIN:
|
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
|
||||||
errno = EAGAIN;
|
} else if ((ret == GNUTLS_E_PREMATURE_TERMINATION) &&
|
||||||
break;
|
gracefulTermination){
|
||||||
case GNUTLS_E_INTERRUPTED:
|
return 0;
|
||||||
errno = EINTR;
|
} else {
|
||||||
break;
|
if (session->rerr) {
|
||||||
case GNUTLS_E_PREMATURE_TERMINATION:
|
error_propagate(errp, session->rerr);
|
||||||
errno = ECONNABORTED;
|
session->rerr = NULL;
|
||||||
break;
|
} else {
|
||||||
default:
|
error_setg(errp,
|
||||||
errno = EIO;
|
"Cannot read from TLS channel: %s",
|
||||||
break;
|
gnutls_strerror(ret));
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
ret = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -512,11 +553,21 @@ qcrypto_tls_session_handshake(QCryptoTLSSession *session,
|
|||||||
ret == GNUTLS_E_AGAIN) {
|
ret == GNUTLS_E_AGAIN) {
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
error_setg(errp, "TLS handshake failed: %s",
|
if (session->rerr || session->werr) {
|
||||||
gnutls_strerror(ret));
|
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;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
error_free(session->rerr);
|
||||||
|
error_free(session->werr);
|
||||||
|
session->rerr = session->werr = NULL;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -605,9 +656,10 @@ qcrypto_tls_session_set_callbacks(
|
|||||||
ssize_t
|
ssize_t
|
||||||
qcrypto_tls_session_write(QCryptoTLSSession *sess,
|
qcrypto_tls_session_write(QCryptoTLSSession *sess,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
size_t len)
|
size_t len,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
errno = -EIO;
|
error_setg(errp, "TLS requires GNUTLS support");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,9 +667,11 @@ qcrypto_tls_session_write(QCryptoTLSSession *sess,
|
|||||||
ssize_t
|
ssize_t
|
||||||
qcrypto_tls_session_read(QCryptoTLSSession *sess,
|
qcrypto_tls_session_read(QCryptoTLSSession *sess,
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t len)
|
size_t len,
|
||||||
|
bool gracefulTermination,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
errno = -EIO;
|
error_setg(errp, "TLS requires GNUTLS support");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
docs/devel/crypto.rst
Normal file
10
docs/devel/crypto.rst
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.. _crypto-ref:
|
||||||
|
|
||||||
|
====================
|
||||||
|
Cryptography in QEMU
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
luks-detached-header
|
@ -20,3 +20,4 @@ Details about QEMU's various subsystems including how to add features to them.
|
|||||||
vfio-iommufd
|
vfio-iommufd
|
||||||
writing-monitor-commands
|
writing-monitor-commands
|
||||||
virtio-backends
|
virtio-backends
|
||||||
|
crypto
|
||||||
|
182
docs/devel/luks-detached-header.rst
Normal file
182
docs/devel/luks-detached-header.rst
Normal 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.
|
@ -107,6 +107,7 @@
|
|||||||
|
|
||||||
typedef struct QCryptoTLSSession QCryptoTLSSession;
|
typedef struct QCryptoTLSSession QCryptoTLSSession;
|
||||||
|
|
||||||
|
#define QCRYPTO_TLS_SESSION_ERR_BLOCK -2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_tls_session_new:
|
* 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,
|
int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
|
||||||
Error **errp);
|
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,
|
typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
void *opaque);
|
void *opaque,
|
||||||
|
Error **errp);
|
||||||
typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
|
typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
void *opaque);
|
void *opaque,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_tls_session_set_callbacks:
|
* qcrypto_tls_session_set_callbacks:
|
||||||
@ -212,6 +219,7 @@ void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
|
|||||||
* @sess: the TLS session object
|
* @sess: the TLS session object
|
||||||
* @buf: the plain text to send
|
* @buf: the plain text to send
|
||||||
* @len: the length of @buf
|
* @len: the length of @buf
|
||||||
|
* @errp: pointer to hold returned error object
|
||||||
*
|
*
|
||||||
* Encrypt @len bytes of the data in @buf and send
|
* Encrypt @len bytes of the data in @buf and send
|
||||||
* it to the remote peer using the callback previously
|
* 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_session_get_handshake_status() returns
|
||||||
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
|
* 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,
|
ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
|
||||||
const char *buf,
|
const char *buf,
|
||||||
size_t len);
|
size_t len,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_tls_session_read:
|
* qcrypto_tls_session_read:
|
||||||
* @sess: the TLS session object
|
* @sess: the TLS session object
|
||||||
* @buf: to fill with plain text received
|
* @buf: to fill with plain text received
|
||||||
* @len: the length of @buf
|
* @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
|
* Receive up to @len bytes of data from the remote peer
|
||||||
* using the callback previously registered with
|
* using the callback previously registered with
|
||||||
* qcrypto_tls_session_set_callbacks(), decrypt it and
|
* qcrypto_tls_session_set_callbacks(), decrypt it and
|
||||||
* store it in @buf.
|
* 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
|
* It is an error to call this before
|
||||||
* qcrypto_tls_session_get_handshake_status() returns
|
* qcrypto_tls_session_get_handshake_status() returns
|
||||||
* QCRYPTO_TLS_HANDSHAKE_COMPLETE
|
* 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,
|
ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
|
||||||
char *buf,
|
char *buf,
|
||||||
size_t len);
|
size_t len,
|
||||||
|
bool gracefulTermination,
|
||||||
|
Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qcrypto_tls_session_check_pending:
|
* qcrypto_tls_session_check_pending:
|
||||||
|
@ -28,17 +28,16 @@
|
|||||||
|
|
||||||
static ssize_t qio_channel_tls_write_handler(const char *buf,
|
static ssize_t qio_channel_tls_write_handler(const char *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
void *opaque)
|
void *opaque,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
|
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
|
||||||
ssize_t ret;
|
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) {
|
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||||
errno = EAGAIN;
|
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
|
||||||
return -1;
|
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
errno = EIO;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ret;
|
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,
|
static ssize_t qio_channel_tls_read_handler(char *buf,
|
||||||
size_t len,
|
size_t len,
|
||||||
void *opaque)
|
void *opaque,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
|
QIOChannelTLS *tioc = QIO_CHANNEL_TLS(opaque);
|
||||||
ssize_t ret;
|
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) {
|
if (ret == QIO_CHANNEL_ERR_BLOCK) {
|
||||||
errno = EAGAIN;
|
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
|
||||||
return -1;
|
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
errno = EIO;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -277,24 +275,19 @@ static ssize_t qio_channel_tls_readv(QIOChannel *ioc,
|
|||||||
ssize_t got = 0;
|
ssize_t got = 0;
|
||||||
|
|
||||||
for (i = 0 ; i < niov ; i++) {
|
for (i = 0 ; i < niov ; i++) {
|
||||||
ssize_t ret = qcrypto_tls_session_read(tioc->session,
|
ssize_t ret = qcrypto_tls_session_read(
|
||||||
iov[i].iov_base,
|
tioc->session,
|
||||||
iov[i].iov_len);
|
iov[i].iov_base,
|
||||||
if (ret < 0) {
|
iov[i].iov_len,
|
||||||
if (errno == EAGAIN) {
|
qatomic_load_acquire(&tioc->shutdown) & QIO_CHANNEL_SHUTDOWN_READ,
|
||||||
if (got) {
|
errp);
|
||||||
return got;
|
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
|
||||||
} else {
|
if (got) {
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return got;
|
||||||
}
|
} else {
|
||||||
} else if (errno == ECONNABORTED &&
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
(qatomic_load_acquire(&tioc->shutdown) &
|
|
||||||
QIO_CHANNEL_SHUTDOWN_READ)) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
} else if (ret < 0) {
|
||||||
error_setg_errno(errp, errno,
|
|
||||||
"Cannot read from TLS channel");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
got += ret;
|
got += ret;
|
||||||
@ -321,18 +314,15 @@ static ssize_t qio_channel_tls_writev(QIOChannel *ioc,
|
|||||||
for (i = 0 ; i < niov ; i++) {
|
for (i = 0 ; i < niov ; i++) {
|
||||||
ssize_t ret = qcrypto_tls_session_write(tioc->session,
|
ssize_t ret = qcrypto_tls_session_write(tioc->session,
|
||||||
iov[i].iov_base,
|
iov[i].iov_base,
|
||||||
iov[i].iov_len);
|
iov[i].iov_len,
|
||||||
if (ret <= 0) {
|
errp);
|
||||||
if (errno == EAGAIN) {
|
if (ret == QCRYPTO_TLS_SESSION_ERR_BLOCK) {
|
||||||
if (done) {
|
if (done) {
|
||||||
return done;
|
return done;
|
||||||
} else {
|
} else {
|
||||||
return QIO_CHANNEL_ERR_BLOCK;
|
return QIO_CHANNEL_ERR_BLOCK;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (ret < 0) {
|
||||||
error_setg_errno(errp, errno,
|
|
||||||
"Cannot write to TLS channel");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
done += ret;
|
done += ret;
|
||||||
|
@ -1696,7 +1696,6 @@ endif
|
|||||||
if not gnutls_crypto.found()
|
if not gnutls_crypto.found()
|
||||||
if (not get_option('gcrypt').auto() or have_system) and not get_option('nettle').enabled()
|
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.8',
|
||||||
method: 'config-tool',
|
|
||||||
required: get_option('gcrypt'))
|
required: get_option('gcrypt'))
|
||||||
# Debian has removed -lgpg-error from libgcrypt-config
|
# Debian has removed -lgpg-error from libgcrypt-config
|
||||||
# as it "spreads unnecessary dependencies" which in
|
# as it "spreads unnecessary dependencies" which in
|
||||||
@ -1979,6 +1978,7 @@ endif
|
|||||||
tasn1 = not_found
|
tasn1 = not_found
|
||||||
if gnutls.found()
|
if gnutls.found()
|
||||||
tasn1 = dependency('libtasn1',
|
tasn1 = dependency('libtasn1',
|
||||||
|
required: false,
|
||||||
method: 'pkg-config')
|
method: 'pkg-config')
|
||||||
endif
|
endif
|
||||||
keyutils = not_found
|
keyutils = not_found
|
||||||
@ -3343,6 +3343,7 @@ if have_block
|
|||||||
trace_events_subdirs += [
|
trace_events_subdirs += [
|
||||||
'authz',
|
'authz',
|
||||||
'block',
|
'block',
|
||||||
|
'chardev',
|
||||||
'io',
|
'io',
|
||||||
'nbd',
|
'nbd',
|
||||||
'scsi',
|
'scsi',
|
||||||
@ -3354,7 +3355,6 @@ if have_system
|
|||||||
'audio',
|
'audio',
|
||||||
'backends',
|
'backends',
|
||||||
'backends/tpm',
|
'backends/tpm',
|
||||||
'chardev',
|
|
||||||
'ebpf',
|
'ebpf',
|
||||||
'hw/9pfs',
|
'hw/9pfs',
|
||||||
'hw/acpi',
|
'hw/acpi',
|
||||||
|
@ -226,8 +226,6 @@
|
|||||||
# @iter-time: number of milliseconds to spend in PBKDF passphrase
|
# @iter-time: number of milliseconds to spend in PBKDF passphrase
|
||||||
# processing. Currently defaults to 2000. (since 2.8)
|
# processing. Currently defaults to 2000. (since 2.8)
|
||||||
#
|
#
|
||||||
# @detached-header: create a detached LUKS header. (since 9.0)
|
|
||||||
#
|
|
||||||
# Since: 2.6
|
# Since: 2.6
|
||||||
##
|
##
|
||||||
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
|
{ 'struct': 'QCryptoBlockCreateOptionsLUKS',
|
||||||
@ -237,8 +235,7 @@
|
|||||||
'*ivgen-alg': 'QCryptoIVGenAlgorithm',
|
'*ivgen-alg': 'QCryptoIVGenAlgorithm',
|
||||||
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
|
'*ivgen-hash-alg': 'QCryptoHashAlgorithm',
|
||||||
'*hash-alg': 'QCryptoHashAlgorithm',
|
'*hash-alg': 'QCryptoHashAlgorithm',
|
||||||
'*iter-time': 'int',
|
'*iter-time': 'int' }}
|
||||||
'*detached-header': 'bool'}}
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# @QCryptoBlockOpenOptions:
|
# @QCryptoBlockOpenOptions:
|
||||||
|
@ -322,8 +322,7 @@ if gnutls.found()
|
|||||||
migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls]
|
migration_files += [files('../unit/crypto-tls-psk-helpers.c'), gnutls]
|
||||||
|
|
||||||
if tasn1.found()
|
if tasn1.found()
|
||||||
migration_files += [files('../unit/crypto-tls-x509-helpers.c',
|
migration_files += [files('../unit/crypto-tls-x509-helpers.c'), tasn1]
|
||||||
'../unit/pkix_asn1_tab.c'), tasn1]
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
#include "crypto-tls-x509-helpers.h"
|
|
||||||
#include "crypto-tls-psk-helpers.h"
|
#include "crypto-tls-psk-helpers.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
|
|
||||||
|
@ -20,15 +20,19 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#include <libtasn1.h>
|
||||||
|
|
||||||
#include "crypto-tls-x509-helpers.h"
|
#include "crypto-tls-x509-helpers.h"
|
||||||
#include "crypto/init.h"
|
#include "crypto/init.h"
|
||||||
#include "qemu/sockets.h"
|
#include "qemu/sockets.h"
|
||||||
|
|
||||||
|
#include "pkix_asn1_tab.c.inc"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This stores some static data that is needed when
|
* This stores some static data that is needed when
|
||||||
* encoding extensions in the x509 certs
|
* encoding extensions in the x509 certs
|
||||||
*/
|
*/
|
||||||
asn1_node pkix_asn1;
|
static asn1_node pkix_asn1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* To avoid consuming random entropy to generate keys,
|
* To avoid consuming random entropy to generate keys,
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <gnutls/gnutls.h>
|
#include <gnutls/gnutls.h>
|
||||||
#include <gnutls/x509.h>
|
#include <gnutls/x509.h>
|
||||||
#include <libtasn1.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define QCRYPTO_TLS_TEST_CLIENT_NAME "ACME QEMU Client"
|
#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)
|
test_tls_generate_cert(&varname, cavarname.crt)
|
||||||
|
|
||||||
extern const asn1_static_node pkix_asn1_tab[];
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -99,11 +99,11 @@ if have_block
|
|||||||
tasn1.found() and \
|
tasn1.found() and \
|
||||||
host_os != 'windows'
|
host_os != 'windows'
|
||||||
tests += {
|
tests += {
|
||||||
'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c', 'pkix_asn1_tab.c',
|
'test-crypto-tlscredsx509': ['crypto-tls-x509-helpers.c',
|
||||||
tasn1, crypto, gnutls],
|
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],
|
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]}
|
tasn1, io, crypto, gnutls]}
|
||||||
endif
|
endif
|
||||||
if pam.found()
|
if pam.found()
|
||||||
|
@ -3,10 +3,7 @@
|
|||||||
* and is under copyright of various GNUTLS contributors.
|
* and is under copyright of various GNUTLS contributors.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
static const asn1_static_node pkix_asn1_tab[] = {
|
||||||
#include "crypto-tls-x509-helpers.h"
|
|
||||||
|
|
||||||
const asn1_static_node pkix_asn1_tab[] = {
|
|
||||||
{"PKIX1", 536875024, 0},
|
{"PKIX1", 536875024, 0},
|
||||||
{0, 1073741836, 0},
|
{0, 1073741836, 0},
|
||||||
{"id-ce", 1879048204, 0},
|
{"id-ce", 1879048204, 0},
|
@ -35,18 +35,40 @@
|
|||||||
#define PSKFILE WORKDIR "keys.psk"
|
#define PSKFILE WORKDIR "keys.psk"
|
||||||
#define KEYFILE WORKDIR "key-ctx.pem"
|
#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 *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 *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(
|
static QCryptoTLSCreds *test_tls_creds_psk_create(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user