Index: net/third_party/nss/patches/canfalsestart.patch |
=================================================================== |
--- net/third_party/nss/patches/canfalsestart.patch (revision 0) |
+++ net/third_party/nss/patches/canfalsestart.patch (revision 0) |
@@ -0,0 +1,637 @@ |
+Index: net/third_party/nss/ssl/ssl.h |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl.h (revision 227363) |
++++ net/third_party/nss/ssl/ssl.h (working copy) |
+@@ -121,14 +121,22 @@ |
+ #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. |
++ * |
++ * 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. |
++ */ |
+ |
+ /* 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 @@ |
+ 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. |
++** |
++** 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. |
+ */ |
+ 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 |
++** 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. |
++** |
++** See the description of SSL_HandshakeCallback for important information on |
++** how registering a custom false start callback affects when the handshake |
++** callback gets called. |
++**/ |
++typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)( |
++ PRFileDesc *fd, void *arg, PRBool *canFalseStart); |
++ |
++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); |
++ |
+ /* |
+ ** 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/ssl3gthr.c |
+=================================================================== |
+--- net/third_party/nss/ssl/ssl3gthr.c (revision 227363) |
++++ net/third_party/nss/ssl/ssl3gthr.c (working copy) |
+@@ -374,9 +374,7 @@ |
+ */ |
+ 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); |
+ } |
+ } 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); |
+ |
+- 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/sslauth.c |
+=================================================================== |
+--- net/third_party/nss/ssl/sslauth.c (revision 227363) |
++++ net/third_party/nss/ssl/sslauth.c (working copy) |
+@@ -100,7 +100,6 @@ |
+ sslSocket *ss; |
+ const char *cipherName; |
+ PRBool isDes = PR_FALSE; |
+- PRBool enoughFirstHsDone = PR_FALSE; |
+ |
+ ss = ssl_FindSocket(fd); |
+ if (!ss) { |
+@@ -118,14 +117,7 @@ |
+ *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 { |
+Index: net/third_party/nss/ssl/sslimpl.h |
+=================================================================== |
+--- net/third_party/nss/ssl/sslimpl.h (revision 227363) |
++++ net/third_party/nss/ssl/sslimpl.h (working copy) |
+@@ -881,6 +881,8 @@ |
+ /* 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. */ |
+@@ -1162,6 +1164,10 @@ |
+ 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. */ |
+@@ -1210,6 +1216,8 @@ |
+ void *badCertArg; |
+ SSLHandshakeCallback handshakeCallback; |
+ void *handshakeCallbackData; |
++ SSLCanFalseStartCallback canFalseStartCallback; |
++ void *canFalseStartCallbackData; |
+ void *pkcs11PinArg; |
+ SSLNextProtoCallback nextProtoCallback; |
+ void *nextProtoArg; |
+@@ -1423,7 +1431,6 @@ |
+ |
+ extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled); |
+ |
+-extern PRBool ssl3_CanFalseStart(sslSocket *ss); |
+ extern SECStatus |
+ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, |
+ PRBool isServer, |
+Index: net/third_party/nss/ssl/sslsecur.c |
+=================================================================== |
+--- net/third_party/nss/ssl/sslsecur.c (revision 227363) |
++++ net/third_party/nss/ssl/sslsecur.c (working copy) |
+@@ -99,21 +99,12 @@ |
+ 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)); |
+- /* 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); |
+- } |
+- ss->firstHsDone = PR_TRUE; |
+- ss->gs.writeOffset = 0; |
+- ss->gs.readOffset = 0; |
+ break; |
+ } |
+ rv = (*ss->handshake)(ss); |
+@@ -206,6 +197,7 @@ |
+ ssl_Get1stHandshakeLock(ss); |
+ |
+ ss->firstHsDone = PR_FALSE; |
++ ss->enoughFirstHsDone = PR_FALSE; |
+ if ( asServer ) { |
+ ss->handshake = ssl2_BeginServerHandshake; |
+ ss->handshaking = sslHandshakingAsServer; |
+@@ -221,6 +213,8 @@ |
+ 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. |
+@@ -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 @@ |
+ 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 *client_data) |
++{ |
++ 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 = client_data; |
++ |
++ ssl_ReleaseSSL3HandshakeLock(ss); |
++ ssl_Release1stHandshakeLock(ss); |
++ |
++ 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) |
++{ |
++ sslSocket *ss; |
++ |
++ *canFalseStart = PR_FALSE; |
++ ss = ssl_FindSocket(fd); |
++ if (!ss) { |
++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_DefaultCanFalseStart", |
++ 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 |
+@@ -1195,12 +1258,7 @@ |
+ ssl_Get1stHandshakeLock(ss); |
+ if (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; |
+- } |
++ canFalseStart = ss->ssl3.hs.canFalseStart; |
+ ssl_ReleaseSSL3HandshakeLock(ss); |
+ } |
+ if (!canFalseStart && |
+Index: net/third_party/nss/ssl/sslsock.c |
+=================================================================== |
+--- net/third_party/nss/ssl/sslsock.c (revision 227363) |
++++ net/third_party/nss/ssl/sslsock.c (working copy) |
+@@ -2457,10 +2457,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 |
+- ** 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)) { |
+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); |
+ } |
+ |