Blame SOURCES/0023-curl-7.29.0-8868a226.patch

92baa4
From 355f7594877a62f9aa657e8a72d3f92b3c887d73 Mon Sep 17 00:00:00 2001
92baa4
From: Kamil Dudka <kdudka@redhat.com>
92baa4
Date: Thu, 17 Apr 2014 13:12:59 +0200
92baa4
Subject: [PATCH 1/4] nss: split Curl_nss_connect() into 4 functions
92baa4
92baa4
Upstream-commit: a43bba3a34ed8912c4ca10f213590d1998ba0d29
92baa4
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
92baa4
---
92baa4
 lib/nss.c | 134 +++++++++++++++++++++++++++++++++++++++++++-------------------
92baa4
 1 file changed, 94 insertions(+), 40 deletions(-)
92baa4
92baa4
diff --git a/lib/nss.c b/lib/nss.c
92baa4
index 1381dc4..4d57a24 100644
92baa4
--- a/lib/nss.c
92baa4
+++ b/lib/nss.c
92baa4
@@ -1216,9 +1216,62 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver,
92baa4
   return CURLE_SSL_CONNECT_ERROR;
92baa4
 }
92baa4
 
92baa4
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
+static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
92baa4
+                                 struct SessionHandle *data,
92baa4
+                                 CURLcode curlerr)
92baa4
 {
92baa4
+  SSLVersionRange sslver;
92baa4
   PRErrorCode err = 0;
92baa4
+
92baa4
+  /* reset the flag to avoid an infinite loop */
92baa4
+  data->state.ssl_connect_retry = FALSE;
92baa4
+
92baa4
+  if(is_nss_error(curlerr)) {
92baa4
+    /* read NSPR error code */
92baa4
+    err = PR_GetError();
92baa4
+    if(is_cc_error(err))
92baa4
+      curlerr = CURLE_SSL_CERTPROBLEM;
92baa4
+
92baa4
+    /* print the error number and error string */
92baa4
+    infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
92baa4
+
92baa4
+    /* print a human-readable message describing the error if available */
92baa4
+    nss_print_error_message(data, err);
92baa4
+  }
92baa4
+
92baa4
+  /* cleanup on connection failure */
92baa4
+  Curl_llist_destroy(connssl->obj_list, NULL);
92baa4
+  connssl->obj_list = NULL;
92baa4
+
92baa4
+  if((SSL_VersionRangeGet(connssl->handle, &sslver) == SECSuccess)
92baa4
+      && (sslver.min == SSL_LIBRARY_VERSION_3_0)
92baa4
+      && (sslver.max == SSL_LIBRARY_VERSION_TLS_1_0)
92baa4
+      && isTLSIntoleranceError(err)) {
92baa4
+    /* schedule reconnect through Curl_retry_request() */
92baa4
+    data->state.ssl_connect_retry = TRUE;
92baa4
+    infof(data, "Error in TLS handshake, trying SSLv3...\n");
92baa4
+    return CURLE_OK;
92baa4
+  }
92baa4
+
92baa4
+  return curlerr;
92baa4
+}
92baa4
+
92baa4
+/* Switch the SSL socket into non-blocking mode. */
92baa4
+static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
92baa4
+                                 struct SessionHandle *data)
92baa4
+{
92baa4
+  static PRSocketOptionData sock_opt;
92baa4
+  sock_opt.option = PR_SockOpt_Nonblocking;
92baa4
+  sock_opt.value.non_blocking = PR_TRUE;
92baa4
+
92baa4
+  if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
92baa4
+    return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
92baa4
+
92baa4
+  return CURLE_OK;
92baa4
+}
92baa4
+
92baa4
+static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
92baa4
+{
92baa4
   PRFileDesc *model = NULL;
92baa4
   PRBool ssl_no_cache;
92baa4
   PRBool ssl_cbc_random_iv;
92baa4
@@ -1226,9 +1279,6 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
   curl_socket_t sockfd = conn->sock[sockindex];
92baa4
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
92baa4
   CURLcode curlerr;
92baa4
-  PRSocketOptionData sock_opt;
92baa4
-  long time_left;
92baa4
-  PRUint32 timeout;
92baa4
 
92baa4
   SSLVersionRange sslver = {
92baa4
     SSL_LIBRARY_VERSION_3_0,      /* min */
92baa4
@@ -1402,16 +1452,32 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
 
92baa4
   SSL_SetURL(connssl->handle, conn->host.name);
92baa4
 
92baa4
+  return CURLE_OK;
92baa4
+
92baa4
+error:
92baa4
+  if(model)
92baa4
+    PR_Close(model);
92baa4
+
92baa4
+  return nss_fail_connect(connssl, data, curlerr);
92baa4
+}
92baa4
+
92baa4
+static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
92baa4
+{
92baa4
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
92baa4
+  struct SessionHandle *data = conn->data;
92baa4
+  CURLcode curlerr = CURLE_SSL_CONNECT_ERROR;
92baa4
+  PRUint32 timeout;
92baa4
+
92baa4
   /* check timeout situation */
92baa4
-  time_left = Curl_timeleft(data, NULL, TRUE);
92baa4
+  const long time_left = Curl_timeleft(data, NULL, TRUE);
92baa4
   if(time_left < 0L) {
92baa4
     failf(data, "timed out before SSL handshake");
92baa4
     curlerr = CURLE_OPERATION_TIMEDOUT;
92baa4
     goto error;
92baa4
   }
92baa4
-  timeout = PR_MillisecondsToInterval((PRUint32) time_left);
92baa4
 
92baa4
   /* Force the handshake now */
92baa4
+  timeout = PR_MillisecondsToInterval((PRUint32) time_left);
92baa4
   if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
92baa4
     if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
92baa4
       curlerr = CURLE_PEER_FAILED_VERIFICATION;
92baa4
@@ -1420,12 +1486,6 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
     goto error;
92baa4
   }
92baa4
 
92baa4
-  /* switch the SSL socket into non-blocking mode */
92baa4
-  sock_opt.option = PR_SockOpt_Nonblocking;
92baa4
-  sock_opt.value.non_blocking = PR_TRUE;
92baa4
-  if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
92baa4
-    goto error;
92baa4
-
92baa4
   connssl->state = ssl_connection_complete;
92baa4
   conn->recv[sockindex] = nss_recv;
92baa4
   conn->send[sockindex] = nss_send;
92baa4
@@ -1453,40 +1513,34 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
 
92baa4
   return CURLE_OK;
92baa4
 
92baa4
-  error:
92baa4
-  /* reset the flag to avoid an infinite loop */
92baa4
-  data->state.ssl_connect_retry = FALSE;
92baa4
+error:
92baa4
+  return nss_fail_connect(connssl, data, curlerr);
92baa4
+}
92baa4
 
