Hello,

I updated the TLS False Start patches I sent a while back to include the various
checks as previously discussed. My implementation now matches the behaviour of
firefox (in fact it's in part the same code).

I've also looked at other TLS implementations, but besides SecureTransport (the
OS X thing) I could not find any that support this. There is a patch for OpenSSL
floating around though [0] which, AFAICT, is available in the Android OpenSSL
build and in BoringSSL, but I'm not sure if it makes sense to implement support
for it in curl just yet (I'm gonna try to see if the OpenSSL developers want to
merge it).

So anyway, see [1] for a way to test this. Note though that the test doesn't
always work (e.g. with https://google.com) because, I suspect, the server
completes the handshake before curl actually starts sending any data to it (I
may be wrong though). The connection still works fine, so no problems there.

Cheers

[0] 
https://android.googlesource.com/platform/external/openssl/+/master/patches/0002-handshake_cutthrough.patch
[1] http://curl.haxx.se/mail/lib-2015-02/0100.html
From 7a286656ab1285d6534798163e45bf9993dcad2c Mon Sep 17 00:00:00 2001
From: Alessandro Ghedini <[email protected]>
Date: Sat, 14 Feb 2015 16:57:07 +0100
Subject: [PATCH 1/3] url: add CURLOPT_SSL_FALSESTART option

This option can be used to enable/disable TLS False Start defined in the RFC
draft-bmoeller-tls-falsestart.
---
 docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3 | 48 ++++++++++++++++++++++++++++++
 include/curl/curl.h                        |  3 ++
 lib/url.c                                  | 11 +++++++
 lib/urldata.h                              |  1 +
 lib/vtls/vtls.c                            | 12 ++++++++
 lib/vtls/vtls.h                            |  3 ++
 6 files changed, 78 insertions(+)
 create mode 100644 docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3

diff --git a/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3 b/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3
new file mode 100644
index 0000000..7d88fc4
--- /dev/null
+++ b/docs/libcurl/opts/CURLOPT_SSL_FALSESTART.3
@@ -0,0 +1,48 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  Project                     ___| | | |  _ \| |
+.\" *                             / __| | | | |_) | |
+.\" *                            | (__| |_| |  _ <| |___
+.\" *                             \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2015, Daniel Stenberg, <[email protected]>, et al.
+.\" *
+.\" * This software is licensed as described in the file COPYING, which
+.\" * you should have received as part of this distribution. The terms
+.\" * are also available at http://curl.haxx.se/docs/copyright.html.
+.\" *
+.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+.\" * copies of the Software, and permit persons to whom the Software is
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_SSL_FALSESTART 3 "14 Feb 2015" "libcurl 7.41.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_SSL_FALSESTART \- enable TLS false start
+.SH SYNOPSIS
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_SSL_FALSESTART, long enable);
+.SH DESCRIPTION
+Pass a long as parameter set to 1 to enable or 0 to disable.
+
+This option determines whether libcurl should use false start during the TLS
+handshake. False start is a mode where a TLS client will start sending
+application data before verifying the server's Finished message, thus saving a
+round trip when performing a full handshake.
+.SH DEFAULT
+0
+.SH PROTOCOLS
+All TLS based protocols: HTTPS, FTPS, IMAPS, POP3, SMTPS etc.
+.SH EXAMPLE
+TODO
+.SH AVAILABILITY
+Added in 7.42.0. This option is currently only supported by the NSS TLS
+backend.
+.SH RETURN VALUE
+Returns CURLE_OK if false start is supported by the SSL backend, otherwise
+returns CURLE_NOT_BUILT_IN.
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 0a326d3..4fcbd57 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1626,6 +1626,9 @@ typedef enum {
   /* Set if we should verify the certificate status. */
   CINIT(SSL_VERIFYSTATUS, LONG, 232),
 
+  /* Set if we should enable TLS false start. */
+  CINIT(SSL_FALSESTART, LONG, 233),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/lib/url.c b/lib/url.c
index 1b0f211..222367f 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2030,6 +2030,17 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     result = CURLE_NOT_BUILT_IN;
 #endif
     break;
+  case CURLOPT_SSL_FALSESTART:
+    /*
+     * Enable TLS false start.
+     */
+    if(!Curl_ssl_false_start()) {
+      result = CURLE_NOT_BUILT_IN;
+      break;
+    }
+
+    data->set.ssl.falsestart = (0 != va_arg(param, long))?TRUE:FALSE;
+    break;
   case CURLOPT_CERTINFO:
 #ifdef have_curlssl_certinfo
     data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
diff --git a/lib/urldata.h b/lib/urldata.h
index 202d819..fda799b 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -350,6 +350,7 @@ struct ssl_config_data {
   void *fsslctxp;        /* parameter for call back */
   bool sessionid;        /* cache session IDs or not */
   bool certinfo;         /* gather lots of certificate info */
+  bool falsestart;
 
 #ifdef USE_TLS_SRP
   char *username; /* TLS username (for, e.g., SRP) */
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index c411b9a..9db2707 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -858,4 +858,16 @@ bool Curl_ssl_cert_status_request(void)
 #endif
 }
 
+/*
+ * Check whether the SSL backend supports false start.
+ */
+bool Curl_ssl_false_start(void)
+{
+#ifdef curlssl_false_start
+  return curlssl_false_start();
+#else
+  return FALSE;
+#endif
+}
+
 #endif /* USE_SSL */
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index bbaa850..1a5f54f 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -118,6 +118,8 @@ CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey,
 
 bool Curl_ssl_cert_status_request(void);
 
+bool Curl_ssl_false_start(void);
+
 #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
 
 #else
@@ -145,6 +147,7 @@ bool Curl_ssl_cert_status_request(void);
 #define Curl_ssl_kill_session(x) Curl_nop_stmt
 #define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
 #define Curl_ssl_cert_status_request() FALSE
+#define Curl_ssl_false_start() FALSE
 #endif
 
 #endif /* HEADER_CURL_VTLS_H */
-- 
2.1.4

From 7eec429d7ac7cb79ba07e6547c55b1daaa790d72 Mon Sep 17 00:00:00 2001
From: Alessandro Ghedini <[email protected]>
Date: Sat, 14 Feb 2015 16:59:01 +0100
Subject: [PATCH 2/3] nss: add support for TLS False Start

---
 lib/vtls/nss.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/vtls/nssg.h |  3 +++
 2 files changed, 67 insertions(+)

diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index d1309dd..be256e8 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -728,6 +728,50 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg)
   }
 }
 
