Bug 713933: Make SSL False Start work with asynchronous certificate validation, r=wtc
authorBrian Smith <brian@briansmith.org>
Thu, 31 Oct 2013 15:40:42 -0700
changeset 10898 1b9c43d28713
parent 10897 834ca86eaa63
child 10899 b45c9b1101aa
push id195
push userbrian@briansmith.org
push date2013-11-01 09:42 +0000
reviewerswtc
bugs713933
Bug 713933: Make SSL False Start work with asynchronous certificate validation, r=wtc
lib/ssl/ssl.def
lib/ssl/ssl.h
lib/ssl/ssl3con.c
lib/ssl/ssl3gthr.c
lib/ssl/sslauth.c
lib/ssl/sslimpl.h
lib/ssl/sslinfo.c
lib/ssl/sslsecur.c
lib/ssl/sslsock.c
--- a/lib/ssl/ssl.def
+++ b/lib/ssl/ssl.def
@@ -161,11 +161,13 @@ SSL_SetSRTPCiphers;
 SSL_PeerStapledOCSPResponses;
 SSL_SetStapledOCSPResponses;
 ;+    local:
 ;+*;
 ;+};
 ;+NSS_3.15.3 {    # NSS 3.15.3 release
 ;+    global:
 SSL_PeerCertificateChain;
+SSL_RecommendedCanFalseStart;
+SSL_SetCanFalseStartCallback;
 ;+    local:
 ;+*;
 ;+};
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -116,24 +116,27 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
 #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.          */
+/* 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. The advantage of false start is that
+ * it saves a round trip for client-speaks-first protocols when performing a
+ * full handshake.
+ *
+ * In addition to enabling this option, the application must register a
+ * callback using the SSL_SetCanFalseStartCallback function.
+ */
 
 /* For SSL 3.0 and TLS 1.0, by default we prevent chosen plaintext attacks
  * on SSL CBC mode cipher suites (see RFC 4346 Section F.3) by splitting
  * non-empty application_data records into two records; the first record has
  * only the first byte of plaintext, and the second has the rest.
  *
  * This only prevents the attack in the sending direction; the connection may
  * still be vulnerable to such attacks if the peer does not implement a similar
@@ -657,24 +660,55 @@ SSL_IMPORT SECStatus SSL_SetMaxServerCac
 /* called in child to inherit SID Cache variables. 
  * If envString is NULL, this function will use the value of the environment
  * variable "SSL_INHERITANCE", otherwise the string value passed in will be 
  * used.
  */
 SSL_IMPORT SECStatus SSL_InheritMPServerSIDCache(const char * envString);
 
 /*
-** Set the callback on a particular socket that gets called when we finish
-** performing a handshake.
+** Set the callback that gets called when a TLS handshake is complete. The
+** handshake callback is called after verifying the peer's Finished message and
+** before processing incoming application data.
+**
+** For the initial handshake: If the handshake false started (see
+** SSL_ENABLE_FALSE_START), then application data may already have been sent
+** before the handshake callback is called. If we did not false start then the
+** callback will get called before any application data is sent.
 */
 typedef void (PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd,
                                                  void *client_data);
 SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd, 
 			          SSLHandshakeCallback cb, void *client_data);
 
+/* Applications that wish to enable TLS false start must set this callback
+** function. NSS will invoke the functon to determine if a particular
+** connection should use false start or not. SECSuccess indicates that the
+** callback completed successfully, and if so *canFalseStart indicates if false
+** start can be used. If the callback does not return SECSuccess then the
+** handshake will be canceled. NSS's recommended criteria can be evaluated by
+** calling SSL_RecommendedCanFalseStart.
+**
+** If no false start callback is registered then false start will never be
+** done, even if the SSL_ENABLE_FALSE_START option is enabled.
+**/
+typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)(
+    PRFileDesc *fd, void *arg, PRBool *canFalseStart);
+
+SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback(
+    PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg);
+
+/* This function sets *canFalseStart according to the recommended criteria for
+** false start. These criteria may change from release to release and may depend
+** on which handshake features have been negotiated and/or properties of the
+** certifciates/keys used on the connection.
+*/
+SSL_IMPORT SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd,
+                                                  PRBool *canFalseStart);
+
 /*
 ** For the server, request a new handshake.  For the client, begin a new
 ** handshake.  If flushCache is non-zero, the SSL3 cache entry will be 
 ** flushed first, ensuring that a full SSL handshake will be done.
 ** If flushCache is zero, and an SSL connection is established, it will 
 ** do the much faster session restart handshake.  This will change the 
 ** session keys without doing another private key operation.
 */
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -2727,17 +2727,17 @@ ssl3_SendRecord(   sslSocket *        ss
     sslBuffer      *          wrBuf 	  = &ss->sec.writeBuf;
     SECStatus                 rv;
     PRInt32                   totalSent   = 0;
     PRBool                    capRecordVersion;
 
     SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
 		SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type),
 		nIn));
