Hello,

I updated the checks as Kamil suggested. Now False Start is only used with TLS
1.2, ECDHE and AES GCM like in newer firefox versions. This kind of reduces the
False Start usability, since NSS doesn't enable ECC ciphers by default and they
need to manually selected like so:

> $ src/curl -v https://ghedini.me --ciphers ecdhe_rsa_aes_128_gcm_sha_256 
> --false-start

But this may change in the future I suppose. Also, AFAICT NSS doesn't support
AES 256 GCM, so there's that too, but I guess that in most servers if AES 256
is enabled, AES 128 will be as well.

See attached patches.

Cheers
From 4bb04cf72d43bf5c2ca27c1cdceb7693e08d8918 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 31fa7d6efe91f03db96e8e18402089030e7da54e 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  | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/vtls/nssg.h |  3 +++
 2 files changed, 81 insertions(+)

diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index d1309dd..a120ffe 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -728,6 +728,64 @@ 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;
+
+  /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
+   * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
+   */
+  if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
+    goto end;
+
+  /* Only allow ECDHE key exchange algorithm.
+   * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
+  if(cipherInfo.keaType != ssl_kea_ecdh)
+    goto end;
+
+  /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
+   * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
+   * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
+  if(cipherInfo.symCipher != ssl_calg_aes_gcm)
+    goto end;
+
+  /* Enforce ALPN or NPN to do False Start, as an indicator of server
+   * compatibility. */
+  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 +1715,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 +2004,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 ff0ceeeee366eec0ba7042699f88ce3135be26ea 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