summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/nss/patches/canfalsestart.patch
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/nss/patches/canfalsestart.patch')
-rw-r--r--chromium/net/third_party/nss/patches/canfalsestart.patch960
1 files changed, 580 insertions, 380 deletions
diff --git a/chromium/net/third_party/nss/patches/canfalsestart.patch b/chromium/net/third_party/nss/patches/canfalsestart.patch
index d2a9752c070..a3fb1813d21 100644
--- a/chromium/net/third_party/nss/patches/canfalsestart.patch
+++ b/chromium/net/third_party/nss/patches/canfalsestart.patch
@@ -1,8 +1,8 @@
Index: net/third_party/nss/ssl/ssl.h
===================================================================
---- net/third_party/nss/ssl/ssl.h (revision 227363)
+--- net/third_party/nss/ssl/ssl.h (revision 227672)
+++ net/third_party/nss/ssl/ssl.h (working copy)
-@@ -121,14 +121,22 @@
+@@ -121,14 +121,17 @@
#define SSL_ENABLE_FALSE_START 22 /* Enable SSL false start (off by */
/* default, applies only to */
/* clients). False start is a */
@@ -22,62 +22,42 @@ Index: net/third_party/nss/ssl/ssl.h
+ * it saves a round trip for client-speaks-first protocols when performing a
+ * full handshake.
+ *
-+ * See SSL_DefaultCanFalseStart for the default criteria that NSS uses to
-+ * determine whether to false start or not. See SSL_SetCanFalseStartCallback
-+ * for how to change that criteria. In addition to those criteria, false start
-+ * will only be done when the server selects a cipher suite with an effective
-+ * key length of 80 bits or more (including RC4-128). Also, see
-+ * SSL_HandshakeCallback for a description on how false start affects when the
-+ * handshake callback gets called.
++ * 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
-@@ -741,14 +749,59 @@
+@@ -741,14 +744,45 @@
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 normally gets called when the TLS handshake
-+** is complete. If false start is not enabled, then the handshake callback is
-+** called after verifying the peer's Finished message and before sending
-+** outgoing application data and before processing incoming application data.
++** 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.
+**
-+** If false start is enabled and there is a custom CanFalseStartCallback
-+** callback set, then the handshake callback gets called after the peer's
-+** Finished message has been verified, which may be after application data is
-+** sent.
-+**
-+** If false start is enabled and there is not a custom CanFalseStartCallback
-+** callback established with SSL_SetCanFalseStartCallback then the handshake
-+** callback gets called before any application data is sent, which may be
-+** before the peer's Finished message has been verified.
++** 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 customize TLS false start should set this callback
++/* 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.
-+**
-+** Applications that do not set the callback will use an internal set of
-+** criteria to determine if the connection should false start. If
-+** the callback is set false start will never be used without invoking the
-+** callback function, but some connections (e.g. resumed connections) will
-+** never use false start and therefore will not invoke the callback.
-+**
-+** NSS's internal criteria for this connection can be evaluated by calling
-+** SSL_DefaultCanFalseStart() from the custom callback.
++** handshake will be canceled. NSS's recommended criteria can be evaluated by
++** calling SSL_RecommendedCanFalseStart.
+**
-+** See the description of SSL_HandshakeCallback for important information on
-+** how registering a custom false start callback affects when the handshake
-+** callback gets called.
++** 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);
@@ -85,62 +65,420 @@ Index: net/third_party/nss/ssl/ssl.h
+SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback(
+ PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg);
+
-+/* A utility function that can be called from a custom CanFalseStartCallback
-+** function to determine what NSS would have done for this connection if the
-+** custom callback was not implemented.
-+**/
-+SSL_IMPORT SECStatus SSL_DefaultCanFalseStart(PRFileDesc *fd,
-+ PRBool *canFalseStart);
++/* 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
+Index: net/third_party/nss/ssl/ssl3con.c
+===================================================================
+--- net/third_party/nss/ssl/ssl3con.c (revision 227672)
++++ net/third_party/nss/ssl/ssl3con.c (working copy)
+@@ -2890,7 +2890,7 @@
+ 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) );
+
+@@ -7344,36 +7344,72 @@
+ 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;
+
+ 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.
+- */
++ 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;
++ default:
++ result = PR_FALSE;
++ break;
++ }
+
+- 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;
++ return result;
+ }
+
+ static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
+@@ -7463,6 +7499,9 @@
+ }
+ 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;
+ }
+@@ -7500,20 +7539,59 @@
+ 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. */
+ }
+ }
++
+ rv = ssl3_SendEncryptedExtensions(ss);
+ if (rv != SECSuccess) {
+ goto loser; /* err code was set. */
+ }
+
++ if (!ss->firstHsDone) {
++ 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. */
+@@ -7526,10 +7604,7 @@
+ 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;
+
+@@ -10147,13 +10222,6 @@
+
+ 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) {
+@@ -10278,6 +10346,12 @@
+ } 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
+@@ -10287,7 +10361,27 @@
+ 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 != idle_handshake);
++
++ if (ss->opt.enableFalseStart &&
++ !ss->firstHsDone &&
++ !ss->sec.isServer &&
++ !ss->ssl3.hs.isResuming &&
++ ssl3_WaitingForStartOfServerSecondRound(ss)) {
++ /* 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.
++ */
++ rv = ssl3_CheckFalseStart(ss);
++ } else {
++ rv = SECSuccess;
++ }
+ }
+
+ done:
+@@ -10913,9 +11007,6 @@
+ return rv;
+ }
+
+- ss->gs.writeOffset = 0;
+- ss->gs.readOffset = 0;
+-
+ if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) {
+ effectiveExchKeyType = kt_rsa;
+ } else {
+@@ -10980,6 +11071,9 @@
+ return rv;
+ }
+
++/* The return type is SECStatus instead of void because this function needs
++ * to have type sslRestartTarget.
++ */
+ SECStatus
+ ssl3_FinishHandshake(sslSocket * ss)
+ {
+@@ -10989,19 +11083,16 @@
+
+ /* 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;
+ }
+@@ -11966,7 +12057,6 @@
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ return rv;
+-
+ }
+
+ /*
Index: net/third_party/nss/ssl/ssl3gthr.c
===================================================================
---- net/third_party/nss/ssl/ssl3gthr.c (revision 227363)
+--- net/third_party/nss/ssl/ssl3gthr.c (revision 227672)
+++ net/third_party/nss/ssl/ssl3gthr.c (working copy)
-@@ -374,9 +374,7 @@
- */
- if (ss->opt.enableFalseStart) {
- ssl_GetSSL3HandshakeLock(ss);
+@@ -275,11 +275,17 @@
+ {
+ 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;
+
+@@ -364,24 +370,52 @@
+
+ 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);
-+ canFalseStart = ss->ssl3.hs.canFalseStart;
- ssl_ReleaseSSL3HandshakeLock(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 &&
-Index: net/third_party/nss/ssl/sslinfo.c
-===================================================================
---- net/third_party/nss/ssl/sslinfo.c (revision 227363)
-+++ net/third_party/nss/ssl/sslinfo.c (working copy)
-@@ -26,7 +26,6 @@
- sslSocket * ss;
- SSLChannelInfo inf;
- sslSessionID * sid;
-- PRBool enoughFirstHsDone = PR_FALSE;
-
- if (!info || len < sizeof inf.length) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-@@ -43,14 +42,7 @@
- memset(&inf, 0, sizeof inf);
- inf.length = PR_MIN(sizeof inf, len);
+- } 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;
+@@ -404,7 +438,10 @@
+ {
+ int rv;
-- 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;
++ /* 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);
Index: net/third_party/nss/ssl/sslauth.c
===================================================================
---- net/third_party/nss/ssl/sslauth.c (revision 227363)
+--- net/third_party/nss/ssl/sslauth.c (revision 227672)
+++ net/third_party/nss/ssl/sslauth.c (working copy)
@@ -100,7 +100,6 @@
sslSocket *ss;
@@ -168,7 +506,7 @@ Index: net/third_party/nss/ssl/sslauth.c
} else {
Index: net/third_party/nss/ssl/sslimpl.h
===================================================================
---- net/third_party/nss/ssl/sslimpl.h (revision 227363)
+--- net/third_party/nss/ssl/sslimpl.h (revision 227672)
+++ net/third_party/nss/ssl/sslimpl.h (working copy)
@@ -881,6 +881,8 @@
/* Shared state between ssl3_HandleFinished and ssl3_FinishHandshake */
@@ -199,28 +537,69 @@ Index: net/third_party/nss/ssl/sslimpl.h
void *pkcs11PinArg;
SSLNextProtoCallback nextProtoCallback;
void *nextProtoArg;
-@@ -1423,7 +1431,6 @@
+@@ -1423,7 +1431,19 @@
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,
+Index: net/third_party/nss/ssl/sslinfo.c
+===================================================================
+--- net/third_party/nss/ssl/sslinfo.c (revision 227672)
++++ net/third_party/nss/ssl/sslinfo.c (working copy)
+@@ -26,7 +26,6 @@
+ sslSocket * ss;
+ SSLChannelInfo inf;
+ sslSessionID * sid;
+- PRBool enoughFirstHsDone = PR_FALSE;
+
+ if (!info || len < sizeof inf.length) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+@@ -43,14 +42,7 @@
+ 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;
Index: net/third_party/nss/ssl/sslsecur.c
===================================================================
---- net/third_party/nss/ssl/sslsecur.c (revision 227363)
+--- net/third_party/nss/ssl/sslsecur.c (revision 227672)
+++ net/third_party/nss/ssl/sslsecur.c (working copy)
-@@ -99,21 +99,12 @@
+@@ -97,23 +97,13 @@
+ ss->securityHandshake = 0;
+ }
if (ss->handshake == 0) {
- ssl_GetRecvBufLock(ss);
- ss->gs.recordLen = 0;
-+ ss->gs.writeOffset = 0;
-+ ss->gs.readOffset = 0;
- ssl_ReleaseRecvBufLock(ss);
-
- SSL_TRC(3, ("%d: SSL[%d]: handshake is completed",
- SSL_GETPID(), ss->fd));
+- 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 */
@@ -228,14 +607,45 @@ Index: net/third_party/nss/ssl/sslsecur.c
- (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);
-@@ -206,6 +197,7 @@
+@@ -134,6 +124,24 @@
+ 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.
+@@ -206,6 +214,7 @@
ssl_Get1stHandshakeLock(ss);
ss->firstHsDone = PR_FALSE;
@@ -243,7 +653,7 @@ Index: net/third_party/nss/ssl/sslsecur.c
if ( asServer ) {
ss->handshake = ssl2_BeginServerHandshake;
ss->handshaking = sslHandshakingAsServer;
-@@ -221,6 +213,8 @@
+@@ -221,6 +230,8 @@
ssl_ReleaseRecvBufLock(ss);
ssl_GetSSL3HandshakeLock(ss);
@@ -252,16 +662,7 @@ Index: net/third_party/nss/ssl/sslsecur.c
/*
** Blow away old security state and get a fresh setup.
-@@ -266,7 +260,7 @@
-
- /* SSL v2 protocol does not support subsequent handshakes. */
- if (ss->version < SSL_LIBRARY_VERSION_3_0) {
-- PORT_SetError(SEC_ERROR_INVALID_ARGS);
-+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
- rv = SECFailure;
- } else {
- ssl_GetSSL3HandshakeLock(ss);
-@@ -331,6 +325,75 @@
+@@ -331,6 +342,71 @@
return SECSuccess;
}
@@ -270,7 +671,7 @@ Index: net/third_party/nss/ssl/sslsecur.c
+*/
+SECStatus
+SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb,
-+ void *client_data)
++ void *arg)
+{
+ sslSocket *ss;
+
@@ -290,7 +691,7 @@ Index: net/third_party/nss/ssl/sslsecur.c
+ ssl_GetSSL3HandshakeLock(ss);
+
+ ss->canFalseStartCallback = cb;
-+ ss->canFalseStartCallbackData = client_data;
++ ss->canFalseStartCallbackData = arg;
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
@@ -298,19 +699,15 @@ Index: net/third_party/nss/ssl/sslsecur.c
+ return SECSuccess;
+}
+
-+/* A utility function that can be called from a custom SSLCanFalseStartCallback
-+** function to determine what NSS would have done for this connection if the
-+** custom callback was not implemented.
-+*/
+SECStatus
-+SSL_DefaultCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart)
++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_DefaultCanFalseStart",
++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
@@ -337,9 +734,43 @@ Index: net/third_party/nss/ssl/sslsecur.c
/* 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
-@@ -1195,12 +1258,7 @@
+@@ -524,6 +600,9 @@
+ 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;
+@@ -590,6 +669,7 @@
+
+ done:
+ ssl_ReleaseRecvBufLock(ss);
++ ssl_Release1stHandshakeLock(ss);
+ return rv;
+ }
+
+@@ -1156,7 +1236,8 @@
+ 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));
+@@ -1191,19 +1272,14 @@
+ 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->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 ||
@@ -347,15 +778,46 @@ Index: net/third_party/nss/ssl/sslsecur.c
- ssl3_CanFalseStart(ss)) {
- canFalseStart = PR_TRUE;
- }
-+ canFalseStart = ss->ssl3.hs.canFalseStart;
++ falseStart = ss->ssl3.hs.canFalseStart;
ssl_ReleaseSSL3HandshakeLock(ss);
}
- if (!canFalseStart &&
+- if (!canFalseStart &&
++ if (!falseStart &&
+ (ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
+ rv = ssl_Do1stHandshake(ss);
+ }
+@@ -1228,6 +1304,17 @@
+ 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
Index: net/third_party/nss/ssl/sslsock.c
===================================================================
---- net/third_party/nss/ssl/sslsock.c (revision 227363)
+--- net/third_party/nss/ssl/sslsock.c (revision 227672)
+++ net/third_party/nss/ssl/sslsock.c (working copy)
-@@ -2457,10 +2457,14 @@
+@@ -366,6 +366,8 @@
+ ss->badCertArg = os->badCertArg;
+ ss->handshakeCallback = os->handshakeCallback;
+ ss->handshakeCallbackData = os->handshakeCallbackData;
++ ss->canFalseStartCallback = os->canFalseStartCallback;
++ ss->canFalseStartCallbackData = os->canFalseStartCallbackData;
+ ss->pkcs11PinArg = os->pkcs11PinArg;
+ ss->getChannelID = os->getChannelID;
+ ss->getChannelIDArg = os->getChannelIDArg;
+@@ -2457,10 +2459,14 @@
} 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
@@ -373,265 +835,3 @@ Index: net/third_party/nss/ssl/sslsock.c
}
}
} else if ((new_flags & PR_POLL_READ) && (SSL_DataPending(fd) > 0)) {
-Index: net/third_party/nss/ssl/ssl3con.c
-===================================================================
---- net/third_party/nss/ssl/ssl3con.c (revision 227363)
-+++ net/third_party/nss/ssl/ssl3con.c (working copy)
-@@ -2890,7 +2890,7 @@
- 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) );
-
-@@ -7344,35 +7344,42 @@
- return rv;
- }
-
--PRBool
--ssl3_CanFalseStart(sslSocket *ss) {
-- PRBool rv;
-+static SECStatus
-+ssl3_CheckFalseStart(sslSocket *ss)
-+{
-+ SECStatus rv;
-+ PRBool maybeFalseStart = PR_TRUE;
-
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
-+ PORT_Assert( !ss->ssl3.hs.authCertificatePending );
-
-- /* 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.
-- */
-+ /* 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);
-- rv = ss->opt.enableFalseStart &&
-- !ss->sec.isServer &&
-- !ss->ssl3.hs.isResuming &&
-- ss->ssl3.cwSpec &&
-+ if (ss->ssl3.cwSpec->cipher_def->secret_key_size < 10) {
-+ ss->ssl3.hs.canFalseStart = PR_FALSE;
-+ maybeFalseStart = PR_FALSE;
-+ }
-+ ssl_ReleaseSpecReadLock(ss);
-+ if (!maybeFalseStart) {
-+ return SECSuccess;
-+ }
-
-- /* 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);
-+ if (!ss->canFalseStartCallback) {
-+ rv = SSL_DefaultCanFalseStart(ss->fd, &ss->ssl3.hs.canFalseStart);
-+ } else {
-+ rv = (ss->canFalseStartCallback)(ss->fd,
-+ ss->canFalseStartCallbackData,
-+ &ss->ssl3.hs.canFalseStart);
-+ }
-+
-+ if (rv != SECSuccess) {
-+ ss->ssl3.hs.canFalseStart = PR_FALSE;
-+ }
-+
- return rv;
- }
-
-@@ -7500,20 +7507,59 @@
- 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. */
- }
- }
-+
- rv = ssl3_SendEncryptedExtensions(ss);
- if (rv != SECSuccess) {
- goto loser; /* err code was set. */
- }
-
-+ if (!ss->firstHsDone) {
-+ 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. */
-@@ -7526,8 +7572,16 @@
- 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)) {
-+ if (ss->handshakeCallback &&
-+ (ss->ssl3.hs.canFalseStart && !ss->canFalseStartCallback)) {
-+ /* Call the handshake callback here for backwards compatibility with
-+ * applications that were using false start before
-+ * canFalseStartCallback was added. Note that we do this after calling
-+ * ssl3_SendFinished, which includes a call to ssl3_FlushHandshake,
-+ * just in case the application is relying on having the handshake
-+ * messages flushed to the network before its handshake callback is
-+ * called.
-+ */
- (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
- }
-
-@@ -10147,13 +10201,6 @@
-
- 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) {
-@@ -10278,6 +10325,12 @@
- } 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
-@@ -10287,7 +10340,39 @@
- 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_change_cipher ||
-+ ss->ssl3.hs.ws == wait_finished ||
-+ ss->ssl3.hs.ws == wait_new_session_ticket);
-+
-+ /* ssl3_SendClientSecondRound deferred the false start check because
-+ * certificate authentication was pending, so we have to do it now.
-+ */
-+ if (ss->opt.enableFalseStart &&
-+ !ss->firstHsDone &&
-+ !ss->sec.isServer &&
-+ !ss->ssl3.hs.isResuming &&
-+ (ss->ssl3.hs.ws == wait_change_cipher ||
-+ ss->ssl3.hs.ws == wait_finished ||
-+ ss->ssl3.hs.ws == wait_new_session_ticket)) {
-+ rv = ssl3_CheckFalseStart(ss);
-+ if (rv == SECSuccess &&
-+ ss->handshakeCallback &&
-+ (ss->ssl3.hs.canFalseStart && !ss->canFalseStartCallback)) {
-+ /* Call the handshake callback here for backwards compatibility
-+ * with applications that were using false start before
-+ * canFalseStartCallback was added.
-+ */
-+ (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
-+ }
-+ } else {
-+ rv = SECSuccess;
-+ }
- }
-
- done:
-@@ -10983,6 +11068,8 @@
- SECStatus
- ssl3_FinishHandshake(sslSocket * ss)
- {
-+ PRBool falseStarted;
-+
- PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
- PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
- PORT_Assert( ss->ssl3.hs.restartTarget == NULL );
-@@ -10990,6 +11077,7 @@
- /* The first handshake is now completed. */
- ss->handshake = NULL;
- ss->firstHsDone = PR_TRUE;
-+ ss->enoughFirstHsDone = PR_TRUE;
-
- if (ss->ssl3.hs.cacheSID) {
- (*ss->sec.cache)(ss->sec.ci.sid);
-@@ -10997,9 +11085,14 @@
- }
-
- ss->ssl3.hs.ws = idle_handshake;
-+ falseStarted = ss->ssl3.hs.canFalseStart;
-+ ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
-
-- /* Do the handshake callback for sslv3 here, if we cannot false start. */
-- if (ss->handshakeCallback != NULL && !ssl3_CanFalseStart(ss)) {
-+ /* Call the handshake callback for sslv3 here, unless we called it already
-+ * for the case where false start was done without a canFalseStartCallback.
-+ */
-+ if (ss->handshakeCallback &&
-+ !(falseStarted && !ss->canFalseStartCallback)) {
- (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
- }
-