-    PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn));
+    PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn));
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
 
     capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
 
     if (capRecordVersion) {
 	/* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
 	 * TLS initial ClientHello. */
@@ -6984,46 +6984,83 @@ loser:
     PORT_SetError(errCode);
     rv = SECFailure;
 done:
     if (arena != NULL)
     	PORT_FreeArena(arena, PR_FALSE);
     return rv;
 }
 
+static SECStatus
+ssl3_CheckFalseStart(sslSocket *ss)
+{
+    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+    PORT_Assert( !ss->ssl3.hs.authCertificatePending );
+    PORT_Assert( !ss->ssl3.hs.canFalseStart );
+
+    if (!ss->canFalseStartCallback) {
+	SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start",
+		    SSL_GETPID(), ss->fd));
+    } else {
+	PRBool maybeFalseStart;
+	SECStatus rv;
+
+	/* An attacker can control the selected ciphersuite so we only wish to
+	 * do False Start in the case that the selected ciphersuite is
+	 * sufficiently strong that the attack can gain no advantage.
+	 * Therefore we always require an 80-bit cipher. */
+        ssl_GetSpecReadLock(ss);
+        maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10;
+        ssl_ReleaseSpecReadLock(ss);
+
+	if (!maybeFalseStart) {
+	    SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher",
+			SSL_GETPID(), ss->fd));
+	} else {
+	    rv = (ss->canFalseStartCallback)(ss->fd,
+					     ss->canFalseStartCallbackData,
+					     &ss->ssl3.hs.canFalseStart);
+	    if (rv == SECSuccess) {
+		SSL_TRC(3, ("%d: SSL[%d]: false start callback returned %s",
+			    SSL_GETPID(), ss->fd,
+			    ss->ssl3.hs.canFalseStart ? "TRUE" : "FALSE"));
+	    } else {
+		SSL_TRC(3, ("%d: SSL[%d]: false start callback failed (%s)",
+			    SSL_GETPID(), ss->fd,
+			    PR_ErrorToName(PR_GetError())));
+	    }
+	    return rv;
+	}
+    }
+
+    ss->ssl3.hs.canFalseStart = PR_FALSE;
+    return SECSuccess;
+}
+
 PRBool
-ssl3_CanFalseStart(sslSocket *ss) {
-    PRBool rv;
+ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss)
+{
+    PRBool result = PR_FALSE;
 
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
 
-    /* XXX: does not take into account whether we are waiting for
-     * SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when
-     * that is done, this function could return different results each time it
-     * would be called.
-     */
-
-    ssl_GetSpecReadLock(ss);
-    rv = ss->opt.enableFalseStart &&
-	 !ss->sec.isServer &&
-	 !ss->ssl3.hs.isResuming &&
-	 ss->ssl3.cwSpec &&
-
-	 /* An attacker can control the selected ciphersuite so we only wish to
-	  * do False Start in the case that the selected ciphersuite is
-	  * sufficiently strong that the attack can gain no advantage.
-	  * Therefore we require an 80-bit cipher and a forward-secret key
-	  * exchange. */
-	 ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10 &&
-	(ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
-	 ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
-	 ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
-	 ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa);
-    ssl_ReleaseSpecReadLock(ss);
-    return rv;
+    switch (ss->ssl3.hs.ws) {
+    case wait_new_session_ticket:
+        result = PR_TRUE;
+        break;
+    case wait_change_cipher:
+        result = !ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn);
+        break;
+    case wait_finished:
+        break;
+    default:
+        PR_NOT_REACHED("ssl3_WaitingForStartOfServerSecondRound");
+    }
+
+    return result;
 }
 
 static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
 
 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
  * ssl3 Server Hello Done message.
  * Caller must hold Handshake and RecvBuf locks.
  */
