Dima Barsky reported a problem with GnuTLS-enabled libcurl in bug report
#1334338 (http://curl.haxx.se/bug/view.cgi?id=1334338). When reading an SSL stream from a server and the server requests a "rehandshake", the current code simply returns this as an error. I have no good way to test this, but I've added a crude attempt of dealing with this situation slightly better - it makes a blocking handshake if this happens. Done like this because fixing this the "proper" way (that would handshake asynchronously) will require quite some work and I really need a good way to test this to do such a change.
This commit is contained in:
Родитель
1a1ab2e2e8
Коммит
c890149c8c
11
CHANGES
11
CHANGES
|
@ -8,6 +8,17 @@
|
|||
|
||||
|
||||
|
||||
Daniel (22 October 2005)
|
||||
- Dima Barsky reported a problem with GnuTLS-enabled libcurl in bug report
|
||||
#1334338 (http://curl.haxx.se/bug/view.cgi?id=1334338). When reading an SSL
|
||||
stream from a server and the server requests a "rehandshake", the current
|
||||
code simply returns this as an error. I have no good way to test this, but
|
||||
I've added a crude attempt of dealing with this situation slightly better -
|
||||
it makes a blocking handshake if this happens. Done like this because fixing
|
||||
this the "proper" way (that would handshake asynchronously) will require
|
||||
quite some work and I really need a good way to test this to do such a
|
||||
change.
|
||||
|
||||
Daniel (21 October 2005)
|
||||
- "Ofer" reported a problem when libcurl re-used a connection and failed to do
|
||||
it, it could then accidentally actually crash. Presumably, this concerns FTP
|
||||
|
|
136
lib/gtls.c
136
lib/gtls.c
|
@ -110,6 +110,72 @@ static void showtime(struct SessionHandle *data,
|
|||
infof(data, "%s", data->state.buffer);
|
||||
}
|
||||
|
||||
/* this function does a BLOCKING SSL/TLS (re-)handshake */
|
||||
static CURLcode handshake(struct connectdata *conn,
|
||||
gnutls_session session,
|
||||
int sockindex,
|
||||
bool duringconnect)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
int rc;
|
||||
|
||||
do {
|
||||
rc = gnutls_handshake(session);
|
||||
|
||||
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
|
||||
long timeout_ms = DEFAULT_CONNECT_TIMEOUT;
|
||||
long has_passed;
|
||||
|
||||
if(duringconnect && data->set.connecttimeout)
|
||||
timeout_ms = data->set.connecttimeout*1000;
|
||||
|
||||
if(data->set.timeout) {
|
||||
/* get the strictest timeout of the ones converted to milliseconds */
|
||||
if((data->set.timeout*1000) < timeout_ms)
|
||||
timeout_ms = data->set.timeout*1000;
|
||||
}
|
||||
|
||||
/* Evaluate in milliseconds how much time that has passed */
|
||||
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
|
||||
|
||||
/* subtract the passed time */
|
||||
timeout_ms -= has_passed;
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
/* a precaution, no need to continue if time already is up */
|
||||
failf(data, "SSL connection timeout");
|
||||
return CURLE_OPERATION_TIMEOUTED;
|
||||
}
|
||||
|
||||
rc = Curl_select(conn->sock[sockindex],
|
||||
conn->sock[sockindex], (int)timeout_ms);
|
||||
if(rc > 0)
|
||||
/* reabable or writable, go loop*/
|
||||
continue;
|
||||
else if(0 == rc) {
|
||||
/* timeout */
|
||||
failf(data, "SSL connection timeout");
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else {
|
||||
/* anything that gets here is fatally bad */
|
||||
failf(data, "select on SSL socket, errno: %d", Curl_ourerrno());
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
if (rc < 0) {
|
||||
failf(data, "gnutls_handshake() failed: %d", rc);
|
||||
/* gnutls_perror(ret); */
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called after the TCP connect has completed. Setup the TLS
|
||||
* layer and do all necessary magic.
|
||||
|
@ -206,61 +272,10 @@ Curl_gtls_connect(struct connectdata *conn,
|
|||
infof (data, "SSL re-using session ID\n");
|
||||
}
|
||||
|
||||
do {
|
||||
rc = gnutls_handshake(session);
|
||||
|
||||
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
|
||||
long timeout_ms;
|
||||
long has_passed;
|
||||
|
||||
if(data->set.timeout || data->set.connecttimeout) {
|
||||
/* get the most strict timeout of the ones converted to milliseconds */
|
||||
if(data->set.timeout &&
|
||||
(data->set.timeout>data->set.connecttimeout))
|
||||
timeout_ms = data->set.timeout*1000;
|
||||
else
|
||||
timeout_ms = data->set.connecttimeout*1000;
|
||||
}
|
||||
else
|
||||
timeout_ms = DEFAULT_CONNECT_TIMEOUT;
|
||||
|
||||
/* Evaluate in milliseconds how much time that has passed */
|
||||
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
|
||||
|
||||
/* subtract the passed time */
|
||||
timeout_ms -= has_passed;
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
/* a precaution, no need to continue if time already is up */
|
||||
failf(data, "SSL connection timeout");
|
||||
return CURLE_OPERATION_TIMEOUTED;
|
||||
}
|
||||
|
||||
rc = Curl_select(conn->sock[sockindex],
|
||||
conn->sock[sockindex], (int)timeout_ms);
|
||||
if(rc > 0)
|
||||
/* reabable or writable, go loop*/
|
||||
continue;
|
||||
else if(0 == rc) {
|
||||
/* timeout */
|
||||
failf(data, "SSL connection timeout");
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else {
|
||||
/* anything that gets here is fatally bad */
|
||||
failf(data, "select on SSL socket, errno: %d", Curl_ourerrno());
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
if (rc < 0) {
|
||||
failf(data, "gnutls_handshake() failed: %d", rc);
|
||||
/* gnutls_perror(ret); */
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
}
|
||||
rc = handshake(conn, session, sockindex, TRUE);
|
||||
if(rc)
|
||||
/* handshake() sets its own error message with failf() */
|
||||
return rc;
|
||||
|
||||
/* This function will return the peer's raw certificate (chain) as sent by
|
||||
the peer. These certificates are in raw format (DER encoded for
|
||||
|
@ -467,6 +482,17 @@ ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
|
|||
return -1;
|
||||
}
|
||||
|
||||
if(ret == GNUTLS_E_REHANDSHAKE) {
|
||||
/* BLOCKING call, this is bad but a work-around for now. Fixing this "the
|
||||
proper way" takes a whole lot of work. */
|
||||
CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE);
|
||||
if(rc)
|
||||
/* handshake() writes error message on its own */
|
||||
return rc;
|
||||
*wouldblock = TRUE; /* then return as if this was a wouldblock */
|
||||
return -1;
|
||||
}
|
||||
|
||||
*wouldblock = FALSE;
|
||||
if (!ret) {
|
||||
failf(conn->data, "Peer closed the TLS connection");
|
||||
|
|
Загрузка…
Ссылка в новой задаче