92baa4
-  if(is_nss_error(curlerr)) {
92baa4
-    /* read NSPR error code */
92baa4
-    err = PR_GetError();
92baa4
-    if(is_cc_error(err))
92baa4
-      curlerr = CURLE_SSL_CERTPROBLEM;
92baa4
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
+{
92baa4
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
92baa4
+  struct SessionHandle *data = conn->data;
92baa4
+  CURLcode rv;
92baa4
 
92baa4
-    /* print the error number and error string */
92baa4
-    infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
92baa4
+  rv = nss_setup_connect(conn, sockindex);
92baa4
+  if(rv)
92baa4
+    return rv;
92baa4
 
92baa4
-    /* print a human-readable message describing the error if available */
92baa4
-    nss_print_error_message(data, err);
92baa4
+  rv = nss_do_connect(conn, sockindex);
92baa4
+  switch(rv) {
92baa4
+  case CURLE_OK:
92baa4
+    break;
92baa4
+  default:
92baa4
+    return rv;
92baa4
   }
92baa4
 
92baa4
-  if(model)
92baa4
-    PR_Close(model);
92baa4
-
92baa4
-  /* cleanup on connection failure */
92baa4
-  Curl_llist_destroy(connssl->obj_list, NULL);
92baa4
-  connssl->obj_list = NULL;
92baa4
-
92baa4
-  if((sslver.min == SSL_LIBRARY_VERSION_3_0)
92baa4
-      && (sslver.max == SSL_LIBRARY_VERSION_TLS_1_0)
92baa4
-      && isTLSIntoleranceError(err)) {
92baa4
-    /* schedule reconnect through Curl_retry_request() */
92baa4
-    data->state.ssl_connect_retry = TRUE;
92baa4
-    infof(data, "Error in TLS handshake, trying SSLv3...\n");
92baa4
-    return CURLE_OK;
92baa4
-  }
92baa4
+  /* switch the SSL socket into non-blocking mode */
92baa4
+  rv = nss_set_nonblock(connssl, data);
92baa4
+  if(rv)
92baa4
+    return rv;
92baa4
 
92baa4
-  return curlerr;
92baa4
+  return CURLE_OK;
92baa4
 }
92baa4
 
92baa4
 static ssize_t nss_send(struct connectdata *conn,  /* connection data */
92baa4
-- 
92baa4
2.1.0
92baa4
92baa4
92baa4
From b5132ce96009510656e5f719c8805647c246685b Mon Sep 17 00:00:00 2001
92baa4
From: Kamil Dudka <kdudka@redhat.com>
92baa4
Date: Thu, 17 Apr 2014 13:27:39 +0200
92baa4
Subject: [PATCH 2/4] nss: implement non-blocking SSL handshake
92baa4
92baa4
Upstream-commit: 8868a226cdad66a9a07d6e3f168884817592a1df
92baa4
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
92baa4
---
92baa4
 lib/nss.c     | 57 ++++++++++++++++++++++++++++++++++++++++++++++++---------
92baa4
 lib/nssg.h    |  1 +
92baa4
 lib/urldata.h |  1 +
92baa4
 3 files changed, 50 insertions(+), 9 deletions(-)
92baa4
92baa4
diff --git a/lib/nss.c b/lib/nss.c
92baa4
index 4d57a24..5be1058 100644
92baa4
--- a/lib/nss.c
92baa4
+++ b/lib/nss.c
92baa4
@@ -1479,7 +1479,10 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
92baa4
   /* Force the handshake now */
92baa4
   timeout = PR_MillisecondsToInterval((PRUint32) time_left);
92baa4
   if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
92baa4
-    if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
92baa4
+    if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
92baa4
+      /* TODO: propagate the blocking direction from the NSPR layer */
92baa4
+      return CURLE_AGAIN;
92baa4
+    else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
92baa4
       curlerr = CURLE_PEER_FAILED_VERIFICATION;
92baa4
     else if(conn->data->set.ssl.certverifyresult!=0)
92baa4
       curlerr = CURLE_SSL_CACERT;
92baa4
@@ -1517,32 +1520,68 @@ error:
92baa4
   return nss_fail_connect(connssl, data, curlerr);
92baa4
 }
92baa4
 
92baa4
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
+static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
92baa4
+                                   bool *done)
92baa4
 {
92baa4
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
92baa4
   struct SessionHandle *data = conn->data;
92baa4
+  const bool blocking = (done == NULL);
92baa4
   CURLcode rv;
92baa4
 
92baa4
-  rv = nss_setup_connect(conn, sockindex);
92baa4
-  if(rv)
92baa4
-    return rv;
92baa4
+  if(connssl->connecting_state == ssl_connect_1) {
92baa4
+    rv = nss_setup_connect(conn, sockindex);
92baa4
+    if(rv)
92baa4
+      /* we do not expect CURLE_AGAIN from nss_setup_connect() */
92baa4
+      return rv;
92baa4
+
92baa4
+    if(!blocking) {
92baa4
+      /* in non-blocking mode, set NSS non-blocking mode before handshake */
92baa4
+      rv = nss_set_nonblock(connssl, data);
92baa4
+      if(rv)
92baa4
+        return rv;
92baa4
+    }
92baa4
+
92baa4
+    connssl->connecting_state = ssl_connect_2;
92baa4
+  }
92baa4
 
92baa4
   rv = nss_do_connect(conn, sockindex);
92baa4
   switch(rv) {
92baa4
   case CURLE_OK:
92baa4
     break;
92baa4
+  case CURLE_AGAIN:
92baa4
+    if(!blocking)
92baa4
+      /* CURLE_AGAIN in non-blocking mode is not an error */
92baa4
+      return CURLE_OK;
92baa4
+    /* fall through */
92baa4
   default:
92baa4
     return rv;
92baa4
   }
92baa4
 
92baa4
-  /* switch the SSL socket into non-blocking mode */
92baa4
-  rv = nss_set_nonblock(connssl, data);
92baa4
-  if(rv)
92baa4
-    return rv;
92baa4
+  if(blocking) {
92baa4
+    /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
92baa4
+    rv = nss_set_nonblock(connssl, data);
92baa4
+    if(rv)
92baa4
+      return rv;
92baa4
+  }
92baa4
+  else
92baa4
+    /* signal completed SSL handshake */
92baa4
+    *done = TRUE;
92baa4
 
92baa4
+  connssl->connecting_state = ssl_connect_done;
92baa4
   return CURLE_OK;
92baa4
 }