@@ -7103,16 +7140,19 @@ ssl3_SendClientSecondRound(sslSocket *ss
      */
     if (ss->ssl3.hs.restartTarget) {
 	PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
 	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
 	return SECFailure;
     }
     if (ss->ssl3.hs.authCertificatePending &&
 	(sendClientCert || ss->ssl3.sendEmptyCert || ss->firstHsDone)) {
+	SSL_TRC(3, ("%d: SSL3[%p]: deferring ssl3_SendClientSecondRound because"
+		    " certificate authentication is still pending.",
+		    SSL_GETPID(), ss->fd));
 	ss->ssl3.hs.restartTarget = ssl3_SendClientSecondRound;
 	return SECWouldBlock;
     }
 
     ssl_GetXmitBufLock(ss);		/*******************************/
 
     if (ss->ssl3.sendEmptyCert) {
 	ss->ssl3.sendEmptyCert = PR_FALSE;
@@ -7140,42 +7180,75 @@ ssl3_SendClientSecondRound(sslSocket *ss
         }
     }
 
     rv = ssl3_SendChangeCipherSpecs(ss);
     if (rv != SECSuccess) {
 	goto loser;	/* err code was set. */
     }
 
-    /* XXX: If the server's certificate hasn't been authenticated by this
-     * point, then we may be leaking this NPN message to an attacker.
+    /* This must be done after we've set ss->ssl3.cwSpec in
+     * ssl3_SendChangeCipherSpecs because SSL_GetChannelInfo uses information
+     * from cwSpec. This must be done before we call ssl3_CheckFalseStart
+     * because the false start callback (if any) may need the information from
+     * the functions that depend on this being set.
      */
+    ss->enoughFirstHsDone = PR_TRUE;
+
     if (!ss->firstHsDone) {
+	/* XXX: If the server's certificate hasn't been authenticated by this
+	 * point, then we may be leaking this NPN message to an attacker.
+	 */
 	rv = ssl3_SendNextProto(ss);
 	if (rv != SECSuccess) {
 	    goto loser;	/* err code was set. */
 	}
+
+	if (ss->opt.enableFalseStart) {
+	    if (!ss->ssl3.hs.authCertificatePending) {
+		/* When we fix bug 589047, we will need to know whether we are
+		 * false starting before we try to flush the client second
+		 * round to the network. With that in mind, we purposefully
+		 * call ssl3_CheckFalseStart before calling ssl3_SendFinished,
+		 * which includes a call to ssl3_FlushHandshake, so that
+		 * no application develops a reliance on such flushing being
+		 * done before its false start callback is called.
+		 */
+		ssl_ReleaseXmitBufLock(ss);
+		rv = ssl3_CheckFalseStart(ss);
+		ssl_GetXmitBufLock(ss);
+		if (rv != SECSuccess) {
+		    goto loser;
+		}
+	    } else {
+		/* The certificate authentication and the server's Finished
+		 * message are racing each other. If the certificate
+		 * authentication wins, then we will try to false start in
+		 * ssl3_AuthCertificateComplete.
+		 */
+		SSL_TRC(3, ("%d: SSL3[%p]: deferring false start check because"
+			    " certificate authentication is still pending.",
+			    SSL_GETPID(), ss->fd));
+	    }
+	}
     }
 
     rv = ssl3_SendFinished(ss, 0);
     if (rv != SECSuccess) {
 	goto loser;	/* err code was set. */
     }
 
     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);
-    }
+    PORT_Assert(ssl3_WaitingForStartOfServerSecondRound(ss));
 
     return SECSuccess;
 
 loser:
     ssl_ReleaseXmitBufLock(ss);
     return rv;
 }
 
@@ -9740,23 +9813,16 @@ ssl3_AuthCertificate(sslSocket *ss)
 	    if (ss->sec.isServer) {
 		errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
 		rv = SECFailure;
 		goto loser;
 	    }
 
 	    ss->ssl3.hs.authCertificatePending = PR_TRUE;
 	    rv = SECSuccess;
-
-	    /* XXX: Async cert validation and False Start don't work together
-	     * safely yet; if we leave False Start enabled, we may end up false
-	     * starting (sending application data) before we
-	     * SSL_AuthCertificateComplete has been called.
-	     */
-	    ss->opt.enableFalseStart = PR_FALSE;
 	}
 
 	if (rv != SECSuccess) {
 	    ssl3_SendAlertForCertError(ss, errCode);
 	    goto loser;
 	}
     }
 
@@ -9870,26 +9936,54 @@ ssl3_AuthCertificateComplete(sslSocket *
 
     if (error != 0) {
 	ss->ssl3.hs.restartTarget = ssl3_AlwaysFail;
 	ssl3_SendAlertForCertError(ss, error);
 	rv = SECSuccess;
     } else if (ss->ssl3.hs.restartTarget != NULL) {
 	sslRestartTarget target = ss->ssl3.hs.restartTarget;
 	ss->ssl3.hs.restartTarget = NULL;
+
+	if (target == ssl3_FinishHandshake) {
+	    SSL_TRC(3,("%d: SSL3[%p]: certificate authentication lost the race"
+		       " with peer's finished message", SSL_GETPID(), ss->fd));
+	}
+
 	rv = target(ss);
 	/* Even if we blocked here, we have accomplished enough to claim
 	 * success. Any remaining work will be taken care of by subsequent
 	 * calls to SSL_ForceHandshake/PR_Send/PR_Read/etc. 
 	 */
 	if (rv == SECWouldBlock) {
 	    rv = SECSuccess;
 	}
     } else {
-	rv = SECSuccess;
+	SSL_TRC(3, ("%d: SSL3[%p]: certificate authentication won the race with"
+        	    " peer's finished message", SSL_GETPID(), ss->fd));
+
+	PORT_Assert(!ss->firstHsDone);
+	PORT_Assert(!ss->sec.isServer);
+	PORT_Assert(!ss->ssl3.hs.isResuming);
+	PORT_Assert(ss->ssl3.hs.ws == wait_new_session_ticket ||
+		    ss->ssl3.hs.ws == wait_change_cipher ||
+		    ss->ssl3.hs.ws == wait_finished);
+
+	/* ssl3_SendClientSecondRound deferred the false start check because
+	 * certificate authentication was pending, so we do it now if we still
+         * haven't received any of the server's second round yet.
+	 */
+	if (ss->opt.enableFalseStart &&
+	    !ss->firstHsDone &&
+	    !ss->sec.isServer &&
+	    !ss->ssl3.hs.isResuming &&
+	    ssl3_WaitingForStartOfServerSecondRound(ss)) {
+	    rv = ssl3_CheckFalseStart(ss);
+	} else {
+	    rv = SECSuccess;
+	}
     }
 
 done:
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_ReleaseRecvBufLock(ss);
 
     return rv;
 }
