1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

- libcurl-NSS now tries to reconnect with TLS disabled in case it detects

a broken TLS server. However it does not happen if SSL version is selected
  manually. The approach was originally taken from PSM. Kaspar Brand helped me
  to complete the patch. Original bug reports:
  https://bugzilla.redhat.com/525496
  https://bugzilla.redhat.com/527771
This commit is contained in:
Kamil Dudka 2009-11-12 11:16:31 +00:00
parent d547d00f2c
commit 571309dc3e
4 changed files with 62 additions and 3 deletions

View File

@ -12,6 +12,13 @@ Kamil Dudka (12 Nov 2009)
before and always closed unresolved. More info at the RH bug: before and always closed unresolved. More info at the RH bug:
https://bugzilla.redhat.com/534176 https://bugzilla.redhat.com/534176
- libcurl-NSS now tries to reconnect with TLS disabled in case it detects
a broken TLS server. However it does not happen if SSL version is selected
manually. The approach was originally taken from PSM. Kaspar Brand helped me
to complete the patch. Original bug reports:
https://bugzilla.redhat.com/525496
https://bugzilla.redhat.com/527771
Yang Tse (11 Nov 2009) Yang Tse (11 Nov 2009)
- Marco Maggi reported that compilation failed when configured --with-gssapi - Marco Maggi reported that compilation failed when configured --with-gssapi
and GNU GSS installed due to a missing mutual exclusion of header files in and GNU GSS installed due to a missing mutual exclusion of header files in

View File

@ -844,6 +844,36 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
return SECSuccess; return SECSuccess;
} }
/* This function is supposed to decide, which error codes should be used
* to conclude server is TLS intolerant.
*
* taken from xulrunner - nsNSSIOLayer.cpp
*/
static PRBool
isTLSIntoleranceError(PRInt32 err)
{
switch (err) {
case SSL_ERROR_BAD_MAC_ALERT:
case SSL_ERROR_BAD_MAC_READ:
case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
case SSL_ERROR_NO_CYPHER_OVERLAP:
case SSL_ERROR_BAD_SERVER:
case SSL_ERROR_BAD_BLOCK_PADDING:
case SSL_ERROR_UNSUPPORTED_VERSION:
case SSL_ERROR_PROTOCOL_VERSION_ALERT:
case SSL_ERROR_RX_MALFORMED_FINISHED:
case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
case SSL_ERROR_DECODE_ERROR_ALERT:
case SSL_ERROR_RX_UNKNOWN_ALERT:
return PR_TRUE;
default:
return PR_FALSE;
}
}
/** /**
* Global SSL init * Global SSL init
* *
@ -1081,7 +1111,11 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
switch (data->set.ssl.version) { switch (data->set.ssl.version) {
default: default:
case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_DEFAULT:
ssl3 = tlsv1 = PR_TRUE; ssl3 = PR_TRUE;
if (data->state.ssl_connect_retry)
infof(data, "TLS disabled due to previous handshake failure\n");
else
tlsv1 = PR_TRUE;
break; break;
case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1:
tlsv1 = PR_TRUE; tlsv1 = PR_TRUE;
@ -1104,6 +1138,9 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess) if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
goto error; goto error;
/* reset the flag to avoid an infinite loop */
data->state.ssl_connect_retry = FALSE;
/* enable all ciphers from enable_ciphers_by_default */ /* enable all ciphers from enable_ciphers_by_default */
cipher_to_enable = enable_ciphers_by_default; cipher_to_enable = enable_ciphers_by_default;
while (SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) { while (SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) {
@ -1282,10 +1319,21 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
return CURLE_OK; return CURLE_OK;
error: error:
/* reset the flag to avoid an infinite loop */
data->state.ssl_connect_retry = FALSE;
err = PR_GetError(); err = PR_GetError();
infof(data, "NSS error %d\n", err); infof(data, "NSS error %d\n", err);
if(model) if(model)
PR_Close(model); PR_Close(model);
if (ssl3 && tlsv1 && isTLSIntoleranceError(err)) {
/* schedule reconnect through Curl_retry_request() */
data->state.ssl_connect_retry = TRUE;
infof(data, "Error in TLS handshake, trying SSLv3...\n");
return CURLE_OK;
}
return curlerr; return curlerr;
} }

View File

@ -2572,10 +2572,11 @@ CURLcode Curl_retry_request(struct connectdata *conn,
if(data->set.upload && !(conn->protocol&PROT_HTTP)) if(data->set.upload && !(conn->protocol&PROT_HTTP))
return CURLE_OK; return CURLE_OK;
if((data->req.bytecount + if(/* workaround for broken TLS servers */ data->state.ssl_connect_retry ||
((data->req.bytecount +
data->req.headerbytecount == 0) && data->req.headerbytecount == 0) &&
conn->bits.reuse && conn->bits.reuse &&
!data->set.opt_no_body) { !data->set.opt_no_body)) {
/* We got no data, we attempted to re-use a connection and yet we want a /* We got no data, we attempted to re-use a connection and yet we want a
"body". This might happen if the connection was left alive when we were "body". This might happen if the connection was left alive when we were
done using it before, but that was closed when we wanted to read from done using it before, but that was closed when we wanted to read from

View File

@ -1331,6 +1331,9 @@ struct UrlState {
} proto; } proto;
/* current user of this SessionHandle instance, or NULL */ /* current user of this SessionHandle instance, or NULL */
struct connectdata *current_conn; struct connectdata *current_conn;
/* if true, force SSL connection retry (workaround for certain servers) */
bool ssl_connect_retry;
}; };