mirror of https://github.com/xemu-project/xemu.git
crypto: push error reporting into TLS session I/O APIs
The current TLS session I/O APIs just return a synthetic errno value on error, which has been translated from a gnutls error value. This looses a large amount of valuable information that distinguishes different scenarios. Pushing population of the "Error *errp" object into the TLS session I/O APIs gives more detailed error information. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
305233349b
commit
57941c9c86
|
@ -441,23 +441,20 @@ 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;
|
error_setg(errp,
|
||||||
case GNUTLS_E_INTERRUPTED:
|
"Cannot write to TLS channel: %s",
|
||||||
errno = EINTR;
|
gnutls_strerror(ret));
|
||||||
break;
|
return -1;
|
||||||
default:
|
|
||||||
errno = EIO;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
ret = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -467,26 +464,24 @@ 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;
|
error_setg(errp,
|
||||||
case GNUTLS_E_PREMATURE_TERMINATION:
|
"Cannot read from TLS channel: %s",
|
||||||
errno = ECONNABORTED;
|
gnutls_strerror(ret));
|
||||||
break;
|
return -1;
|
||||||
default:
|
|
||||||
errno = EIO;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
ret = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -605,9 +600,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 +611,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
@ -212,6 +213,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 +223,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:
|
||||||
|
|
|
@ -277,24 +277,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 +316,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;
|
||||||
|
|
Loading…
Reference in New Issue