@@ -10340,19 +10434,16 @@ ssl3_HandleFinished(sslSocket *ss, SSL3O
     }
 
 xmit_loser:
     ssl_ReleaseXmitBufLock(ss);	/*************************************/
     if (rv != SECSuccess) {
         return rv;
     }
 
-    ss->gs.writeOffset = 0;
-    ss->gs.readOffset  = 0;
-
     if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) {
 	effectiveExchKeyType = kt_rsa;
     } else {
 	effectiveExchKeyType = ss->ssl3.hs.kea_def->exchKeyType;
     }
 
     if (sid->cached == never_cached && !ss->opt.noCache && ss->sec.cache) {
 	/* fill in the sid */
@@ -10407,38 +10498,38 @@ xmit_loser:
 	ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
 	return SECWouldBlock;
     }
 
     rv = ssl3_FinishHandshake(ss);
     return rv;
 }
 
+/* The return type is SECStatus instead of void because this function needs
+ * to have type sslRestartTarget.
+ */
 SECStatus
 ssl3_FinishHandshake(sslSocket * ss)
 {
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
     PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
 
     /* The first handshake is now completed. */
     ss->handshake           = NULL;
-    ss->firstHsDone         = PR_TRUE;
 
     if (ss->ssl3.hs.cacheSID) {
 	(*ss->sec.cache)(ss->sec.ci.sid);
 	ss->ssl3.hs.cacheSID = PR_FALSE;
     }
 
+    ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
     ss->ssl3.hs.ws = idle_handshake;
 
-    /* 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);
-    }
+    ssl_FinishHandshake(ss);
 
     return SECSuccess;
 }
 
 /* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
  * hanshake message.
  * Caller must hold Handshake and RecvBuf locks.
  */
@@ -11393,17 +11484,16 @@ process_it:
 	/* XXX Send an alert ???  */
 	PORT_SetError(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE);
 	rv = SECFailure;
 	break;
     }
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     return rv;
-
 }
 
 /*
  * Initialization functions
  */
 
 /* Called from ssl3_InitState, immediately below. */
 /* Caller must hold the SpecWriteLock. */
--- a/lib/ssl/ssl3gthr.c
+++ b/lib/ssl/ssl3gthr.c
@@ -270,21 +270,27 @@ dtls_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;
+    PRBool         keepGoing = PR_TRUE;
 
     SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
 
+    /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake,
+     * which requires the 1stHandshakeLock, which must be acquired before the
+     * RecvBufLock.
+     */
+    PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
     do {
 	PRBool handleRecordNow = PR_FALSE;
 
 	ssl_GetSSL3HandshakeLock(ss);
 
 	/* Without this, we may end up wrongly reporting
 	 * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the
 	 * peer while we are waiting to be restarted.
@@ -359,34 +365,62 @@ ssl3_GatherCompleteHandshake(sslSocket *
 		    cText.seq_num.high <<= 8; cText.seq_num.low <<= 8;
 		    cText.seq_num.high |= ss->gs.hdr[3 + i];
 		    cText.seq_num.low |= ss->gs.hdr[7 + i];
 		}
 	    }
 
 	    cText.buf     = &ss->gs.inbuf;
 	    rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf);
+
+	    if (rv == (int) SECSuccess && ss->gs.buf.len > 0) {
+		/* We have application data to return to the application. This
+		 * prioritizes returning application data to the application over
+		 * completing any renegotiation handshake we may be doing.
+		 */
+		PORT_Assert(ss->firstHsDone);
+		PORT_Assert(cText.type == content_application_data);
+		break;
+	    }
 	}
 	if (rv < 0) {
 	    return ss->recvdCloseNotify ? 0 : rv;
 	}
 
-	/* 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);
+	PORT_Assert(keepGoing);
+	ssl_GetSSL3HandshakeLock(ss);
+	if (ss->ssl3.hs.ws == idle_handshake) {
+	    /* We are done with the current handshake so stop trying to
+	     * handshake. Note that it would be safe to test ss->firstHsDone
+	     * instead of ss->ssl3.hs.ws. By testing ss->ssl3.hs.ws instead,
+	     * we prioritize completing a renegotiation handshake over sending
+	     * application data.
+	     */
+	    PORT_Assert(ss->firstHsDone);
+	    PORT_Assert(!ss->ssl3.hs.canFalseStart);
+	    keepGoing = PR_FALSE;
+	} else if (ss->ssl3.hs.canFalseStart) {
+	    /* Prioritize sending application data over trying to complete
+	     * the handshake if we're false starting.
+	     *
+	     * If we were to do this check at the beginning of the loop instead
+	     * of here, then this function would become be a no-op after
+	     * receiving the ServerHelloDone in the false start case, and we
+	     * would never complete the handshake.
+	     */
+	    PORT_Assert(!ss->firstHsDone);
+
+	    if (ssl3_WaitingForStartOfServerSecondRound(ss)) {
+		keepGoing = PR_FALSE;
+	    } else {
+		ss->ssl3.hs.canFalseStart = PR_FALSE;
+	    }
 	}
