cURL / Mailing Lists / curl-library / Single Mail

curl-library

[PATCH 2/2] nss: implement non-blocking SSL handshake

From: Kamil Dudka <kdudka_at_redhat.com>
Date: Thu, 17 Apr 2014 15:13:26 +0200

---
 RELEASE-NOTES   |    1 +
 lib/urldata.h   |    1 +
 lib/vtls/nss.c  |   57 ++++++++++++++++++++++++++++++++++++++++++++++--------
 lib/vtls/nssg.h |    1 +
 4 files changed, 51 insertions(+), 9 deletions(-)
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index ed12421..b79b5d9 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -13,6 +13,7 @@ This release includes the following changes:
  o CURLOPT_HEADEROPT: added
  o curl: add --proxy-header
  o sasl: Added support for DIGEST-MD5 via Windows SSPI
+ o nss: implement non-blocking SSL handshake
  o 
 
 This release includes the following bugfixes:
diff --git a/lib/urldata.h b/lib/urldata.h
index 19c79cf..ec48f65 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -318,6 +318,7 @@ struct ssl_connect_data {
   struct SessionHandle *data;
   struct curl_llist *obj_list;
   PK11GenericObject *obj_clicert;
+  ssl_connect_state connecting_state;
 #endif /* USE_NSS */
 #ifdef USE_QSOSSL
   SSLHandle *handle;
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index 455648c..8d00488 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -1611,7 +1611,10 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
   /* Force the handshake now */
   timeout = PR_MillisecondsToInterval((PRUint32) time_left);
   if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
-    if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
+    if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
+      /* TODO: propagate the blocking direction from the NSPR layer */
+      return CURLE_AGAIN;
+    else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
       curlerr = CURLE_PEER_FAILED_VERIFICATION;
     else if(conn->data->set.ssl.certverifyresult!=0)
       curlerr = CURLE_SSL_CACERT;
@@ -1649,32 +1652,68 @@ error:
   return nss_fail_connect(connssl, data, curlerr);
 }
 
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
+                                   bool *done)
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct SessionHandle *data = conn->data;
+  const bool blocking = (done == NULL);
   CURLcode rv;
 
-  rv = nss_setup_connect(conn, sockindex);
-  if(rv)
-    return rv;
+  if(connssl->connecting_state == ssl_connect_1) {
+    rv = nss_setup_connect(conn, sockindex);
+    if(rv)
+      /* we do not expect CURLE_AGAIN from nss_setup_connect() */
+      return rv;
+
+    if(!blocking) {
+      /* in non-blocking mode, set NSS non-blocking mode before handshake */
+      rv = nss_set_nonblock(connssl, data);
+      if(rv)
+        return rv;
+    }
+
+    connssl->connecting_state = ssl_connect_2;
+  }
 
   rv = nss_do_connect(conn, sockindex);
   switch(rv) {
   case CURLE_OK:
     break;
+  case CURLE_AGAIN:
+    if(!blocking)
+      /* CURLE_AGAIN in non-blocking mode is not an error */
+      return CURLE_OK;
+    /* fall through */
   default:
     return rv;
   }
 
-  /* switch the SSL socket into non-blocking mode */
-  rv = nss_set_nonblock(connssl, data);
-  if(rv)
-    return rv;
+  if(blocking) {
+    /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
+    rv = nss_set_nonblock(connssl, data);
+    if(rv)
+      return rv;
+  }
+  else
+    /* signal completed SSL handshake */
+    *done = TRUE;
 
+  connssl->connecting_state = ssl_connect_done;
   return CURLE_OK;
 }
 
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+{
+  return nss_connect_common(conn, sockindex, /* blocking */ NULL);
+}
+
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
+                                      int sockindex, bool *done)
+{
+  return nss_connect_common(conn, sockindex, done);
+}
+
 static ssize_t nss_send(struct connectdata *conn,  /* connection data */
                         int sockindex,             /* socketindex */
                         const void *mem,           /* send this data */
diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h
index 38181a9..21e96ce 100644
--- a/lib/vtls/nssg.h
+++ b/lib/vtls/nssg.h
@@ -68,6 +68,7 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */
 #define curlssl_init Curl_nss_init
 #define curlssl_cleanup Curl_nss_cleanup
 #define curlssl_connect Curl_nss_connect
+#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking
 
 /* NSS has its own session ID cache */
 #define curlssl_session_free(x) Curl_nop_stmt
-- 
1.7.1
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2014-04-17