diff options
Diffstat (limited to 'chromium/net/third_party/nss/patches/canfalsestart.patch')
-rw-r--r-- | chromium/net/third_party/nss/patches/canfalsestart.patch | 960 |
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); - } - |