-    } while (ss->ssl3.hs.ws != idle_handshake &&
-             !canFalseStart &&
-             ss->gs.buf.len == 0);
+	ssl_ReleaseSSL3HandshakeLock(ss);
+    } while (keepGoing);
 
     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.
@@ -399,15 +433,18 @@ ssl3_GatherCompleteHandshake(sslSocket *
  * Called from DoRecv in sslsecur.c
  * Caller must hold the recv buf lock.
  */
 int
 ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
 {
     int            rv;
 
+    /* ssl3_GatherCompleteHandshake requires both of these locks. */
+    PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
     do {
 	rv = ssl3_GatherCompleteHandshake(ss, flags);
     } while (rv > 0 && ss->gs.buf.len == 0);
 
     return rv;
 }
--- a/lib/ssl/sslauth.c
+++ b/lib/ssl/sslauth.c
@@ -95,17 +95,16 @@ SSL_LocalCertificate(PRFileDesc *fd)
 /* NEED LOCKS IN HERE.  */
 SECStatus
 SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
 		   char **ip, char **sp)
 {
     sslSocket *ss;
     const char *cipherName;
     PRBool isDes = PR_FALSE;
-    PRBool enoughFirstHsDone = PR_FALSE;
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
 	SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
 		 SSL_GETPID(), fd));
 	return SECFailure;
     }
 
