Bug 525092: Support TLS false start. The patch is contributed by Adam NSS_3_12_BRANCH NSS_3_12_8_BETA1
authorwtc%google.com
Sat, 31 Jul 2010 04:33:52 +0000
branchNSS_3_12_BRANCH
changeset 9728 f80a8570054ee72693fbb4dcc7c8fdd61ca3fe86
parent 9727 e1b664e6bf6927cda62375f960970e0561365ac9
child 9730 e8e98f559ebceca911ed9cf6fece722a8d1078e3
push idunknown
push userunknown
push dateunknown
bugs525092
Bug 525092: Support TLS false start. The patch is contributed by Adam Langley of Google <agl@chromium.org>. r=wtc. Modified Files: Tag: NSS_3_12_BRANCH cmd/strsclnt/strsclnt.c cmd/tstclnt/tstclnt.c lib/ssl/ssl.h lib/ssl/ssl3con.c lib/ssl/ssl3gthr.c lib/ssl/sslimpl.h lib/ssl/sslsecur.c lib/ssl/sslsock.c tests/ssl/sslstress.txt
security/nss/cmd/strsclnt/strsclnt.c
security/nss/cmd/tstclnt/tstclnt.c
security/nss/lib/ssl/ssl.h
security/nss/lib/ssl/ssl3con.c
security/nss/lib/ssl/ssl3gthr.c
security/nss/lib/ssl/sslimpl.h
security/nss/lib/ssl/sslsecur.c
security/nss/lib/ssl/sslsock.c
security/nss/tests/ssl/sslstress.txt
--- a/security/nss/cmd/strsclnt/strsclnt.c
+++ b/security/nss/cmd/strsclnt/strsclnt.c
@@ -157,16 +157,17 @@ static int failed_already = 0;
 static PRBool disableSSL2     = PR_FALSE;
 static PRBool disableSSL3     = PR_FALSE;
 static PRBool disableTLS      = PR_FALSE;
 static PRBool bypassPKCS11    = PR_FALSE;
 static PRBool disableLocking  = PR_FALSE;
 static PRBool ignoreErrors    = PR_FALSE;
 static PRBool enableSessionTickets = PR_FALSE;
 static PRBool enableCompression    = PR_FALSE;
+static PRBool enableFalseStart     = PR_FALSE;
 
 PRIntervalTime maxInterval    = PR_INTERVAL_NO_TIMEOUT;
 
 char * progName;
 
 int	stopping;
 int	verbose;
 SECItem	bigBuf;
@@ -192,17 +193,18 @@ Usage(const char *progName)
 	"       -N means no session reuse\n"
 	"       -P means do a specified percentage of full handshakes (0-100)\n"
         "       -2 means disable SSL2\n"
         "       -3 means disable SSL3\n"
         "       -T means disable TLS\n"
         "       -U means enable throttling up threads\n"
 	"       -B bypasses the PKCS11 layer for SSL encryption and MACing\n"
 	"       -u enable TLS Session Ticket extension\n"
-	"       -z enable compression\n",
+	"       -z enable compression\n"
+	"       -g enable false start\n",
 	progName);
     exit(1);
 }
 
 
 static void
 errWarn(char * funcString)
 {
@@ -1239,16 +1241,22 @@ client_main(
     }
 
     if (enableCompression) {
 	rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
 	if (rv != SECSuccess)
 	    errExit("SSL_OptionSet SSL_ENABLE_DEFLATE");
     }
 
+    if (enableFalseStart) {
+	rv = SSL_OptionSet(model_sock, SSL_ENABLE_FALSE_START, PR_TRUE);
+	if (rv != SECSuccess)
+	    errExit("SSL_OptionSet SSL_ENABLE_FALSE_START");
+    }
+
     SSL_SetURL(model_sock, hostName);
 
     SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, 
 			(void *)CERT_GetDefaultCertDB());
     SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
 
     SSL_GetClientAuthDataHook(model_sock, StressClient_GetClientAuthData, (void*)Cert_And_Key);
 
