mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
Handle TLS rehandshakes in GnuTLS code
* src/gnutls.c: New static function _do_handshake() * src/gnutls.c (wgnutls_read_timeout): Handle rehandshake * src/gnutls.c (wgnutls_write): Handle rehandshake * src/gnutls.c (ssl_connect_wget): Move handshake code into _do_handshake() Fixes #46061
This commit is contained in:
parent
e51076e683
commit
26fadc55c2
169
src/gnutls.c
169
src/gnutls.c
@ -56,6 +56,9 @@ as that of the covered work. */
|
||||
|
||||
#include "host.h"
|
||||
|
||||
static int
|
||||
_do_handshake (gnutls_session_t session, int fd, double timeout);
|
||||
|
||||
static int
|
||||
key_type_to_gnutls_type (enum keyfile_type type)
|
||||
{
|
||||
@ -277,6 +280,12 @@ wgnutls_read_timeout (int fd, char *buf, int bufsize, void *arg, double timeout)
|
||||
{
|
||||
ret = gnutls_record_recv (ctx->session, buf, bufsize);
|
||||
timed_out = timeout && ptimer_measure (timer) >= timeout;
|
||||
if (!timed_out && ret == GNUTLS_E_REHANDSHAKE)
|
||||
{
|
||||
DEBUGP (("GnuTLS: *** REHANDSHAKE while reading\n"));
|
||||
if ((ret = _do_handshake (ctx->session, fd, timeout)) == 0)
|
||||
ret = GNUTLS_E_AGAIN; /* restart reading */
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ret == GNUTLS_E_INTERRUPTED || (ret == GNUTLS_E_AGAIN && !timed_out));
|
||||
@ -425,16 +434,96 @@ static struct transport_implementation wgnutls_transport =
|
||||
wgnutls_peek, wgnutls_errstr, wgnutls_close
|
||||
};
|
||||
|
||||
bool
|
||||
ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
static int
|
||||
_do_handshake (gnutls_session_t session, int fd, double timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
int flags = 0;
|
||||
#endif
|
||||
int err;
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
flags = fcntl (fd, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
|
||||
return -1;
|
||||
#else
|
||||
/* XXX: Assume it was blocking before. */
|
||||
const int one = 1;
|
||||
if (ioctl (fd, FIONBIO, &one) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We don't stop the handshake process for non-fatal errors */
|
||||
do
|
||||
{
|
||||
err = gnutls_handshake (session);
|
||||
|
||||
if (timeout && err == GNUTLS_E_AGAIN)
|
||||
{
|
||||
if (gnutls_record_get_direction (session))
|
||||
{
|
||||
/* wait for writeability */
|
||||
err = select_fd (fd, timeout, WAIT_FOR_WRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait for readability */
|
||||
err = select_fd (fd, timeout, WAIT_FOR_READ);
|
||||
}
|
||||
|
||||
if (err <= 0)
|
||||
{
|
||||
if (err == 0)
|
||||
{
|
||||
errno = ETIMEDOUT;
|
||||
err = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
err = GNUTLS_E_AGAIN;
|
||||
}
|
||||
else if (err < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
|
||||
if (err == GNUTLS_E_WARNING_ALERT_RECEIVED ||
|
||||
err == GNUTLS_E_FATAL_ALERT_RECEIVED)
|
||||
{
|
||||
gnutls_alert_description_t alert = gnutls_alert_get (session);
|
||||
const char *str = gnutls_alert_get_name (alert);
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n",
|
||||
alert, str ? str : "(unknown)");
|
||||
}
|
||||
}
|
||||
}
|
||||
while (err && gnutls_error_is_fatal (err) == 0);
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
if (fcntl (fd, F_SETFL, flags) < 0)
|
||||
return -1;
|
||||
#else
|
||||
const int zero = 0;
|
||||
if (ioctl (fd, FIONBIO, &zero) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool
|
||||
ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
{
|
||||
struct wgnutls_transport_context *ctx;
|
||||
gnutls_session_t session;
|
||||
int err;
|
||||
const char *str;
|
||||
|
||||
gnutls_init (&session, GNUTLS_CLIENT);
|
||||
|
||||
@ -558,79 +647,7 @@ ssl_connect_wget (int fd, const char *hostname, int *continue_session)
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.connect_timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
flags = fcntl (fd, F_GETFL, 0);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
if (fcntl (fd, F_SETFL, flags | O_NONBLOCK))
|
||||
return -1;
|
||||
#else
|
||||
/* XXX: Assume it was blocking before. */
|
||||
const int one = 1;
|
||||
if (ioctl (fd, FIONBIO, &one) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* We don't stop the handshake process for non-fatal errors */
|
||||
do
|
||||
{
|
||||
err = gnutls_handshake (session);
|
||||
|
||||
if (opt.connect_timeout && err == GNUTLS_E_AGAIN)
|
||||
{
|
||||
if (gnutls_record_get_direction (session))
|
||||
{
|
||||
/* wait for writeability */
|
||||
err = select_fd (fd, opt.connect_timeout, WAIT_FOR_WRITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* wait for readability */
|
||||
err = select_fd (fd, opt.connect_timeout, WAIT_FOR_READ);
|
||||
}
|
||||
|
||||
if (err <= 0)
|
||||
{
|
||||
if (err == 0)
|
||||
{
|
||||
errno = ETIMEDOUT;
|
||||
err = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
err = GNUTLS_E_AGAIN;
|
||||
}
|
||||
else if (err < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: %s\n", gnutls_strerror (err));
|
||||
if (err == GNUTLS_E_WARNING_ALERT_RECEIVED ||
|
||||
err == GNUTLS_E_FATAL_ALERT_RECEIVED)
|
||||
{
|
||||
gnutls_alert_description_t alert = gnutls_alert_get (session);
|
||||
str = gnutls_alert_get_name (alert);
|
||||
if (str == NULL)
|
||||
str = "(unknown)";
|
||||
logprintf (LOG_NOTQUIET, "GnuTLS: received alert [%d]: %s\n", alert, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (err && gnutls_error_is_fatal (err) == 0);
|
||||
|
||||
if (opt.connect_timeout)
|
||||
{
|
||||
#ifdef F_GETFL
|
||||
if (fcntl (fd, F_SETFL, flags) < 0)
|
||||
return -1;
|
||||
#else
|
||||
const int zero = 0;
|
||||
if (ioctl (fd, FIONBIO, &zero) < 0)
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
err = _do_handshake (session, fd, opt.connect_timeout);
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user