|
@@ -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"
|
|
@@ -450,9 +486,14 @@ qcrypto_tls_session_write(QCryptoTLSSession *session,
|
|
if (ret == GNUTLS_E_AGAIN) {
|
|
if (ret == GNUTLS_E_AGAIN) {
|
|
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
|
|
return QCRYPTO_TLS_SESSION_ERR_BLOCK;
|
|
} else {
|
|
} else {
|
|
- error_setg(errp,
|
|
|
|
- "Cannot write to TLS channel: %s",
|
|
|
|
- gnutls_strerror(ret));
|
|
|
|
|
|
+ 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;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -477,9 +518,14 @@ qcrypto_tls_session_read(QCryptoTLSSession *session,
|
|
gracefulTermination){
|
|
gracefulTermination){
|
|
return 0;
|
|
return 0;
|
|
} else {
|
|
} else {
|
|
- error_setg(errp,
|
|
|
|
- "Cannot read from TLS channel: %s",
|
|
|
|
- gnutls_strerror(ret));
|
|
|
|
|
|
+ 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;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -507,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",
|
|
|
|
- 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;
|
|
ret = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ error_free(session->rerr);
|
|
|
|
+ error_free(session->werr);
|
|
|
|
+ session->rerr = session->werr = NULL;
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|