@@ -1349,17 +1357,17 @@ main(int argc, char **argv)
 
     tmp      = strrchr(argv[0], '/');
     tmp      = tmp ? tmp + 1 : argv[0];
     progName = strrchr(tmp, '\\');
     progName = progName ? progName + 1 : tmp;
  
 
     optstate = PL_CreateOptState(argc, argv,
-                                 "23BC:DNP:TUW:a:c:d:f:in:op:qst:uvw:z");
+                                 "23BC:DNP:TUW:a:c:d:f:gin:op:qst:uvw:z");
     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
 	switch(optstate->option) {
 
 	case '2': disableSSL2 = PR_TRUE; break;
 
 	case '3': disableSSL3 = PR_TRUE; break;
 
 	case 'B': bypassPKCS11 = PR_TRUE; break;
@@ -1379,16 +1387,18 @@ main(int argc, char **argv)
 	case 'a': sniHostName = PL_strdup(optstate->value); break;
 
 	case 'c': connections = PORT_Atoi(optstate->value); break;
 
 	case 'd': dir = optstate->value; break;
 
 	case 'f': fileName = optstate->value; break;
 
+	case 'g': enableFalseStart = PR_TRUE; break;
+
 	case 'i': ignoreErrors = PR_TRUE; break;
 
         case 'n': nickName = PL_strdup(optstate->value); break;
 
 	case 'o': MakeCertOK++; break;
 
 	case 'p': port = PORT_Atoi(optstate->value); break;
 
--- a/security/nss/cmd/tstclnt/tstclnt.c
+++ b/security/nss/cmd/tstclnt/tstclnt.c
@@ -220,16 +220,17 @@ static void Usage(const char *progName)
     fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
     fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
     fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
     fprintf(stderr, "%-20s Use export policy.\n", "-x");
     fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
     fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
     fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
     fprintf(stderr, "%-20s Enable compression.\n", "-z");
+    fprintf(stderr, "%-20s Enable false start.\n", "-g");
     fprintf(stderr, "%-20s Letter(s) chosen from the following list\n", 
                     "-c ciphers");
     fprintf(stderr, 
 "A    SSL2 RC4 128 WITH MD5\n"
 "B    SSL2 RC4 128 EXPORT40 WITH MD5\n"
 "C    SSL2 RC2 128 CBC WITH MD5\n"
 "D    SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
 "E    SSL2 DES 64 CBC WITH MD5\n"
@@ -516,16 +517,17 @@ int main(int argc, char **argv)
     int                disableSSL2 = 0;
     int                disableSSL3 = 0;
     int                disableTLS  = 0;
     int                bypassPKCS11 = 0;
     int                disableLocking = 0;
     int                useExportPolicy = 0;
     int                enableSessionTickets = 0;
     int                enableCompression = 0;
+    int                enableFalseStart = 0;
     PRSocketOptionData opt;
     PRNetAddr          addr;
     PRPollDesc         pollset[2];
     PRBool             pingServerFirst = PR_FALSE;
     PRBool             clientSpeaksFirst = PR_FALSE;
     PRBool             wrStarted = PR_FALSE;
     PRBool             skipProtoHeader = PR_FALSE;
     int                headerSeparatorPtrnId = 0;
@@ -546,17 +548,17 @@ int main(int argc, char **argv)
     if (tmp && tmp[0]) {
        int sec = PORT_Atoi(tmp);
        if (sec > 0) {
            maxInterval = PR_SecondsToInterval(sec);
        }
     }
 
     optstate = PL_CreateOptState(argc, argv,
-                                 "23BSTW:a:c:d:fh:m:n:op:qr:suvw:xz");
+                                 "23BSTW:a:c:d:fgh:m:n:op:qr:suvw:xz");
     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
 	switch (optstate->option) {
 	  case '?':
 	  default : Usage(progName); 			break;
 
           case '2': disableSSL2 = 1; 			break;
 
           case '3': disableSSL3 = 1; 			break;
@@ -573,16 +575,18 @@ int main(int argc, char **argv)
                         hs2SniHostName =  PORT_Strdup(optstate->value);
                     } else {
                         Usage(progName);
                     }
                     break;
 
           case 'c': cipherString = PORT_Strdup(optstate->value); break;
 
+          case 'g': enableFalseStart = 1; 		break;
+
           case 'd': certDir = PORT_Strdup(optstate->value);   break;
 
           case 'f': clientSpeaksFirst = PR_TRUE;        break;
 
           case 'h': host = PORT_Strdup(optstate->value);	break;
 
 	  case 'm':
 	    multiplier = atoi(optstate->value);
@@ -858,17 +862,24 @@ int main(int argc, char **argv)
     }
 
     /* enable compression. */
     rv = SSL_OptionSet(s, SSL_ENABLE_DEFLATE, enableCompression);
     if (rv != SECSuccess) {
 	SECU_PrintError(progName, "error enabling compression");
 	return 1;
     }