@@ -113,24 +112,17 @@ SSL_SecurityStatus(PRFileDesc *fd, int *
     if (kp0) *kp0 = 0;
     if (kp1) *kp1 = 0;
     if (ip) *ip = 0;
     if (sp) *sp = 0;
     if (op) {
 	*op = SSL_SECURITY_STATUS_OFF;
     }
 
-    if (ss->firstHsDone) {
-	enoughFirstHsDone = PR_TRUE;
-    } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
-	       ssl3_CanFalseStart(ss)) {
-	enoughFirstHsDone = PR_TRUE;
-    }
-
-    if (ss->opt.useSecurity && enoughFirstHsDone) {
+    if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
 	if (ss->version < SSL_LIBRARY_VERSION_3_0) {
 	    cipherName = ssl_cipherName[ss->sec.cipherType];
 	} else {
 	    cipherName = ssl3_cipherName[ss->sec.cipherType];
 	}
 	PORT_Assert(cipherName);
 	if (cipherName) {
             if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -854,16 +854,18 @@ const ssl3CipherSuiteDef *suite_def;
     PRBool                authCertificatePending;
     /* Which function should SSL_RestartHandshake* call if we're blocked?
      * One of NULL, ssl3_SendClientSecondRound, ssl3_FinishHandshake,
      * or ssl3_AlwaysFail */
     sslRestartTarget      restartTarget;
     /* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
     PRBool                cacheSID;
 
+    PRBool                canFalseStart;   /* Can/did we False Start */
+
     /* clientSigAndHash contains the contents of the signature_algorithms
      * extension (if any) from the client. This is only valid for TLS 1.2
      * or later. */
     SSL3SignatureAndHashAlgorithm *clientSigAndHash;
     unsigned int          numClientSigAndHash;
 
     /* This group of values is used for DTLS */
     PRUint16              sendMessageSeq;  /* The sending message sequence
@@ -1128,16 +1130,20 @@ struct sslSocketStr {
     sslOptions       opt;
     /* Enabled version range */
     SSLVersionRange  vrange;
 
     /* State flags */
     unsigned long    clientAuthRequested;
     unsigned long    delayDisabled;       /* Nagle delay disabled */
     unsigned long    firstHsDone;         /* first handshake is complete. */
+    unsigned long    enoughFirstHsDone;   /* enough of the first handshake is
+					   * done for callbacks to be able to
+					   * retrieve channel security
+					   * parameters from the SSL socket. */
     unsigned long    handshakeBegun;     
     unsigned long    lastWriteBlocked;   
     unsigned long    recvdCloseNotify;    /* received SSL EOF. */
     unsigned long    TCPconnected;       
     unsigned long    appDataBuffered;
     unsigned long    peerRequestedProtection; /* from old renegotiation */
 
     /* version of the protocol to use */
@@ -1168,16 +1174,18 @@ const unsigned char *  preferredCipher;
     SSLGetClientAuthData      getClientAuthData;
     void                     *getClientAuthDataArg;
     SSLSNISocketConfig        sniSocketConfig;
     void                     *sniSocketConfigArg;
     SSLBadCertHandler         handleBadCert;
     void                     *badCertArg;
     SSLHandshakeCallback      handshakeCallback;
     void                     *handshakeCallbackData;
+    SSLCanFalseStartCallback  canFalseStartCallback;
+    void                     *canFalseStartCallbackData;
     void                     *pkcs11PinArg;
     SSLNextProtoCallback      nextProtoCallback;
     void                     *nextProtoArg;
 
     PRIntervalTime            rTimeout; /* timeout for NSPR I/O */
     PRIntervalTime            wTimeout; /* timeout for NSPR I/O */
     PRIntervalTime            cTimeout; /* timeout for NSPR I/O */
 
@@ -1370,17 +1378,29 @@ extern int       ssl3_SendApplicationDat
 extern PRBool    ssl_FdIsBlocking(PRFileDesc *fd);
 
 extern PRBool    ssl_SocketIsBlocking(sslSocket *ss);
 
 extern void      ssl3_SetAlwaysBlock(sslSocket *ss);
 
 extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
 
-extern PRBool    ssl3_CanFalseStart(sslSocket *ss);
+extern void      ssl_FinishHandshake(sslSocket *ss);
+
+/* Returns PR_TRUE if we are still waiting for the server to respond to our
+ * client second round. Once we've received any part of the server's second
+ * round then we don't bother trying to false start since it is almost always
+ * the case that the NewSessionTicket, ChangeCipherSoec, and Finished messages
+ * were sent in the same packet and we want to process them all at the same
+ * time. If we were to try to false start in the middle of the server's second
+ * round, then we would increase the number of I/O operations
+ * (SSL_ForceHandshake/PR_Recv/PR_Send/etc.) needed to finish the handshake.
+ */
+extern PRBool    ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss);
+
 extern SECStatus
 ssl3_CompressMACEncryptRecord(ssl3CipherSpec *   cwSpec,
 		              PRBool             isServer,
 			      PRBool             isDTLS,
 			      PRBool             capRecordVersion,
                               SSL3ContentType    type,
 		              const SSL3Opaque * pIn,
 		              PRUint32           contentLen,
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -21,41 +21,33 @@ ssl_GetCompressionMethodName(SSLCompress
 }
 
 SECStatus 
 SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
 {
     sslSocket *      ss;
     SSLChannelInfo   inf;
     sslSessionID *   sid;
-    PRBool           enoughFirstHsDone = PR_FALSE;
 
     if (!info || len < sizeof inf.length) { 
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return SECFailure;
     }
 
     ss = ssl_FindSocket(fd);
     if (!ss) {
 	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo",
 		 SSL_GETPID(), fd));
 	return SECFailure;
     }
 
     memset(&inf, 0, sizeof inf);
     inf.length = PR_MIN(sizeof inf, len);
 
-    if (ss->firstHsDone) {
-	enoughFirstHsDone = PR_TRUE;
-    } else if (ss->version >= SSL_LIBRARY_VERSION_3_0 &&
-	       ssl3_CanFalseStart(ss)) {
-	enoughFirstHsDone = PR_TRUE;
-    }
-
-    if (ss->opt.useSecurity && enoughFirstHsDone) {
+    if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
         sid = ss->sec.ci.sid;
 	inf.protocolVersion  = ss->version;
 	inf.authKeyBits      = ss->sec.authKeyBits;
 	inf.keaKeyBits       = ss->sec.keaKeyBits;
 	if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
 	    inf.cipherSuite           = ss->sec.cipherType | 0xff00;
 	    inf.compressionMethod     = ssl_compression_null;
 	    inf.compressionMethodName = "N/A";
--- a/lib/ssl/sslsecur.c
+++ b/lib/ssl/sslsecur.c
@@ -92,33 +92,23 @@ ssl_Do1stHandshake(sslSocket *ss)
 	    ss->nextHandshake = 0;
 	}
 	if (ss->handshake == 0) {
 	    /* Previous handshake finished. Switch to security handshake */
 	    ss->handshake = ss->securityHandshake;
 	    ss->securityHandshake = 0;
 	}
 	if (ss->handshake == 0) {
-	    ssl_GetRecvBufLock(ss);
-	    ss->gs.recordLen = 0;
-	    ssl_ReleaseRecvBufLock(ss);
-
-	    SSL_TRC(3, ("%d: SSL[%d]: handshake is completed",
-			SSL_GETPID(), ss->fd));
-            /* call handshake callback for ssl v2 */
-	    /* for v3 this is done in ssl3_HandleFinished() */
-	    if ((ss->handshakeCallback != NULL) && /* has callback */
-		(!ss->firstHsDone) &&              /* only first time */
-		(ss->version < SSL_LIBRARY_VERSION_3_0)) {  /* not ssl3 */
-		ss->firstHsDone     = PR_TRUE;
-		(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+	    /* for v3 this is done in ssl3_FinishHandshake */
+	    if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) {
+		ssl_GetRecvBufLock(ss);
+		ss->gs.recordLen = 0;
+		ssl_FinishHandshake(ss);
+		ssl_ReleaseRecvBufLock(ss);
 	    }
-	    ss->firstHsDone         = PR_TRUE;
-	    ss->gs.writeOffset = 0;
-	    ss->gs.readOffset  = 0;
 	    break;
 	}
 	rv = (*ss->handshake)(ss);
 	++loopCount;
     /* This code must continue to loop on SECWouldBlock, 
      * or any positive value.	See XXX_1 comments.
      */
     } while (rv != SECFailure);  	/* was (rv >= 0); XXX_1 */
@@ -129,16 +119,34 @@ ssl_Do1stHandshake(sslSocket *ss)
 
     if (rv == SECWouldBlock) {
 	PORT_SetError(PR_WOULD_BLOCK_ERROR);
 	rv = SECFailure;
     }
     return rv;
 }
 