92baa4
 
92baa4
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
92baa4
+{
92baa4
+  return nss_connect_common(conn, sockindex, /* blocking */ NULL);
92baa4
+}
92baa4
+
92baa4
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
92baa4
+                                      int sockindex, bool *done)
92baa4
+{
92baa4
+  return nss_connect_common(conn, sockindex, done);
92baa4
+}
92baa4
+
92baa4
 static ssize_t nss_send(struct connectdata *conn,  /* connection data */
92baa4
                         int sockindex,             /* socketindex */
92baa4
                         const void *mem,           /* send this data */
92baa4
diff --git a/lib/nssg.h b/lib/nssg.h
92baa4
index a881a9a..6d9aea6 100644
92baa4
--- a/lib/nssg.h
92baa4
+++ b/lib/nssg.h
92baa4
@@ -64,6 +64,7 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */
92baa4
 #define curlssl_init Curl_nss_init
92baa4
 #define curlssl_cleanup Curl_nss_cleanup
92baa4
 #define curlssl_connect Curl_nss_connect
92baa4
+#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking
92baa4
 
92baa4
 /* NSS has its own session ID cache */
92baa4
 #define curlssl_session_free(x) Curl_nop_stmt
92baa4
diff --git a/lib/urldata.h b/lib/urldata.h
92baa4
index e5d85ff..c91bcff 100644
92baa4
--- a/lib/urldata.h
92baa4
+++ b/lib/urldata.h
92baa4
@@ -303,6 +303,7 @@ struct ssl_connect_data {
92baa4
   struct SessionHandle *data;
92baa4
   struct curl_llist *obj_list;
92baa4
   PK11GenericObject *obj_clicert;
92baa4
+  ssl_connect_state connecting_state;
92baa4
 #endif /* USE_NSS */
92baa4
 #ifdef USE_QSOSSL
92baa4
   SSLHandle *handle;
92baa4
-- 
92baa4
2.1.0
92baa4
92baa4
92baa4
From 2f1f1b1ca2d9c60c5fca5d73303ae2ec4c3d94b2 Mon Sep 17 00:00:00 2001
92baa4
From: Kamil Dudka <kdudka@redhat.com>
92baa4
Date: Wed, 23 Apr 2014 15:37:26 +0200
92baa4
Subject: [PATCH 3/4] nss: propagate blocking direction from NSPR I/O
92baa4
92baa4
... during the non-blocking SSL handshake
92baa4
92baa4
Upstream-commit: 9c941e92c4bd3d2a5dbe243f7517b6a6029afc6e
92baa4
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
92baa4
---
92baa4
 lib/http.c |   2 +-
92baa4
 lib/nss.c  | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
92baa4
 2 files changed, 104 insertions(+), 6 deletions(-)
92baa4
92baa4
diff --git a/lib/http.c b/lib/http.c
92baa4
index d1b0405..c007226 100644
92baa4
--- a/lib/http.c
92baa4
+++ b/lib/http.c
92baa4
@@ -1351,7 +1351,7 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
92baa4
 #endif
92baa4
 
92baa4
 #if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
92baa4
-    defined(USE_DARWINSSL)
92baa4
+    defined(USE_DARWINSSL) || defined(USE_NSS)
92baa4
 /* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only.
92baa4
    It should be made to query the generic SSL layer instead. */
92baa4
 static int https_getsock(struct connectdata *conn,
92baa4
diff --git a/lib/nss.c b/lib/nss.c
92baa4
index 5be1058..dadeb58 100644
92baa4
--- a/lib/nss.c
92baa4
+++ b/lib/nss.c
92baa4
@@ -179,6 +179,10 @@ static const cipher_s cipherlist[] = {
92baa4
 static const char* pem_library = "libnsspem.so";
92baa4
 SECMODModule* mod = NULL;
92baa4
 
92baa4
+/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
92baa4
+static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
92baa4
+static PRIOMethods nspr_io_methods;
92baa4
+
92baa4
 static const char* nss_error_to_name(PRErrorCode code)
92baa4
 {
92baa4
   const char *name = PR_ErrorToName(code);
92baa4
@@ -861,6 +865,60 @@ isTLSIntoleranceError(PRInt32 err)
92baa4
   }
92baa4
 }
92baa4
 
92baa4
+/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
92baa4
+static void nss_update_connecting_state(ssl_connect_state state, void *secret)
92baa4
+{
92baa4
+  struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
92baa4
+  if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
92baa4
+    /* an unrelated error is passing by */
92baa4
+    return;
92baa4
+
92baa4
+  switch(connssl->connecting_state) {
92baa4
+  case ssl_connect_2:
92baa4
+  case ssl_connect_2_reading:
92baa4
+  case ssl_connect_2_writing:
92baa4
+    break;
92baa4
+  default:
92baa4
+    /* we are not called from an SSL handshake */
92baa4
+    return;
92baa4
+  }
92baa4
+
92baa4
+  /* update the state accordingly */
92baa4
+  connssl->connecting_state = state;
92baa4
+}
92baa4
+
92baa4
+/* recv() wrapper we use to detect blocking direction during SSL handshake */
92baa4
+static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
92baa4
+                            PRIntn flags, PRIntervalTime timeout)
92baa4
+{
92baa4
+  const PRRecvFN recv_fn = fd->lower->methods->recv;
92baa4
+  const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
92baa4
+  if(rv < 0)
92baa4
+    /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
92baa4
+    nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
92baa4
+  return rv;
92baa4
+}
92baa4
+
92baa4
+/* send() wrapper we use to detect blocking direction during SSL handshake */
92baa4
+static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
92baa4
+                            PRIntn flags, PRIntervalTime timeout)
92baa4
+{
92baa4
+  const PRSendFN send_fn = fd->lower->methods->send;
92baa4
+  const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
92baa4
+  if(rv < 0)
92baa4
+    /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
92baa4
+    nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
92baa4
+  return rv;
92baa4
+}
92baa4
+
92baa4
+/* close() wrapper to avoid assertion failure due to fd->secret != NULL */
92baa4
+static PRStatus nspr_io_close(PRFileDesc *fd)
92baa4
+{
92baa4
+  const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
92baa4
+  fd->secret = NULL;
92baa4
+  return close_fn(fd);
92baa4
+}
92baa4
+
92baa4
 static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
92baa4
 {
92baa4
   NSSInitParameters initparams;
92baa4
@@ -925,6 +983,21 @@ static CURLcode nss_init(struct SessionHandle *data)
92baa4
     }
92baa4
   }