+static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
+                                       PRBool *canFalseStart)
+{
+  struct connectdata *conn = client_data;
+  struct SessionHandle *data = conn->data;
+
+  SSLChannelInfo channelInfo;
+  SSLCipherSuiteInfo cipherInfo;
+
+  SECStatus rv;
+  PRBool negotiatedExtension;
+
+  *canFalseStart = PR_FALSE;
+
+  if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
+    return SECFailure;
+
+  if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
+                            sizeof(cipherInfo)) != SECSuccess)
+    return SECFailure;
+
+  if(cipherInfo.keaType != ssl_kea_rsa &&
+     cipherInfo.keaType != ssl_kea_dh &&
+     cipherInfo.keaType != ssl_kea_ecdh)
+    goto end;
+
+  rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
+                                        &negotiatedExtension);
+  if(rv != SECSuccess || !negotiatedExtension) {
+    rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
+                                          &negotiatedExtension);
+  }
+
+  if(rv != SECSuccess || !negotiatedExtension)
+    goto end;
+
+  *canFalseStart = PR_TRUE;
+
+  infof(data, "Trying TLS False Start\n");
+
+end:
+  return SECSuccess;
+}
+
 static void display_cert_info(struct SessionHandle *data,
                               CERTCertificate *cert)
 {
@@ -1657,6 +1701,18 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
   }
 #endif
 
+#ifdef SSL_ENABLE_FALSE_START
+  if(data->set.ssl.falsestart) {
+    if(SSL_OptionSet(connssl->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
+        != SECSuccess)
+      goto error;
+
+    if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback,
+        conn) != SECSuccess)
+      goto error;
+  }
+#endif
+
 #if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
   if(data->set.ssl_enable_npn || data->set.ssl_enable_alpn) {
     int cur = 0;
@@ -1934,4 +1990,12 @@ bool Curl_nss_cert_status_request(void)
 #endif
 }
 
