summaryrefslogtreecommitdiffstats
path: root/net/third_party
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-09 09:40:51 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-09 09:40:51 +0000
commit8f3a23ec70c531406e3b1c605170924da47426e9 (patch)
treebb865b99b350f371418b956c7d53bae69dc7fa50 /net/third_party
parent2e9d18e3bc39e93bf6c821a5224f6816970c686d (diff)
downloadchromium_src-8f3a23ec70c531406e3b1c605170924da47426e9.zip
chromium_src-8f3a23ec70c531406e3b1c605170924da47426e9.tar.gz
chromium_src-8f3a23ec70c531406e3b1c605170924da47426e9.tar.bz2
Make SSL False Start work with asynchronous certificate validation
(SSL_AuthCertificateComplete). Patch by Brian Smith <brian@briansmith.org>. NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=713933 R=agl@chromium.org BUG=none TEST=none Review URL: https://codereview.chromium.org/23621040 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@227704 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/third_party')
-rw-r--r--net/third_party/nss/README.chromium4
-rwxr-xr-xnet/third_party/nss/patches/applypatches.sh2
-rw-r--r--net/third_party/nss/patches/canfalsestart.patch637
-rw-r--r--net/third_party/nss/ssl/ssl.h73
-rw-r--r--net/third_party/nss/ssl/ssl3con.c169
-rw-r--r--net/third_party/nss/ssl/ssl3gthr.c4
-rw-r--r--net/third_party/nss/ssl/sslauth.c10
-rw-r--r--net/third_party/nss/ssl/sslimpl.h9
-rw-r--r--net/third_party/nss/ssl/sslinfo.c10
-rw-r--r--net/third_party/nss/ssl/sslsecur.c94
-rw-r--r--net/third_party/nss/ssl/sslsock.c10
11 files changed, 931 insertions, 91 deletions
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium
index b7441f5..0e6ef5b 100644
--- a/net/third_party/nss/README.chromium
+++ b/net/third_party/nss/README.chromium
@@ -131,6 +131,10 @@ Patches:
https://code.google.com/p/chromium/issues/detail?id=303398
patches/resumeclienthelloversion.patch
+ * Make SSL False Start work with asynchronous certificate validation.
+ https://bugzilla.mozilla.org/show_bug.cgi?id=713933
+ patches/canfalsestart.patch
+
Apply the patches to NSS by running the patches/applypatches.sh script. Read
the comments at the top of patches/applypatches.sh for instructions.
diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh
index 7b9b913e..ec96d22 100755
--- a/net/third_party/nss/patches/applypatches.sh
+++ b/net/third_party/nss/patches/applypatches.sh
@@ -61,3 +61,5 @@ patch -p4 < $patches_dir/cachelocks.patch
patch -p4 < $patches_dir/ciphersuiteversion.patch
patch -p4 < $patches_dir/peercertchain2.patch
+
+patch -p4 < $patches_dir/canfalsestart.patch
diff --git a/net/third_party/nss/patches/canfalsestart.patch b/net/third_party/nss/patches/canfalsestart.patch
new file mode 100644
index 0000000..d2a9752
--- /dev/null
+++ b/net/third_party/nss/patches/canfalsestart.patch
@@ -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);
+ }
+
diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
index 4f51a7e..47468a0 100644
--- a/net/third_party/nss/ssl/ssl.h
+++ b/net/third_party/nss/ssl/ssl.h
@@ -121,14 +121,22 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
#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_SetMaxServerCacheLocks(PRUint32 maxLocks);
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
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index a7617fb..7b93a63 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -2890,7 +2890,7 @@ ssl3_SendRecord( sslSocket * ss,
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 @@ ssl3_RestartHandshakeAfterCertReq(sslSocket * ss,
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 &&
-
- /* 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);
+ 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;
+ }
+
+ 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 @@ ssl3_SendClientSecondRound(sslSocket *ss)
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 @@ ssl3_SendClientSecondRound(sslSocket *ss)
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 @@ ssl3_AuthCertificate(sslSocket *ss)
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 @@ ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error)
} 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 @@ ssl3_AuthCertificateComplete(sslSocket *ss, PRErrorCode error)
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 @@ xmit_loser:
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 @@ ssl3_FinishHandshake(sslSocket * ss)
/* 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 @@ ssl3_FinishHandshake(sslSocket * ss)
}
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);
}
diff --git a/net/third_party/nss/ssl/ssl3gthr.c b/net/third_party/nss/ssl/ssl3gthr.c
index 6d62515..7385d65 100644
--- a/net/third_party/nss/ssl/ssl3gthr.c
+++ b/net/third_party/nss/ssl/ssl3gthr.c
@@ -374,9 +374,7 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
*/
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 &&
diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c
index 70695e7..695cab8 100644
--- a/net/third_party/nss/ssl/sslauth.c
+++ b/net/third_party/nss/ssl/sslauth.c
@@ -100,7 +100,6 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
sslSocket *ss;
const char *cipherName;
PRBool isDes = PR_FALSE;
- PRBool enoughFirstHsDone = PR_FALSE;
ss = ssl_FindSocket(fd);
if (!ss) {
@@ -118,14 +117,7 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
*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 {
diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h
index 59140f8..614eed1 100644
--- a/net/third_party/nss/ssl/sslimpl.h
+++ b/net/third_party/nss/ssl/sslimpl.h
@@ -881,6 +881,8 @@ const ssl3CipherSuiteDef *suite_def;
/* 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 @@ struct sslSocketStr {
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 @@ const unsigned char * preferredCipher;
void *badCertArg;
SSLHandshakeCallback handshakeCallback;
void *handshakeCallbackData;
+ SSLCanFalseStartCallback canFalseStartCallback;
+ void *canFalseStartCallbackData;
void *pkcs11PinArg;
SSLNextProtoCallback nextProtoCallback;
void *nextProtoArg;
@@ -1423,7 +1431,6 @@ extern void ssl3_SetAlwaysBlock(sslSocket *ss);
extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
-extern PRBool ssl3_CanFalseStart(sslSocket *ss);
extern SECStatus
ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec,
PRBool isServer,
diff --git a/net/third_party/nss/ssl/sslinfo.c b/net/third_party/nss/ssl/sslinfo.c
index bfc1676..df7e669 100644
--- a/net/third_party/nss/ssl/sslinfo.c
+++ b/net/third_party/nss/ssl/sslinfo.c
@@ -26,7 +26,6 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
sslSocket * ss;
SSLChannelInfo inf;
sslSessionID * sid;
- PRBool enoughFirstHsDone = PR_FALSE;
if (!info || len < sizeof inf.length) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
@@ -43,14 +42,7 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len)
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;
diff --git a/net/third_party/nss/ssl/sslsecur.c b/net/third_party/nss/ssl/sslsecur.c
index 0714a0b..6c7532e 100644
--- a/net/third_party/nss/ssl/sslsecur.c
+++ b/net/third_party/nss/ssl/sslsecur.c
@@ -99,21 +99,12 @@ ssl_Do1stHandshake(sslSocket *ss)
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_ResetHandshake(PRFileDesc *s, PRBool asServer)
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_ResetHandshake(PRFileDesc *s, PRBool asServer)
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_ReHandshake(PRFileDesc *fd, PRBool flushCache)
/* 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 @@ SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb,
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_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
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 &&
diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c
index ffbccc6..072fad5 100644
--- a/net/third_party/nss/ssl/sslsock.c
+++ b/net/third_party/nss/ssl/sslsock.c
@@ -2457,10 +2457,14 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags)
} 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)) {