92baa4
 
92baa4
+  if(nspr_io_identity == PR_INVALID_IO_LAYER) {
92baa4
+    /* allocate an identity for our own NSPR I/O layer */
92baa4
+    nspr_io_identity = PR_GetUniqueIdentity("libcurl");
92baa4
+    if(nspr_io_identity == PR_INVALID_IO_LAYER)
92baa4
+      return CURLE_OUT_OF_MEMORY;
92baa4
+
92baa4
+    /* the default methods just call down to the lower I/O layer */
92baa4
+    memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods);
92baa4
+
92baa4
+    /* override certain methods in the table by our wrappers */
92baa4
+    nspr_io_methods.recv  = nspr_io_recv;
92baa4
+    nspr_io_methods.send  = nspr_io_send;
92baa4
+    nspr_io_methods.close = nspr_io_close;
92baa4
+  }
92baa4
+
92baa4
   rv = nss_init_core(data, cert_dir);
92baa4
   if(rv)
92baa4
     return rv;
92baa4
@@ -1273,6 +1346,8 @@ static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl,
92baa4
 static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
92baa4
 {
92baa4
   PRFileDesc *model = NULL;
92baa4
+  PRFileDesc *nspr_io = NULL;
92baa4
+  PRFileDesc *nspr_io_stub = NULL;
92baa4
   PRBool ssl_no_cache;
92baa4
   PRBool ssl_cbc_random_iv;
92baa4
   struct SessionHandle *data = conn->data;
92baa4
@@ -1433,11 +1508,34 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
92baa4
     goto error;
92baa4
   }
