Index: lib/nss.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/nss.c,v
retrieving revision 1.61
diff -u -p -r1.61 nss.c
--- lib/nss.c	18 Oct 2009 00:10:13 -0000	1.61
+++ lib/nss.c	18 Oct 2009 19:55:30 -0000
@@ -846,6 +846,36 @@ static SECStatus SelectClientCert(void *
   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
  *
@@ -972,6 +1002,9 @@ CURLcode Curl_nss_connect(struct connect
 
   curlerr = CURLE_SSL_CONNECT_ERROR;
 
+  /* reset the flag to avoid an infinite loop */
+  data->state.ssl_connect_retry = FALSE;
+
   if (connssl->state == ssl_connection_complete)
     return CURLE_OK;
 
@@ -1074,7 +1107,11 @@ 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.tls_broken_server)
+      infof(data, "TLS server known as broken, disabling TLS\n");
+    else
+      tlsv1 = PR_TRUE;
     break;
   case CURL_SSLVERSION_TLSv1:
     tlsv1 = PR_TRUE;
@@ -1094,7 +1131,8 @@ 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(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2
+        || data->state.tls_broken_server) != SECSuccess)
     goto error;
 
   /* enable all ciphers from enable_ciphers_by_default */
@@ -1278,6 +1316,20 @@ error:
   infof(data, "NSS error %d\n", err);
   if(model)
     PR_Close(model);
+
+  if (ssl3 && tlsv1 && !data->state.tls_broken_server
+      && isTLSIntoleranceError(err)) {
+
+    /* the SSL error is known to be suppressed by disabling TLSv1 and/or
+     * enabling SSL_V2_COMPATIBLE_HELLO */
+    data->state.tls_broken_server = TRUE;
+
+    /* schedule reconnect through Curl_retry_request() */
+    data->state.ssl_connect_retry = TRUE;
+    infof(data, "encountered broken TLS server, trying reconnect...\n");
+    return CURLE_OK;
+  }
+
   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	18 Oct 2009 19:55:30 -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(/* 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
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	18 Oct 2009 19:55:30 -0000
@@ -1327,6 +1327,12 @@ struct UrlState {
   } proto;
   /* current user of this SessionHandle instance, or NULL */
   struct connectdata *current_conn;
+
+  /* if true, TLS peer is considered broken (workaround for certain servers) */
+  bool tls_broken_server;
+
+  /* if true, force SSL connection retry (workaround for certain servers) */
+  bool ssl_connect_retry;
 };
 
 