+bool Curl_nss_false_start(void) {
+#ifdef SSL_ENABLE_FALSE_START
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
 #endif /* USE_NSS */
diff --git a/lib/vtls/nssg.h b/lib/vtls/nssg.h
index 38e7545..d0e7412 100644
--- a/lib/vtls/nssg.h
+++ b/lib/vtls/nssg.h
@@ -58,6 +58,8 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */
 
 bool Curl_nss_cert_status_request(void);
 
+bool Curl_nss_false_start(void);
+
 /* Set the API backend definition to NSS */
 #define CURL_SSL_BACKEND CURLSSLBACKEND_NSS
 
@@ -88,6 +90,7 @@ bool Curl_nss_cert_status_request(void);
 #define curlssl_random(x,y,z) Curl_nss_random(x,y,z)
 #define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d)
 #define curlssl_cert_status_request() Curl_nss_cert_status_request()
+#define curlssl_false_start() Curl_nss_false_start()
 
 #endif /* USE_NSS */
 #endif /* HEADER_CURL_NSSG_H */
-- 
2.1.4

From c02f6ac7b9679b3b2f8e4fe0d04812c19af8f241 Mon Sep 17 00:00:00 2001
From: Alessandro Ghedini <[email protected]>
Date: Sat, 14 Feb 2015 18:17:04 +0100
Subject: [PATCH 3/3] curl: add --false-start option

---
 docs/curl.1         | 9 +++++++++
 src/tool_cfgable.h  | 2 ++
 src/tool_getparam.c | 5 +++++
 src/tool_help.c     | 1 +
 src/tool_operate.c  | 3 +++
 5 files changed, 20 insertions(+)

diff --git a/docs/curl.1 b/docs/curl.1
index ff1ff57..2846b69 100644
--- a/docs/curl.1
+++ b/docs/curl.1
@@ -562,6 +562,15 @@ or no response at all is received, the verification fails.
 
 This is currently only implemented in the OpenSSL, GnuTLS and NSS backends.
 (Added in 7.41.0)
+.IP "--false-start"
+
+(SSL) Tells curl to use false start during the TLS handshake. False start is a
+mode where a TLS client will start sending application data before verifying
+the server's Finished message, thus saving a round trip when performing a full
+handshake.
+
+This is currently only implemented in the NSS backend.
+(Added in 7.42.0)
 .IP "-f, --fail"
 (HTTP) Fail silently (no output at all) on server errors. This is mostly done
 to better enable scripts etc to better deal with failed attempts. In normal
diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h
index 4008cd0..e851130 100644
--- a/src/tool_cfgable.h
+++ b/src/tool_cfgable.h
@@ -207,6 +207,8 @@ struct OperationConfig {
   bool noalpn;                    /* enable/disable TLS ALPN extension */
   char *unix_socket_path;         /* path to Unix domain socket */
 
+  bool falsestart;
+
   struct GlobalConfig *global;
   struct OperationConfig *prev;
   struct OperationConfig *next;   /* Always last in the struct */
diff --git a/src/tool_getparam.c b/src/tool_getparam.c
index b7c88d8..2773b42 100644
--- a/src/tool_getparam.c
+++ b/src/tool_getparam.c
@@ -218,6 +218,7 @@ static const struct LongShort aliases[]= {
   {"Eo", "login-options",            TRUE},
   {"Ep", "pinnedpubkey",             TRUE},
   {"Eq", "cert-status",              FALSE},
+  {"Er", "false-start",              FALSE},
   {"f",  "fail",                     FALSE},
   {"F",  "form",                     TRUE},
   {"Fs", "form-string",              TRUE},
@@ -1368,6 +1369,10 @@ ParameterError getparameter(char *flag,    /* f or -long-flag */
         config->verifystatus = TRUE;
         break;
 
+      case 'r': /* --false-start */
+        config->falsestart = TRUE;
+        break;
+
       default: /* certificate file */
       {
         char *certname, *passphrase;
diff --git a/src/tool_help.c b/src/tool_help.c
index 4616211..69778b9 100644
--- a/src/tool_help.c
+++ b/src/tool_help.c
@@ -83,6 +83,7 @@ static const char *const helptext[] = {
   "     --environment   Write results to environment variables (RISC OS)",
 #endif
   " -f, --fail          Fail silently (no output at all) on HTTP errors (H)",
+  "     --false-start   Enable TLS False Start.",
   " -F, --form CONTENT  Specify HTTP multipart POST data (H)",
   "     --form-string STRING  Specify HTTP multipart POST data (H)",
   "     --ftp-account DATA  Account data string (F)",
diff --git a/src/tool_operate.c b/src/tool_operate.c
index a875f8d..e2ae22e 100644
--- a/src/tool_operate.c
+++ b/src/tool_operate.c
@@ -1041,6 +1041,9 @@ static CURLcode operate_do(struct GlobalConfig *global,
 
           if(config->verifystatus)
             my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
+
+          if(config->falsestart)
+            my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
         }
 
         if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) {
-- 
2.1.4

Attachment: signature.asc
Description: Digital signature

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to