92baa4
 
92baa4
-  /* Import our model socket  onto the existing file descriptor */
92baa4
-  connssl->handle = PR_ImportTCPSocket(sockfd);
92baa4
-  connssl->handle = SSL_ImportFD(model, connssl->handle);
92baa4
-  if(!connssl->handle)
92baa4
+  /* wrap OS file descriptor by NSPR's file descriptor abstraction */
92baa4
+  nspr_io = PR_ImportTCPSocket(sockfd);
92baa4
+  if(!nspr_io)
92baa4
+    goto error;
92baa4
+
92baa4
+  /* create our own NSPR I/O layer */
92baa4
+  nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
92baa4
+  if(!nspr_io_stub) {
92baa4
+    PR_Close(nspr_io);
92baa4
     goto error;
92baa4
+  }
92baa4
+
92baa4
+  /* make the per-connection data accessible from NSPR I/O callbacks */
92baa4
+  nspr_io_stub->secret = (void *)connssl;
92baa4
+
92baa4
+  /* push our new layer to the NSPR I/O stack */
92baa4
+  if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
92baa4
+    PR_Close(nspr_io);
92baa4
+    PR_Close(nspr_io_stub);
92baa4
+    goto error;
92baa4
+  }
92baa4
+
92baa4
+  /* import our model socket onto the current I/O stack */
92baa4
+  connssl->handle = SSL_ImportFD(model, nspr_io);
92baa4
+  if(!connssl->handle) {
92baa4
+    PR_Close(nspr_io);
92baa4
+    goto error;
92baa4
+  }
92baa4
 