+void
+ssl_FinishHandshake(sslSocket *ss)
+{
+    PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
+
+    SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd));
+
+    ss->firstHsDone = PR_TRUE;
+    ss->enoughFirstHsDone = PR_TRUE;
+    ss->gs.writeOffset = 0;
+    ss->gs.readOffset  = 0;
+
+    if (ss->handshakeCallback) {
+	(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+    }
+}
+
 /*
  * Handshake function that blocks.  Used to force a
  * retry on a connection on the next read/write.
  */
 static SECStatus
 ssl3_AlwaysBlock(sslSocket *ss)
 {
     PORT_SetError(PR_WOULD_BLOCK_ERROR);	/* perhaps redundant. */
@@ -201,31 +209,34 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool
 
     SSL_LOCK_READER(ss);
     SSL_LOCK_WRITER(ss);
 
     /* Reset handshake state */
     ssl_Get1stHandshakeLock(ss);
 
     ss->firstHsDone = PR_FALSE;
+    ss->enoughFirstHsDone = PR_FALSE;
     if ( asServer ) {
 	ss->handshake = ssl2_BeginServerHandshake;
 	ss->handshaking = sslHandshakingAsServer;
     } else {
 	ss->handshake = ssl2_BeginClientHandshake;
 	ss->handshaking = sslHandshakingAsClient;
     }
     ss->nextHandshake       = 0;
     ss->securityHandshake   = 0;
 
     ssl_GetRecvBufLock(ss);
     status = ssl_InitGather(&ss->gs);
     ssl_ReleaseRecvBufLock(ss);
 
     ssl_GetSSL3HandshakeLock(ss);
+    ss->ssl3.hs.canFalseStart = PR_FALSE;
+    ss->ssl3.hs.restartTarget = NULL;
 
     /*
     ** Blow away old security state and get a fresh setup.
     */
     ssl_GetXmitBufLock(ss); 
     ssl_ResetSecurityInfo(&ss->sec, PR_TRUE);
     status = ssl_CreateSecurityInfo(ss);
     ssl_ReleaseXmitBufLock(ss); 
@@ -326,16 +337,81 @@ SSL_HandshakeCallback(PRFileDesc *fd, SS
     ss->handshakeCallbackData = client_data;
 
     ssl_ReleaseSSL3HandshakeLock(ss);
     ssl_Release1stHandshakeLock(ss);
 
     return SECSuccess;
 }
 
+/* Register an application callback to be called when false start may happen.
+** Acquires and releases HandshakeLock.
+*/
+SECStatus
+SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb,
+			     void *arg)
+{
+    sslSocket *ss;
+
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback",
+		 SSL_GETPID(), fd));
+	return SECFailure;
+    }
+
+    if (!ss->opt.useSecurity) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    ssl_Get1stHandshakeLock(ss);
+    ssl_GetSSL3HandshakeLock(ss);
+
+    ss->canFalseStartCallback     = cb;
+    ss->canFalseStartCallbackData = arg;
+
+    ssl_ReleaseSSL3HandshakeLock(ss);
+    ssl_Release1stHandshakeLock(ss);
+
+    return SECSuccess;
+}
+
+SECStatus
+SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart)
+{
+    sslSocket *ss;
+
+    *canFalseStart = PR_FALSE;
+    ss = ssl_FindSocket(fd);
+    if (!ss) {
+	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart",
+		 SSL_GETPID(), fd));
+	return SECFailure;
+    }
+
+    if (!ss->ssl3.initialized) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	return SECFailure;
+    }
+
+    if (ss->version < SSL_LIBRARY_VERSION_3_0) {
+	PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
+	return SECFailure;
+    }
+
+    /* Require a forward-secret key exchange. */
+    *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
+		     ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
+		     ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
+		     ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa;
+
+    return SECSuccess;
+}
+
 /* Try to make progress on an SSL handshake by attempting to read the 
 ** next handshake from the peer, and sending any responses.
 ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK  if it cannot 
 ** read the next handshake from the underlying socket.
 ** For SSLv2, returns when handshake is complete or fatal error occurs.
 ** For SSLv3, returns when handshake is complete, or application data has
 ** arrived that must be taken by application before handshake can continue, 
 ** or a fatal error occurs.
@@ -519,16 +595,19 @@ ssl_SendSavedWriteData(sslSocket *ss)
 */
 static int 
 DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
 {
     int              rv;
     int              amount;
     int              available;
 
+    /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the
+     * 1stHandshakeLock. */
+    ssl_Get1stHandshakeLock(ss);
     ssl_GetRecvBufLock(ss);
 
     available = ss->gs.writeOffset - ss->gs.readOffset;
     if (available == 0) {
 	/* Get some more data */
 	if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
 	    /* Wait for application data to arrive.  */
 	    rv = ssl3_GatherAppDataRecord(ss, 0);
@@ -585,16 +664,17 @@ DoRecv(sslSocket *ss, unsigned char *out
     rv = amount;
 
     SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d",
 		 SSL_GETPID(), ss->fd, amount, available));
     PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount));
 
 done:
     ssl_ReleaseRecvBufLock(ss);
