[OE-core] [PATCH 2/2] nss: CVE-2013-1740

rongqing.li at windriver.com rongqing.li at windriver.com
Thu May 15 06:00:04 UTC 2014


From: Li Wang <li.wang at windriver.com>

the patch comes from:
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-1740
https://bugzilla.mozilla.org/show_bug.cgi?id=919877
https://bugzilla.mozilla.org/show_bug.cgi?id=713933

changeset:   10946:f28426e944ae
user:        Wan-Teh Chang <wtc at google.com>
date:        Tue Nov 26 16:44:39 2013 -0800
summary:     Bug 713933: Handle the return value of both ssl3_HandleRecord calls

changeset:   10945:774c7dec7565
user:        Wan-Teh Chang <wtc at google.com>
date:        Mon Nov 25 19:16:23 2013 -0800
summary:     Bug 713933: Declare the |falseStart| local variable in the smallest

changeset:   10848:141fae8fb2e8
user:        Wan-Teh Chang <wtc at google.com>
date:        Mon Sep 23 11:25:41 2013 -0700
summary:     Bug 681839: Allow SSL_HandshakeNegotiatedExtension to be called before the handshake is finished, r=brian at briansmith.org

changeset:   10898:1b9c43d28713
user:        Brian Smith <brian at briansmith.org>
date:        Thu Oct 31 15:40:42 2013 -0700
summary:     Bug 713933: Make SSL False Start work with asynchronous certificate validation, r=wtc

Signed-off-by: Li Wang <li.wang at windriver.com>
Signed-off-by: Roy Li <rongqing.li at windriver.com>
---
 .../nss/files/nss-CVE-2013-1740.patch              |  914 ++++++++++++++++++++
 meta/recipes-support/nss/nss.inc                   |    1 +
 2 files changed, 915 insertions(+)
 create mode 100644 meta/recipes-support/nss/files/nss-CVE-2013-1740.patch