-               
+
+    /* enable false start. */
+    rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
+    if (rv != SECSuccess) {
+	SECU_PrintError(progName, "error enabling false start");
+	return 1;
+    }
+
     SSL_SetPKCS11PinArg(s, &pwdata);
 
     SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
     if (override) {
 	SSL_BadCertHook(s, ownBadCertHandler, NULL);
     }
     SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
     SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
--- a/security/nss/lib/ssl/ssl.h
+++ b/security/nss/lib/ssl/ssl.h
@@ -123,16 +123,27 @@ SSL_IMPORT PRFileDesc *SSL_ImportFD(PRFi
 #define SSL_ENABLE_DEFLATE             19 /* Enable TLS compression with    */
                                           /* DEFLATE (off by default)       */
 #define SSL_ENABLE_RENEGOTIATION       20 /* Values below (default: never)  */
 #define SSL_REQUIRE_SAFE_NEGOTIATION   21 /* Peer must send Signaling       */
 					  /* Cipher Suite Value (SCSV) or   */
                                           /* Renegotiation  Info (RI)       */
 					  /* extension in ALL handshakes.   */
                                           /* default: off                   */
+#define SSL_ENABLE_FALSE_START         22 /* Enable SSL false start (off by */
+                                          /* default, applies only to       */
+                                          /* clients). False start is a     */
+/* mode where an SSL client will start sending application data before      */
+/* verifying the server's Finished message. This means that we could end up */
+/* sending data to an imposter. However, the data will be encrypted and     */
+/* only the true server can derive the session key. Thus, so long as the    */
+/* cipher isn't broken this is safe. Because of this, False Start will only */
+/* occur on RSA or DH ciphersuites where the cipher's key length is >= 80   */
+/* bits. The advantage of False Start is that it saves a round trip for     */
+/* client-speaks-first protocols when performing a full handshake.          */
 
 #ifdef SSL_DEPRECATED_FUNCTION 
 /* Old deprecated function names */
 SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRBool on);
 SSL_IMPORT SECStatus SSL_EnableDefault(int option, PRBool on);
 #endif
 
 /* New function names */
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -5660,17 +5660,27 @@ ssl3_RestartHandshakeAfterCertReq(sslSoc
 		rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf);
 	    }
 	    ssl_ReleaseRecvBufLock(ss);
 	}
     }
     return rv;
 }
 
-
+PRBool
+ssl3_CanFalseStart(sslSocket *ss) {
+    return ss->opt.enableFalseStart &&
+	   !ss->sec.isServer &&
+	   !ss->ssl3.hs.isResuming &&
+	   ss->ssl3.cwSpec &&
+	   ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 &&
+	   (ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_rsa ||
+	    ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh  ||
+	    ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh);
+}
 
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Server Hello Done message.
  * Caller must hold Handshake and RecvBuf locks.
  */
 static SECStatus
 ssl3_HandleServerHelloDone(sslSocket *ss)
 {
@@ -5732,16 +5742,22 @@ ssl3_HandleServerHelloDone(sslSocket *ss
     }
 
     ssl_ReleaseXmitBufLock(ss);		/*******************************/
 
     if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
 	ss->ssl3.hs.ws = wait_new_session_ticket;
     else
 	ss->ssl3.hs.ws = wait_change_cipher;
+
+    /* Do the handshake callback for sslv3 here, if we can false start. */
+    if (ss->handshakeCallback != NULL && ssl3_CanFalseStart(ss)) {
+	(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+    }
+
     return SECSuccess;
 
 loser:
     ssl_ReleaseXmitBufLock(ss);
     return rv;
 }
 
 /*
@@ -8471,18 +8487,18 @@ xmit_loser:
 	 * The connection continues normally however.
 	 */
 	if (rv == SECSuccess) {
 	    (*ss->sec.cache)(sid);
 	}
     }
     ss->ssl3.hs.ws = idle_handshake;
 