+    ssl_Release1stHandshakeLock(ss);
     return rv;
 }
 
 /************************************************************************/
 
 /*
 ** Return SSLKEAType derived from cert's Public Key algorithm info.
 */
@@ -1151,17 +1231,18 @@ ssl_SecureRead(sslSocket *ss, unsigned c
 {
     return ssl_SecureRecv(ss, buf, len, 0);
 }
 
 /* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */
 int
 ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
 {
-    int              rv		= 0;
+    int rv = 0;
+    PRBool falseStart = PR_FALSE;
 
     SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
 		SSL_GETPID(), ss->fd, len));
 
     if (ss->shutdownHow & ssl_SHUTDOWN_SEND) {
 	PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR);
     	rv = PR_FAILURE;
 	goto done;
@@ -1186,29 +1267,24 @@ 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->version >= SSL_LIBRARY_VERSION_3_0) {
+	if (ss->opt.enableFalseStart &&
+	    ss->version >= SSL_LIBRARY_VERSION_3_0) {
 	    ssl_GetSSL3HandshakeLock(ss);
-	    if ((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;
-	    }
+	    falseStart = ss->ssl3.hs.canFalseStart;
 	    ssl_ReleaseSSL3HandshakeLock(ss);
 	}
-	if (!canFalseStart &&
+	if (!falseStart &&
 	    (ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
 	    rv = ssl_Do1stHandshake(ss);
 	}
 	ssl_Release1stHandshakeLock(ss);
     }
     if (rv < 0) {
     	ss->writerThread = NULL;
 	goto done;
@@ -1223,16 +1299,27 @@ ssl_SecureSend(sslSocket *ss, const unsi
     }
     PORT_Assert(buf != NULL);
     if (!buf) {
 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
     	rv = PR_FAILURE;
 	goto done;
     }
 
+    if (!ss->firstHsDone) {
+	PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0);
+#ifdef DEBUG
+	ssl_GetSSL3HandshakeLock(ss);
+	PORT_Assert(ss->ssl3.hs.canFalseStart);
+	ssl_ReleaseSSL3HandshakeLock(ss);
+#endif
+	SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start",
+		    SSL_GETPID(), ss->fd));
+    }
+
     /* Send out the data using one of these functions:
      *	ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, 
      *  ssl3_SendApplicationData
      */
     ssl_GetXmitBufLock(ss);
     rv = (*ss->sec.send)(ss, buf, len, flags);
     ssl_ReleaseXmitBufLock(ss);
     ss->writerThread = NULL;
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -262,16 +262,18 @@ ssl_DupSocket(sslSocket *os)
 	    ss->getClientAuthData     = os->getClientAuthData;
 	    ss->getClientAuthDataArg  = os->getClientAuthDataArg;
             ss->sniSocketConfig       = os->sniSocketConfig;
             ss->sniSocketConfigArg    = os->sniSocketConfigArg;
 	    ss->handleBadCert         = os->handleBadCert;
 	    ss->badCertArg            = os->badCertArg;
 	    ss->handshakeCallback     = os->handshakeCallback;
 	    ss->handshakeCallbackData = os->handshakeCallbackData;
+	    ss->canFalseStartCallback = os->canFalseStartCallback;
+	    ss->canFalseStartCallbackData = os->canFalseStartCallbackData;
 	    ss->pkcs11PinArg          = os->pkcs11PinArg;
     
 	    /* Create security data */
 	    rv = ssl_CopySecurityInfo(ss, os);
 	    if (rv != SECSuccess) {
 		goto loser;
 	    }
 	}
@@ -2254,20 +2256,24 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_fla
 		    ** The code should select on write, not read.
 		    */
 		    new_flags ^=  PR_POLL_READ;	   /* don't select on read. */
 		    new_flags |=  PR_POLL_WRITE;   /* do    select on write. */
 		}
 	    } else if (new_flags & PR_POLL_WRITE) {
 		    /* The caller is trying to write, but the handshake is 
 		    ** blocked waiting for data to read, and the first 
-		    ** handshake has been sent.  so do NOT to poll on write.
+		    ** handshake has been sent.  So do NOT to poll on write
+		    ** unless we did false start.
 		    */
-		    new_flags ^=  PR_POLL_WRITE;   /* don't select on write. */
-		    new_flags |=  PR_POLL_READ;	   /* do    select on read. */
+		    if (!(ss->version >= SSL_LIBRARY_VERSION_3_0 &&
+			ss->ssl3.hs.canFalseStart)) {
+			new_flags ^= PR_POLL_WRITE; /* don't select on write. */
+		    }
+		    new_flags |= PR_POLL_READ;      /* do    select on read. */
 	    }
 	}
     } else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) {
 	*p_out_flags = PR_POLL_READ;	/* it's ready already. */
 	return new_flags;
     } else if ((ss->lastWriteBlocked) && (how_flags & PR_POLL_READ) &&
 	       (ss->pendingBuf.len != 0)) { /* write data waiting to be sent */
 	new_flags |=  PR_POLL_WRITE;   /* also select on write. */