aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKamil Dudka <kdudka@redhat.com>2009-11-12 11:16:31 +0000
committerKamil Dudka <kdudka@redhat.com>2009-11-12 11:16:31 +0000
commit571309dc3edaf1c03ff6fdfbcf551875644b5a7f (patch)
tree4d9a937fdb822578e6899d657c7d1bd324d23c8f /lib
parentd547d00f2cfa69e07d6873bbebbc82f3132f1b82 (diff)
- 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
Diffstat (limited to 'lib')
-rw-r--r--lib/nss.c50
-rw-r--r--lib/transfer.c5
-rw-r--r--lib/urldata.h3
3 files changed, 55 insertions, 3 deletions
diff --git a/lib/nss.c b/lib/nss.c
index 5c1340fa9..893ca2edc 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -844,6 +844,36 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
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
*
@@ -1081,7 +1111,11 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
switch (data->set.ssl.version) {
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;
case CURL_SSLVERSION_TLSv1:
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)
goto error;
+ /* reset the flag to avoid an infinite loop */
+ data->state.ssl_connect_retry = FALSE;
+
/* enable all ciphers from enable_ciphers_by_default */
cipher_to_enable = enable_ciphers_by_default;
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;
error:
+ /* reset the flag to avoid an infinite loop */
+ data->state.ssl_connect_retry = FALSE;
+
err = PR_GetError();
infof(data, "NSS error %d\n", err);
if(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;
}
diff --git a/lib/transfer.c b/lib/transfer.c
index e875ce309..86213f90d 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -2572,10 +2572,11 @@ CURLcode Curl_retry_request(struct connectdata *conn,
if(data->set.upload && !(conn->protocol&PROT_HTTP))
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) &&
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
"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
diff --git a/lib/urldata.h b/lib/urldata.h
index 014cb98f8..d3101c03a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1331,6 +1331,9 @@ struct UrlState {
} proto;
/* current user of this SessionHandle instance, or NULL */
struct connectdata *current_conn;
+
+ /* if true, force SSL connection retry (workaround for certain servers) */
+ bool ssl_connect_retry;
};