-    /* Do the handshake callback for sslv3 here. */
-    if (ss->handshakeCallback != NULL) {
+    /* Do the handshake callback for sslv3 here, if we cannot false start. */
+    if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
 	(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
     }
 
     return SECSuccess;
 }
 
 /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
  * hanshake message.
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -183,36 +183,52 @@ ssl3_GatherData(sslSocket *ss, sslGather
  *
  * Caller must hold the recv buf lock.
  */
 int
 ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
 {
     SSL3Ciphertext cText;
     int            rv;
+    PRBool         canFalseStart = PR_FALSE;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     do {
 	/* bring in the next sslv3 record. */
 	rv = ssl3_GatherData(ss, &ss->gs, flags);
 	if (rv <= 0) {
 	    return rv;
 	}
 	
 	/* decipher it, and handle it if it's a handshake. 
 	 * If it's application data, ss->gs.buf will not be empty upon return. 
+	 * If it's a change cipher spec, alert, or handshake message,
+	 * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess.
 	 */
 	cText.type    = (SSL3ContentType)ss->gs.hdr[0];
 	cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
 	cText.buf     = &ss->gs.inbuf;
 	rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
 	if (rv < 0) {
 	    return ss->recvdCloseNotify ? 0 : rv;
 	}
-    } while (ss->ssl3.hs.ws != idle_handshake && ss->gs.buf.len == 0);
+
+	/* If we kicked off a false start in ssl3_HandleServerHelloDone, break
+	 * out of this loop early without finishing the handshake.
+	 */
+	if (ss->opt.enableFalseStart) {
+	    ssl_GetSSL3HandshakeLock(ss);
+	    canFalseStart = (ss->ssl3.hs.ws == wait_change_cipher ||
+			     ss->ssl3.hs.ws == wait_new_session_ticket) &&
+		            ssl3_CanFalseStart(ss);
+	    ssl_ReleaseSSL3HandshakeLock(ss);
+	}
+    } while (ss->ssl3.hs.ws != idle_handshake &&
+             !canFalseStart &&
+             ss->gs.buf.len == 0);
 
     ss->gs.readOffset = 0;
     ss->gs.writeOffset = ss->gs.buf.len;
     return 1;
 }
 
 /* Repeatedly gather in a record and when complete, Handle that record.
  * Repeat this until some application data is received.
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -328,16 +328,17 @@ typedef struct sslOptionsStr {
     unsigned int detectRollBack  	: 1;  /* 14 */
     unsigned int noStepDown             : 1;  /* 15 */
     unsigned int bypassPKCS11           : 1;  /* 16 */
     unsigned int noLocks                : 1;  /* 17 */
     unsigned int enableSessionTickets   : 1;  /* 18 */
     unsigned int enableDeflate          : 1;  /* 19 */
     unsigned int enableRenegotiation    : 2;  /* 20-21 */
     unsigned int requireSafeNegotiation : 1;  /* 22 */
