Hello,
here is a proposed patch implementing the workaround for TLS intolerant
servers (taken from Firefox/xulrunner). I've just tested it as following
and it looks like it solves the problem:
$ curl --silent --verbose -o/dev/null https://www.orange.sk
$ curl --silent --verbose -o/dev/null \
https://tcs.mysap.com/invoke/tc/getCert?SAPServerCA.der
Any feedback welcome!
Kamil
Index: lib/nss.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/nss.c,v
retrieving revision 1.60
diff -u -p -r1.60 nss.c
--- lib/nss.c 7 Oct 2009 20:34:08 -0000 1.60
+++ lib/nss.c 14 Oct 2009 17:37:44 -0000
@@ -1070,7 +1070,9 @@ CURLcode Curl_nss_connect(struct connect
switch (data->set.ssl.version) {
default:
case CURL_SSLVERSION_DEFAULT:
- ssl3 = tlsv1 = PR_TRUE;
+ ssl3 = PR_TRUE;
+ if (!data->state.ssl_connect_retry)
+ tlsv1 = PR_TRUE;
break;
case CURL_SSLVERSION_TLSv1:
tlsv1 = PR_TRUE;
@@ -1090,9 +1092,13 @@ CURLcode Curl_nss_connect(struct connect
if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess)
goto error;
- if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
+ if(!data->state.ssl_connect_retry
+ && 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) {
@@ -1270,10 +1276,34 @@ CURLcode Curl_nss_connect(struct connect
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);
+
+ switch (err) {
+ case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
+ case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
+ /* these SSL errors are known to be suppressed by disabling TLSv1 and/or
+ * enabling SSL_V2_COMPATIBLE_HELLO, let's try to reconnect */
+
+ if (!ssl3 || !tlsv1)
+ /* this is either the second attempt or the SSL version was selected
+ * by user, so we should respect the selection */
+ break;
+
+ /* schedule reconnect through Curl_retry_request() */
+ infof(data, "peer seems to be TLS intolerant, trying reconnect...\n");
+ data->state.ssl_connect_retry = TRUE;
+ return CURLE_OK;
+
+ default:
+ break;
+ }
+
return curlerr;
}
Index: lib/transfer.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/transfer.c,v
retrieving revision 1.440
diff -u -p -r1.440 transfer.c
--- lib/transfer.c 27 Sep 2009 21:37:24 -0000 1.440
+++ lib/transfer.c 14 Oct 2009 17:37:45 -0000
@@ -2572,10 +2572,11 @@ CURLcode Curl_retry_request(struct conne
if(data->set.upload && !(conn->protocol&PROT_HTTP))
return CURLE_OK;
- if((data->req.bytecount +
+ if(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
Index: lib/urldata.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/urldata.h,v
retrieving revision 1.419
diff -u -p -r1.419 urldata.h
--- lib/urldata.h 26 Sep 2009 08:31:48 -0000 1.419
+++ lib/urldata.h 14 Oct 2009 17:37:45 -0000
@@ -1327,6 +1327,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;
};
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html