92baa4
   PR_Close(model); /* We don't need this any more */
92baa4
   model = NULL;
92baa4
@@ -1480,7 +1578,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
92baa4
   timeout = PR_MillisecondsToInterval((PRUint32) time_left);
92baa4
   if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
92baa4
     if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
92baa4
-      /* TODO: propagate the blocking direction from the NSPR layer */
92baa4
+      /* blocking direction is updated by nss_update_connecting_state() */
92baa4
       return CURLE_AGAIN;
92baa4
     else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
92baa4
       curlerr = CURLE_PEER_FAILED_VERIFICATION;
92baa4
-- 
92baa4
2.1.0
92baa4
92baa4
92baa4
From 813f39b34ecc2634aa8ff332709ddde9235f6891 Mon Sep 17 00:00:00 2001
92baa4
From: Kamil Dudka <kdudka@redhat.com>
92baa4
Date: Mon, 20 Oct 2014 18:18:57 +0200
92baa4
Subject: [PATCH 4/4] nss: reset SSL handshake state machine
92baa4
92baa4
... when the handshake succeeds
92baa4
92baa4
This fixes a connection failure when FTPS handle is reused.
92baa4
92baa4
Upstream-commit: 0aecdf682895b42c25b232e91529f48bdf7738b3
92baa4
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
92baa4
---
92baa4
 lib/nss.c | 17 +++++++++--------
92baa4
 1 file changed, 9 insertions(+), 8 deletions(-)
92baa4
92baa4
diff --git a/lib/nss.c b/lib/nss.c
92baa4
index dadeb58..36fa097 100644
92baa4
--- a/lib/nss.c
92baa4
+++ b/lib/nss.c
92baa4
@@ -1360,9 +1360,6 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
92baa4
     SSL_LIBRARY_VERSION_TLS_1_0   /* max */
92baa4
   };
92baa4
 
92baa4
-  if(connssl->state == ssl_connection_complete)
92baa4
-    return CURLE_OK;
92baa4
-
92baa4
   connssl->data = data;
92baa4
 
92baa4
   /* list of all NSS objects we need to destroy in Curl_nss_close() */
92baa4
@@ -1587,10 +1584,6 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
92baa4
     goto error;
92baa4
   }
92baa4
 
92baa4
-  connssl->state = ssl_connection_complete;
92baa4
-  conn->recv[sockindex] = nss_recv;
92baa4
-  conn->send[sockindex] = nss_send;
92baa4
-
92baa4
   display_conn_info(conn, connssl->handle);
92baa4
 
92baa4
   if(data->set.str[STRING_SSL_ISSUERCERT]) {
92baa4
@@ -1626,6 +1619,9 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
92baa4
   const bool blocking = (done == NULL);
92baa4
   CURLcode rv;
92baa4
 
92baa4
+  if(connssl->state == ssl_connection_complete)
92baa4
+    return CURLE_OK;
92baa4
+
92baa4
   if(connssl->connecting_state == ssl_connect_1) {
92baa4
     rv = nss_setup_connect(conn, sockindex);
92baa4
     if(rv)
92baa4
@@ -1665,7 +1661,12 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
92baa4
     /* signal completed SSL handshake */
92baa4
     *done = TRUE;
92baa4
 
92baa4
-  connssl->connecting_state = ssl_connect_done;
92baa4
+  connssl->state = ssl_connection_complete;
92baa4
+  conn->recv[sockindex] = nss_recv;
92baa4
+  conn->send[sockindex] = nss_send;
92baa4
+
92baa4
+  /* ssl_connect_done is never used outside, go back to the initial state */
92baa4
+  connssl->connecting_state = ssl_connect_1;
92baa4
   return CURLE_OK;
92baa4
 }
92baa4
 
92baa4
-- 
92baa4
2.1.0
92baa4