+    unsigned int enableFalseStart       : 1;  /* 23 */
 } sslOptions;
 
 typedef enum { sslHandshakingUndetermined = 0,
 	       sslHandshakingAsClient,
 	       sslHandshakingAsServer 
 } sslHandshakingType;
 
 typedef struct sslServerCertsStr {
@@ -1245,16 +1246,18 @@ extern int       ssl3_SendApplicationDat
 extern PRBool    ssl_FdIsBlocking(PRFileDesc *fd);
 
 extern PRBool    ssl_SocketIsBlocking(sslSocket *ss);
 
 extern void      ssl_SetAlwaysBlock(sslSocket *ss);
 
 extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
 
+extern PRBool    ssl3_CanFalseStart(sslSocket *ss);
+
 #define SSL_LOCK_READER(ss)		if (ss->recvLock) PZ_Lock(ss->recvLock)
 #define SSL_UNLOCK_READER(ss)		if (ss->recvLock) PZ_Unlock(ss->recvLock)
 #define SSL_LOCK_WRITER(ss)		if (ss->sendLock) PZ_Lock(ss->sendLock)
 #define SSL_UNLOCK_WRITER(ss)		if (ss->sendLock) PZ_Unlock(ss->sendLock)
 
 #define ssl_Get1stHandshakeLock(ss)     \
     { if (!ss->opt.noLocks) PZ_EnterMonitor((ss)->firstHandshakeLock); }
 #define ssl_Release1stHandshakeLock(ss) \
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -1194,18 +1194,27 @@ ssl_SecureSend(sslSocket *ss, const unsi
     if (rv < 0) {
 	goto done;
     }
 
     if (len > 0) 
     	ss->writerThread = PR_GetCurrentThread();
     /* If any of these is non-zero, the initial handshake is not done. */
     if (!ss->firstHsDone) {
+	PRBool canFalseStart = PR_FALSE;
 	ssl_Get1stHandshakeLock(ss);
-	if (ss->handshake || ss->nextHandshake || ss->securityHandshake) {
+	if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+	    (ss->ssl3.hs.ws == wait_change_cipher ||
+	     ss->ssl3.hs.ws == wait_finished ||
+	     ss->ssl3.hs.ws == wait_new_session_ticket) &&
+	    ssl3_CanFalseStart(ss)) {
+	    canFalseStart = PR_TRUE;
+	}
+	if (!canFalseStart &&
+	    (ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
 	    rv = ssl_Do1stHandshake(ss);
 	}
 	ssl_Release1stHandshakeLock(ss);
     }
     if (rv < 0) {
     	ss->writerThread = NULL;
 	goto done;
     }
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -178,16 +178,17 @@ static sslOptions ssl_defaults = {
     PR_TRUE,	/* detectRollBack     */
     PR_FALSE,   /* noStepDown         */
     PR_FALSE,   /* bypassPKCS11       */
     PR_FALSE,   /* noLocks            */
     PR_FALSE,   /* enableSessionTickets */
     PR_FALSE,   /* enableDeflate      */
     2,          /* enableRenegotiation (default: requires extension) */
     PR_FALSE,   /* requireSafeNegotiation */
+    PR_FALSE,   /* enableFalseStart   */
 };
 
 sslSessionIDLookupFunc  ssl_sid_lookup;
 sslSessionIDCacheFunc   ssl_sid_cache;
 sslSessionIDUncacheFunc ssl_sid_uncache;
 
 static PRBool ssl_inited = PR_FALSE;
 static PRDescIdentity ssl_layer_id;
@@ -723,16 +724,20 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 wh
       case SSL_ENABLE_RENEGOTIATION:
 	ss->opt.enableRenegotiation = on;
 	break;
 
       case SSL_REQUIRE_SAFE_NEGOTIATION:
 	ss->opt.requireSafeNegotiation = on;
 	break;
 
+      case SSL_ENABLE_FALSE_START:
+	ss->opt.enableFalseStart = on;
+	break;
+
       default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	rv = SECFailure;
     }
 
     /* We can't use the macros for releasing the locks here,
      * because ss->opt.noLocks might have changed just above.
      * We must release these locks (monitors) here, if we aquired them above,
@@ -786,16 +791,17 @@ SSL_OptionGet(PRFileDesc *fd, PRInt32 wh
     case SSL_ENABLE_SESSION_TICKETS:
 	on = ss->opt.enableSessionTickets;
 	break;
     case SSL_ENABLE_DEFLATE:      on = ss->opt.enableDeflate;      break;
     case SSL_ENABLE_RENEGOTIATION:     
                                   on = ss->opt.enableRenegotiation; break;
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ss->opt.requireSafeNegotiation; break;
+    case SSL_ENABLE_FALSE_START:  on = ss->opt.enableFalseStart;   break;
 
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	rv = SECFailure;
     }
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_Release1stHandshakeLock(ss);
@@ -836,16 +842,17 @@ SSL_OptionGetDefault(PRInt32 which, PRBo
 	on = ssl_defaults.enableSessionTickets;
 	break;
     case SSL_ENABLE_DEFLATE:      on = ssl_defaults.enableDeflate;      break;
     case SSL_ENABLE_RENEGOTIATION:     
                                   on = ssl_defaults.enableRenegotiation; break;
     case SSL_REQUIRE_SAFE_NEGOTIATION: 
                                   on = ssl_defaults.requireSafeNegotiation; 
 				  break;
+    case SSL_ENABLE_FALSE_START:  on = ssl_defaults.enableFalseStart;   break;
 
     default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	rv = SECFailure;
     }
 
     *pOn = on;
     return rv;
@@ -979,16 +986,20 @@ SSL_OptionSetDefault(PRInt32 which, PRBo
       case SSL_ENABLE_RENEGOTIATION:
 	ssl_defaults.enableRenegotiation = on;
 	break;
 
       case SSL_REQUIRE_SAFE_NEGOTIATION:
 	ssl_defaults.requireSafeNegotiation = on;
 	break;
 
+      case SSL_ENABLE_FALSE_START:
+	ssl_defaults.enableFalseStart = on;
+	break;
+
       default:
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return SECFailure;
     }
     return SECSuccess;
 }
 
 /* function tells us if the cipher suite is one that we no longer support. */
--- a/security/nss/tests/ssl/sslstress.txt
+++ b/security/nss/tests/ssl/sslstress.txt
@@ -37,30 +37,34 @@
 #
 #        expected
 # Enable  return  server     client                         Test Case name
 #  ECC    value   params     params
 # ------- ------  ------     ------                         ---------------
   noECC     0      _         -c_1000_-C_A                  Stress SSL2 RC4 128 with MD5
   noECC     0      _         -c_1000_-C_c_-T               Stress SSL3 RC4 128 with MD5
   noECC     0      _         -c_1000_-C_c                  Stress TLS  RC4 128 with MD5
+  noECC     0      _         -c_1000_-C_c_-g               Stress TLS  RC4 128 with MD5 (false start)
   noECC     0      -u        -2_-c_1000_-C_c_-u            Stress TLS  RC4 128 with MD5 (session ticket)
   noECC     0      -z        -2_-c_1000_-C_c_-z            Stress TLS  RC4 128 with MD5 (compression)
   noECC     0      -u_-z     -2_-c_1000_-C_c_-u_-z         Stress TLS  RC4 128 with MD5 (session ticket, compression)
+  noECC     0      -u_-z     -2_-c_1000_-C_c_-u_-z_-g      Stress TLS  RC4 128 with MD5 (session ticket, compression, false start)
   SNI       0      -u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI)
 
 #
 # add client auth versions here...
 #
   noECC     0      -r_-r     -c_100_-C_A_-N_-n_TestUser    Stress SSL2 RC4 128 with MD5 (no reuse, client auth)
   noECC     0      -r_-r     -c_100_-C_c_-T_-N_-n_TestUser Stress SSL3 RC4 128 with MD5 (no reuse, client auth)
   noECC     0      -r_-r     -c_100_-C_c_-N_-n_TestUser    Stress TLS RC4 128 with MD5 (no reuse, client auth)
   noECC     0      -r_-r_-u  -2_-c_100_-C_c_-n_TestUser_-u Stress TLS RC4 128 with MD5 (session ticket, client auth)
   noECC     0      -r_-r_-z  -2_-c_100_-C_c_-n_TestUser_-z Stress TLS RC4 128 with MD5 (compression, client auth)
+  noECC     0      -r_-r_-z  -2_-c_100_-C_c_-n_TestUser_-z_-g Stress TLS RC4 128 with MD5 (compression, client auth, false start)
   noECC     0   -r_-r_-u_-z  -2_-c_100_-C_c_-n_TestUser_-u_-z Stress TLS RC4 128 with MD5 (session ticket, compression, client auth)
+  noECC     0   -r_-r_-u_-z  -2_-c_100_-C_c_-n_TestUser_-u_-z_-g Stress TLS RC4 128 with MD5 (session ticket, compression, client auth, false start)
   SNI       0   -r_-r_-u_-a_Host-sni.Dom -2_-3_-c_1000_-C_c_-u Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth, default virt host)
   SNI       0   -r_-r_-u_-a_Host-sni.Dom_-k_Host-sni.Dom -2_-3_-c_1000_-C_c_-u_-a_Host-sni.Dom Stress TLS RC4 128 with MD5 (session ticket, SNI, client auth, change virt host)
 
 #
 # ############################ ECC ciphers ############################
 #
    ECC      0      -c_:C009  -c_100_-C_:C009_-N_-T  Stress SSL3 ECDHE-ECDSA AES 128 CBC with SHA (no reuse)
    ECC      0      -c_:C013  -c_1000_-C_:C013_-T    Stress SSL3 ECDHE-RSA   AES 128 CBC with SHA