diff --git a/meta/recipes-support/nss/files/nss-CVE-2013-1740.patch b/meta/recipes-support/nss/files/nss-CVE-2013-1740.patch
new file mode 100644
index 0000000..a681ef5
--- /dev/null
+++ b/meta/recipes-support/nss/files/nss-CVE-2013-1740.patch
@@ -0,0 +1,914 @@
+nss: CVE-2013-1740
+
+the patch comes from:
+http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-1740
+https://bugzilla.mozilla.org/show_bug.cgi?id=919877
+https://bugzilla.mozilla.org/show_bug.cgi?id=713933
+
+changeset:   10946:f28426e944ae
+user:        Wan-Teh Chang <wtc at google.com>
+date:        Tue Nov 26 16:44:39 2013 -0800
+summary:     Bug 713933: Handle the return value of both ssl3_HandleRecord calls
+
+changeset:   10945:774c7dec7565
+user:        Wan-Teh Chang <wtc at google.com>
+date:        Mon Nov 25 19:16:23 2013 -0800
+summary:     Bug 713933: Declare the |falseStart| local variable in the smallest
+
+changeset:   10848:141fae8fb2e8
+user:        Wan-Teh Chang <wtc at google.com>
+date:        Mon Sep 23 11:25:41 2013 -0700
+summary:     Bug 681839: Allow SSL_HandshakeNegotiatedExtension to be called before the handshake is finished, r=brian at briansmith.org
+
+changeset:   10898:1b9c43d28713
+user:        Brian Smith <brian at briansmith.org>
+date:        Thu Oct 31 15:40:42 2013 -0700
+summary:     Bug 713933: Make SSL False Start work with asynchronous certificate validation, r=wtc
+
+Signed-off-by: Li Wang <li.wang at windriver.com>
+---
+ nss/lib/ssl/ssl.def     |    7 ++
+ nss/lib/ssl/ssl.h       |   54 +++++++++++---
+ nss/lib/ssl/ssl3con.c   |  188 +++++++++++++++++++++++++++++++++++------------
+ nss/lib/ssl/ssl3gthr.c  |   63 ++++++++++++----
+ nss/lib/ssl/sslauth.c   |   10 +--
+ nss/lib/ssl/sslimpl.h   |   22 +++++-
+ nss/lib/ssl/sslinfo.c   |   10 +--
+ nss/lib/ssl/sslreveal.c |    9 +--
+ nss/lib/ssl/sslsecur.c  |  139 ++++++++++++++++++++++++++++-------
+ nss/lib/ssl/sslsock.c   |   12 ++-
+ 10 files changed, 386 insertions(+), 128 deletions(-)
+
+diff --git a/nss/lib/ssl/ssl.def b/nss/lib/ssl/ssl.def
+index fbf7fc5..e937bd4 100644
+--- a/nss/lib/ssl/ssl.def
++++ b/nss/lib/ssl/ssl.def
+@@ -163,3 +163,10 @@ SSL_SetStapledOCSPResponses;
+ ;+    local:
+ ;+*;
+ ;+};
++;+NSS_3.15.3 {    # NSS 3.15.3 release
++;+    global:
++SSL_RecommendedCanFalseStart;
++SSL_SetCanFalseStartCallback;
++;+    local:
++;+*;
++;+};
+diff --git a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h
+index 6db0e34..ddeaaef 100644
+--- a/nss/lib/ssl/ssl.h
++++ b/nss/lib/ssl/ssl.h
+@@ -121,14 +121,17 @@ 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.
++ *
++ * 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
+@@ -653,14 +656,45 @@ 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 gets called when a TLS handshake is complete. The
++** handshake callback is called after verifying the peer's Finished message and
++** before processing incoming application data.
++**
++** For the initial handshake: If the handshake false started (see
++** SSL_ENABLE_FALSE_START), then application data may already have been sent
++** before the handshake callback is called. If we did not false start then the
++** callback will get called before any application data is sent.
+ */
+ typedef void (PR_CALLBACK *SSLHandshakeCallback)(PRFileDesc *fd,
+                                                  void *client_data);
+ SSL_IMPORT SECStatus SSL_HandshakeCallback(PRFileDesc *fd, 
+ 			          SSLHandshakeCallback cb, void *client_data);
+ 
++/* Applications that wish to enable TLS false start must set this callback
++** function. NSS will invoke the functon to determine if a particular
++** connection should use false start or not. SECSuccess indicates that the
++** callback completed successfully, and if so *canFalseStart indicates if false
++** start can be used. If the callback does not return SECSuccess then the
++** handshake will be canceled. NSS's recommended criteria can be evaluated by
++** calling SSL_RecommendedCanFalseStart.
++**
++** If no false start callback is registered then false start will never be
++** done, even if the SSL_ENABLE_FALSE_START option is enabled.
++**/
++typedef SECStatus (PR_CALLBACK *SSLCanFalseStartCallback)(
++    PRFileDesc *fd, void *arg, PRBool *canFalseStart);
++
++SSL_IMPORT SECStatus SSL_SetCanFalseStartCallback(
++    PRFileDesc *fd, SSLCanFalseStartCallback callback, void *arg);
++
++/* This function sets *canFalseStart according to the recommended criteria for
++** false start. These criteria may change from release to release and may depend
++** on which handshake features have been negotiated and/or properties of the
++** certifciates/keys used on the connection.
++*/
++SSL_IMPORT SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd,
++                                                  PRBool *canFalseStart);
++
+ /*
+ ** For the server, request a new handshake.  For the client, begin a new
+ ** handshake.  If flushCache is non-zero, the SSL3 cache entry will be 
+diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c
+index 61d24d9..f39ba09 100644
+--- a/nss/lib/ssl/ssl3con.c
++++ b/nss/lib/ssl/ssl3con.c
+@@ -2535,7 +2535,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) );
+ 
+@@ -6674,36 +6674,73 @@ done:
+     return rv;
+ }
+ 
++static SECStatus
++ssl3_CheckFalseStart(sslSocket *ss)
++{
++    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
++    PORT_Assert( !ss->ssl3.hs.authCertificatePending );
++    PORT_Assert( !ss->ssl3.hs.canFalseStart );
++
++    if (!ss->canFalseStartCallback) {
++       SSL_TRC(3, ("%d: SSL[%d]: no false start callback so no false start",
++                   SSL_GETPID(), ss->fd));
++    } else {
++       PRBool maybeFalseStart;
++       SECStatus rv;
++
++       /* An attacker can control the selected ciphersuite so we only wish to
++        * do False Start in the case that the selected ciphersuite is
++        * sufficiently strong that the attack can gain no advantage.
++        * Therefore we always require an 80-bit cipher. */
++        ssl_GetSpecReadLock(ss);
++        maybeFalseStart = ss->ssl3.cwSpec->cipher_def->secret_key_size >= 10;
++        ssl_ReleaseSpecReadLock(ss);
++
++       if (!maybeFalseStart) {
++           SSL_TRC(3, ("%d: SSL[%d]: no false start due to weak cipher",
++                       SSL_GETPID(), ss->fd));
++       } else {
++           rv = (ss->canFalseStartCallback)(ss->fd,
++                                            ss->canFalseStartCallbackData,
++                                            &ss->ssl3.hs.canFalseStart);
++           if (rv == SECSuccess) {
++               SSL_TRC(3, ("%d: SSL[%d]: false start callback returned %s",
++                           SSL_GETPID(), ss->fd,
++                           ss->ssl3.hs.canFalseStart ? "TRUE" : "FALSE"));
++           } else {
++               SSL_TRC(3, ("%d: SSL[%d]: false start callback failed (%s)",
++                           SSL_GETPID(), ss->fd,
++                           PR_ErrorToName(PR_GetError())));
++           }
++           return rv;
++       }
++    }
++
++    ss->ssl3.hs.canFalseStart = PR_FALSE;
++    return SECSuccess;
++}
++
+ PRBool
+-ssl3_CanFalseStart(sslSocket *ss) {
+-    PRBool rv;
++ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss)
++{
++    PRBool result = PR_FALSE;
+ 
+     PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
+ 
+-    /* XXX: does not take into account whether we are waiting for
+-     * SSL_AuthCertificateComplete or SSL_RestartHandshakeAfterCertReq. If/when
+-     * that is done, this function could return different results each time it
+-     * would be called.
+-     */
++    switch (ss->ssl3.hs.ws) {
++    case wait_new_session_ticket:
++        result = PR_TRUE;
++        break;
++    case wait_change_cipher:
++        result = !ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn);
++        break;
++    case wait_finished:
++        break;
++    default:
++        PR_NOT_REACHED("ssl3_WaitingForStartOfServerSecondRound");
++    }
+ 
+-    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);
+@@ -6785,6 +6822,9 @@ ssl3_SendClientSecondRound(sslSocket *ss)
+     }
+     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;
+     }
+@@ -6822,14 +6862,50 @@ 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. */
+ 	}
++
++        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);
+@@ -6844,10 +6920,7 @@ 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)) {
+-	(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
+-    }
++    PORT_Assert(ssl3_WaitingForStartOfServerSecondRound(ss));
+ 
+     return SECSuccess;
+ 
+@@ -9421,13 +9494,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) {
+@@ -9551,6 +9617,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
+@@ -9560,7 +9632,29 @@ 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_new_session_ticket ||
++                    ss->ssl3.hs.ws == wait_change_cipher ||
++                    ss->ssl3.hs.ws == wait_finished);
++ 
++        /* ssl3_SendClientSecondRound deferred the false start check because
++         * certificate authentication was pending, so we do it now if we still
++          * haven't received any of the server's second round yet.
++         */
++        if (ss->opt.enableFalseStart &&
++            !ss->firstHsDone &&
++            !ss->sec.isServer &&
++            !ss->ssl3.hs.isResuming &&
++            ssl3_WaitingForStartOfServerSecondRound(ss)) {
++            rv = ssl3_CheckFalseStart(ss);
++        } else {
++            rv = SECSuccess;
++        }
+     }
+ 
+ done:
+@@ -10023,9 +10117,6 @@ xmit_loser:
+         return rv;
+     }
+ 
+-    ss->gs.writeOffset = 0;
+-    ss->gs.readOffset  = 0;
+-
+     if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) {
+ 	effectiveExchKeyType = kt_rsa;
+     } else {
+@@ -10090,6 +10181,9 @@ xmit_loser:
+     return rv;
+ }
+ 
++/* The return type is SECStatus instead of void because this function needs
++ * to have type sslRestartTarget.
++ */
+ SECStatus
+ ssl3_FinishHandshake(sslSocket * ss)
+ {
+@@ -10099,19 +10193,16 @@ ssl3_FinishHandshake(sslSocket * ss)
+ 
+     /* 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;
+ }
+@@ -11045,7 +11136,6 @@ process_it:
+ 
+     ssl_ReleaseSSL3HandshakeLock(ss);
+     return rv;
+-
+ }
+ 
+ /*
+diff --git a/nss/lib/ssl/ssl3gthr.c b/nss/lib/ssl/ssl3gthr.c
+index 6d62515..03e369d 100644
+--- a/nss/lib/ssl/ssl3gthr.c
++++ b/nss/lib/ssl/ssl3gthr.c
+@@ -275,11 +275,17 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
+ {
+     SSL3Ciphertext cText;
+     int            rv;
+-    PRBool         canFalseStart = PR_FALSE;
++    PRBool         keepGoing = PR_TRUE;
+ 
+     SSL_TRC(30, ("ssl3_GatherCompleteHandshake"));
+ 
++    /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake,
++     * which requires the 1stHandshakeLock, which must be acquired before the
++     * RecvBufLock.
++     */
++    PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
++
+     do {
+ 	PRBool handleRecordNow = PR_FALSE;
+ 
+@@ -368,20 +374,48 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
+ 	if (rv < 0) {
+ 	    return ss->recvdCloseNotify ? 0 : rv;
+ 	}
++        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 we kicked off a false start in ssl3_HandleServerHelloDone, break
+-	 * out of this loop early without finishing the handshake.
+-	 */
+-	if (ss->opt.enableFalseStart) {
+-	    ssl_GetSSL3HandshakeLock(ss);
+-	    canFalseStart = (ss->ssl3.hs.ws == wait_change_cipher ||
+-			     ss->ssl3.hs.ws == wait_new_session_ticket) &&
+-		            ssl3_CanFalseStart(ss);
+-	    ssl_ReleaseSSL3HandshakeLock(ss);
++        PORT_Assert(keepGoing);
++        ssl_GetSSL3HandshakeLock(ss);
++        if (ss->ssl3.hs.ws == idle_handshake) {
++            /* We are done with the current handshake so stop trying to
++             * handshake. Note that it would be safe to test ss->firstHsDone
++             * instead of ss->ssl3.hs.ws. By testing ss->ssl3.hs.ws instead,
++             * we prioritize completing a renegotiation handshake over sending
++             * application data.
++             */
++            PORT_Assert(ss->firstHsDone);
++            PORT_Assert(!ss->ssl3.hs.canFalseStart);
++            keepGoing = PR_FALSE;
++        } else if (ss->ssl3.hs.canFalseStart) {
++            /* Prioritize sending application data over trying to complete
++             * the handshake if we're false starting.
++             *
++             * If we were to do this check at the beginning of the loop instead
++             * of here, then this function would become be a no-op after
++             * receiving the ServerHelloDone in the false start case, and we
++             * would never complete the handshake.
++             */
++            PORT_Assert(!ss->firstHsDone);
++ 
++            if (ssl3_WaitingForStartOfServerSecondRound(ss)) {
++                keepGoing = PR_FALSE;
++            } else {
++                ss->ssl3.hs.canFalseStart = PR_FALSE;
++            }
+ 	}
+-    } while (ss->ssl3.hs.ws != idle_handshake &&
+-             !canFalseStart &&
+-             ss->gs.buf.len == 0);
++        ssl_ReleaseSSL3HandshakeLock(ss);
++     } while (keepGoing);
++
+ 
+     ss->gs.readOffset = 0;
+     ss->gs.writeOffset = ss->gs.buf.len;
+@@ -404,7 +438,10 @@ ssl3_GatherAppDataRecord(sslSocket *ss, int flags)
+ {
+     int            rv;
+ 
++    /* ssl3_GatherCompleteHandshake requires both of these locks. */
++    PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
+     PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
++
+     do {
+ 	rv = ssl3_GatherCompleteHandshake(ss, flags);
+     } while (rv > 0 && ss->gs.buf.len == 0);
+diff --git a/nss/lib/ssl/sslauth.c b/nss/lib/ssl/sslauth.c
+index d2f57bf..cb956d4 100644
+--- a/nss/lib/ssl/sslauth.c
++++ b/nss/lib/ssl/sslauth.c
+@@ -60,7 +60,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) {
+@@ -78,14 +77,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/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h
+index 90e9567..bf0d67f 100644
+--- a/nss/lib/ssl/sslimpl.h
++++ b/nss/lib/ssl/sslimpl.h
+@@ -842,6 +842,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. */
+@@ -1116,6 +1118,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. */
+@@ -1156,6 +1162,8 @@ const unsigned char *  preferredCipher;
+     void                     *badCertArg;
+     SSLHandshakeCallback      handshakeCallback;
+     void                     *handshakeCallbackData;
++    SSLCanFalseStartCallback  canFalseStartCallback;
++    void                     *canFalseStartCallbackData;
+     void                     *pkcs11PinArg;
+     SSLNextProtoCallback      nextProtoCallback;
+     void                     *nextProtoArg;
+@@ -1358,7 +1366,19 @@ extern void      ssl3_SetAlwaysBlock(sslSocket *ss);
+ 
+ extern SECStatus ssl_EnableNagleDelay(sslSocket *ss, PRBool enabled);
+ 
+-extern PRBool    ssl3_CanFalseStart(sslSocket *ss);
++extern void      ssl_FinishHandshake(sslSocket *ss);
++
++/* Returns PR_TRUE if we are still waiting for the server to respond to our
++ * client second round. Once we've received any part of the server's second
++ * round then we don't bother trying to false start since it is almost always
++ * the case that the NewSessionTicket, ChangeCipherSoec, and Finished messages
++ * were sent in the same packet and we want to process them all at the same
++ * time. If we were to try to false start in the middle of the server's second
++ * round, then we would increase the number of I/O operations
++ * (SSL_ForceHandshake/PR_Recv/PR_Send/etc.) needed to finish the handshake.
++ */
++extern PRBool    ssl3_WaitingForStartOfServerSecondRound(sslSocket *ss);
++
+ extern SECStatus
+ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *   cwSpec,
+ 		              PRBool             isServer,
+diff --git a/nss/lib/ssl/sslinfo.c b/nss/lib/ssl/sslinfo.c
+index 9f2597e..d0c23b7 100644
+--- a/nss/lib/ssl/sslinfo.c
++++ b/nss/lib/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/nss/lib/ssl/sslreveal.c b/nss/lib/ssl/sslreveal.c
+index dc14794..d972998 100644
+--- a/nss/lib/ssl/sslreveal.c
++++ b/nss/lib/ssl/sslreveal.c
+@@ -77,7 +77,6 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
+ {
+   /* some decisions derived from SSL_GetChannelInfo */
+   sslSocket * sslsocket = NULL;
+-  PRBool enoughFirstHsDone = PR_FALSE;
+ 
+   if (!pYes) {
+     PORT_SetError(SEC_ERROR_INVALID_ARGS);
+@@ -93,14 +92,8 @@ SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
+ 
+   *pYes = PR_FALSE;
+ 
+-  if (sslsocket->firstHsDone) {
+-    enoughFirstHsDone = PR_TRUE;
+-  } else if (sslsocket->ssl3.initialized && ssl3_CanFalseStart(sslsocket)) {
+-    enoughFirstHsDone = PR_TRUE;
+-  }
+-
+   /* according to public API SSL_GetChannelInfo, this doesn't need a lock */
+-  if (sslsocket->opt.useSecurity && enoughFirstHsDone) {
++  if (sslsocket->opt.useSecurity) {
+     if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */
+       /* now we know this socket went through ssl3_InitState() and
+        * ss->xtnData got initialized, which is the only member accessed by
+diff --git a/nss/lib/ssl/sslsecur.c b/nss/lib/ssl/sslsecur.c
+index 49bb42b..d0df442 100644
+--- a/nss/lib/ssl/sslsecur.c
++++ b/nss/lib/ssl/sslsecur.c
+@@ -97,23 +97,13 @@ ssl_Do1stHandshake(sslSocket *ss)
+ 	    ss->securityHandshake = 0;
+ 	}
+ 	if (ss->handshake == 0) {
+-	    ssl_GetRecvBufLock(ss);
+-	    ss->gs.recordLen = 0;
+-	    ssl_ReleaseRecvBufLock(ss);
+-
+-	    SSL_TRC(3, ("%d: SSL[%d]: handshake is completed",
+-			SSL_GETPID(), ss->fd));
+-            /* call handshake callback for ssl v2 */
+-	    /* for v3 this is done in ssl3_HandleFinished() */
+-	    if ((ss->handshakeCallback != NULL) && /* has callback */
+-		(!ss->firstHsDone) &&              /* only first time */
+-		(ss->version < SSL_LIBRARY_VERSION_3_0)) {  /* not ssl3 */
+-		ss->firstHsDone     = PR_TRUE;
+-		(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
++            /* for v3 this is done in ssl3_FinishHandshake */
++            if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) {
++                ssl_GetRecvBufLock(ss);
++                ss->gs.recordLen = 0;
++                ssl_FinishHandshake(ss);
++                ssl_ReleaseRecvBufLock(ss);
+ 	    }
+-	    ss->firstHsDone         = PR_TRUE;
+-	    ss->gs.writeOffset = 0;
+-	    ss->gs.readOffset  = 0;
+ 	    break;
+ 	}
+ 	rv = (*ss->handshake)(ss);
+@@ -134,6 +124,24 @@ ssl_Do1stHandshake(sslSocket *ss)
+     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_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 +230,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.
+@@ -331,6 +342,71 @@ 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 *arg)
++{
++    sslSocket *ss;
++
++    ss = ssl_FindSocket(fd);
++    if (!ss) {
++       SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback",
++                SSL_GETPID(), fd));
++       return SECFailure;
++    }
++
++    if (!ss->opt.useSecurity) {
++       PORT_SetError(SEC_ERROR_INVALID_ARGS);
++       return SECFailure;
++    }
++
++    ssl_Get1stHandshakeLock(ss);
++    ssl_GetSSL3HandshakeLock(ss);
++
++    ss->canFalseStartCallback     = cb;
++    ss->canFalseStartCallbackData = arg;
++
++    ssl_ReleaseSSL3HandshakeLock(ss);
++    ssl_Release1stHandshakeLock(ss);
++
++    return SECSuccess;
++}
++
++SECStatus
++SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart)
++{
++    sslSocket *ss;
++
++    *canFalseStart = PR_FALSE;
++    ss = ssl_FindSocket(fd);
++    if (!ss) {
++       SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart",
++                SSL_GETPID(), fd));
++       return SECFailure;
++    }
++
++    if (!ss->ssl3.initialized) {
++       PORT_SetError(SEC_ERROR_INVALID_ARGS);
++       return SECFailure;
++    }
++
++    if (ss->version < SSL_LIBRARY_VERSION_3_0) {
++       PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
++       return SECFailure;
++    }
++
++    /* Require a forward-secret key exchange. */
++    *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
++                    ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
++                    ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
++                    ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa;
++
++    return SECSuccess;
++}
++
+ /* Try to make progress on an SSL handshake by attempting to read the 
+ ** next handshake from the peer, and sending any responses.
+ ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK  if it cannot 
+@@ -524,6 +600,9 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
+     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 @@ DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
+ 
+ done:
+     ssl_ReleaseRecvBufLock(ss);
++    ssl_Release1stHandshakeLock(ss);
+     return rv;
+ }
+ 
+@@ -1156,7 +1236,7 @@ ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len)
+ int
+ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
+ {
+-    int              rv		= 0;
++    int rv = 0;
+ 
+     SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
+ 		SSL_GETPID(), ss->fd, len));
+@@ -1191,19 +1271,15 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
+     	ss->writerThread = PR_GetCurrentThread();
+     /* If any of these is non-zero, the initial handshake is not done. */
+     if (!ss->firstHsDone) {
+-	PRBool canFalseStart = PR_FALSE;
++        PRBool falseStart = PR_FALSE;
+ 	ssl_Get1stHandshakeLock(ss);
+-	if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
++        if (ss->opt.enableFalseStart &&
++            ss->version >= SSL_LIBRARY_VERSION_3_0) {
+ 	    ssl_GetSSL3HandshakeLock(ss);
+-	    if ((ss->ssl3.hs.ws == wait_change_cipher ||
+-		ss->ssl3.hs.ws == wait_finished ||
+-		ss->ssl3.hs.ws == wait_new_session_ticket) &&
+-		ssl3_CanFalseStart(ss)) {
+-		canFalseStart = PR_TRUE;
+-	    }
++	    falseStart = ss->ssl3.hs.canFalseStart;
+ 	    ssl_ReleaseSSL3HandshakeLock(ss);
+ 	}
+-	if (!canFalseStart &&
++	if (!falseStart &&
+ 	    (ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
+ 	    rv = ssl_Do1stHandshake(ss);
+ 	}
+@@ -1228,6 +1304,17 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
+ 	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
+diff --git a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c
+index cd4a7a7..73e069b 100644
+--- a/nss/lib/ssl/sslsock.c
++++ b/nss/lib/ssl/sslsock.c
+@@ -349,6 +349,8 @@ ssl_DupSocket(sslSocket *os)
+ 	    ss->badCertArg            = os->badCertArg;
+ 	    ss->handshakeCallback     = os->handshakeCallback;
+ 	    ss->handshakeCallbackData = os->handshakeCallbackData;
++            ss->canFalseStartCallback = os->canFalseStartCallback;
++            ss->canFalseStartCallbackData = os->canFalseStartCallbackData;
+ 	    ss->pkcs11PinArg          = os->pkcs11PinArg;
+     
+ 	    /* Create security data */
+@@ -2341,10 +2343,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)) {
+-- 
+1.7.9.5
+
diff --git a/meta/recipes-support/nss/nss.inc b/meta/recipes-support/nss/nss.inc
index fbe4001..5afd639 100644
--- a/meta/recipes-support/nss/nss.inc
+++ b/meta/recipes-support/nss/nss.inc
@@ -19,6 +19,7 @@ SRC_URI = "\
     file://nss-3.15.1-fix-CVE-2013-1741.patch \
     file://nss-3.15.1-fix-CVE-2013-5605.patch \
     file://nss-CVE-2014-1492.patch \
+    file://nss-CVE-2013-1740.patch \
 "
 SRC_URI_append_class-target = "\
     file://nss.pc.in \
-- 
1.7.10.4




More information about the Openembedded-core mailing list