зеркало из https://github.com/mozilla/gecko-dev.git
Bug 713933: Add the NSS patch for this bug (rather than the PSM patch
for bug 658222) to security/patches.
This commit is contained in:
Родитель
ddff2a6c30
Коммит
975bc25be6
|
@ -1,6 +1,6 @@
|
|||
This directory contains patches that were added locally
|
||||
on top of the NSS release.
|
||||
|
||||
bug-658222-false-start.patch: First iteration of false start. The patch will be
|
||||
bug-713933-false-start.patch: First iteration of false start. The patch will be
|
||||
further modified to make it work for Chromium and
|
||||
other projects before being checked in.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,836 @@
|
|||
# HG changeset patch
|
||||
# User Patrick McManus <mcmanus@ducksong.com>
|
||||
# Date 1372656196 25200
|
||||
# Node ID f6bc026a0c368178b4d327bf05de785305161d72
|
||||
# Parent 89a5e4356ad1f7bc9d9d24f6409c6d963dde3ca4
|
||||
Bug 713933: Make false start work with asynchronous certificate verification, r=bsmith
|
||||
|
||||
diff --git a/security/nss/lib/ssl/ssl.def b/security/nss/lib/ssl/ssl.def
|
||||
--- a/security/nss/lib/ssl/ssl.def
|
||||
+++ b/security/nss/lib/ssl/ssl.def
|
||||
@@ -158,8 +158,15 @@ SSL_SetSRTPCiphers;
|
||||
;+};
|
||||
;+NSS_3.15 { # NSS 3.15 release
|
||||
;+ global:
|
||||
SSL_PeerStapledOCSPResponses;
|
||||
SSL_SetStapledOCSPResponses;
|
||||
;+ local:
|
||||
;+*;
|
||||
;+};
|
||||
+;+NSS_3.15.2 { # NSS 3.15.2 release
|
||||
+;+ global:
|
||||
+SSL_SetCanFalseStartCallback;
|
||||
+SSL_DefaultCanFalseStart;
|
||||
+;+ local:
|
||||
+;+*;
|
||||
+;+};
|
||||
diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h
|
||||
--- a/security/nss/lib/ssl/ssl.h
|
||||
+++ b/security/nss/lib/ssl/ssl.h
|
||||
@@ -116,24 +116,32 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRF
|
||||
#define SSL_REQUIRE_SAFE_NEGOTIATION 21 /* Peer must send Signaling */
|
||||
/* Cipher Suite Value (SCSV) or */
|
||||
/* Renegotiation Info (RI) */
|
||||
/* extension in ALL handshakes. */
|
||||
/* default: off */
|
||||
#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
|
||||
* non-empty application_data records into two records; the first record has
|
||||
* only the first byte of plaintext, and the second has the rest.
|
||||
*
|
||||
* This only prevents the attack in the sending direction; the connection may
|
||||
* still be vulnerable to such attacks if the peer does not implement a similar
|
||||
@@ -648,24 +656,69 @@ SSL_IMPORT SECStatus SSL_SetMaxServerCac
|
||||
/* called in child to inherit SID Cache variables.
|
||||
* If envString is NULL, this function will use the value of the environment
|
||||
* variable "SSL_INHERITANCE", otherwise the string value passed in will be
|
||||
* used.
|
||||
*/
|
||||
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
|
||||
** flushed first, ensuring that a full SSL handshake will be done.
|
||||
** If flushCache is zero, and an SSL connection is established, it will
|
||||
** do the much faster session restart handshake. This will change the
|
||||
** session keys without doing another private key operation.
|
||||
*/
|
||||
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
|
||||
--- a/security/nss/lib/ssl/ssl3con.c
|
||||
+++ b/security/nss/lib/ssl/ssl3con.c
|
||||
@@ -6664,45 +6664,61 @@ loser:
|
||||
PORT_SetError(errCode);
|
||||
rv = SECFailure;
|
||||
done:
|
||||
if (arena != NULL)
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
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) );
|
||||
-
|
||||
- /* 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.
|
||||
- */
|
||||
+ PORT_Assert( !ss->ssl3.hs.authCertificatePending );
|
||||
+
|
||||
+ /* 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);
|
||||
+
|
||||
+ if (rv == SECSuccess &&
|
||||
+ ss->ssl3.hs.canFalseStart && ss->handshakeCallback) {
|
||||
+ /* 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 = (ss->canFalseStartCallback)(ss->fd,
|
||||
+ ss->canFalseStartCallbackData,
|
||||
+ &ss->ssl3.hs.canFalseStart);
|
||||
+ }
|
||||
+
|
||||
+ if (rv != SECSuccess) {
|
||||
+ ss->ssl3.hs.canFalseStart = PR_FALSE;
|
||||
+ }
|
||||
+
|
||||
return rv;
|
||||
}
|
||||
|
||||
static SECStatus ssl3_SendClientSecondRound(sslSocket *ss);
|
||||
|
||||
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
|
||||
* ssl3 Server Hello Done message.
|
||||
* Caller must hold Handshake and RecvBuf locks.
|
||||
@@ -6722,16 +6738,17 @@ ssl3_HandleServerHelloDone(sslSocket *ss
|
||||
ws != wait_server_cert &&
|
||||
ws != wait_server_key &&
|
||||
ws != wait_cert_request) {
|
||||
SSL3_SendAlert(ss, alert_fatal, unexpected_message);
|
||||
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
+ ss->enoughFirstHsDone = PR_TRUE;
|
||||
rv = ssl3_SendClientSecondRound(ss);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Called from ssl3_HandleServerHelloDone and ssl3_AuthCertificateComplete.
|
||||
*
|
||||
* Caller must hold Handshake and RecvBuf locks.
|
||||
@@ -6820,35 +6837,47 @@ ssl3_SendClientSecondRound(sslSocket *ss
|
||||
/* XXX: If the server's certificate hasn't been authenticated by this
|
||||
* point, then we may be leaking this NPN message to an attacker.
|
||||
*/
|
||||
if (!ss->firstHsDone) {
|
||||
rv = ssl3_SendNextProto(ss);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser; /* err code was set. */
|
||||
}
|
||||
+
|
||||
+ if (ss->opt.enableFalseStart) {
|
||||
+ if (!ss->ssl3.hs.authCertificatePending) {
|
||||
+ rv = ssl3_CheckFalseStart(ss);
|
||||
+ if (rv != SECSuccess) {
|
||||
+ goto loser;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* The certificate authentication and the server's Finished
|
||||
+ * message are going to race each other. If the certificate
|
||||
+ * authentication wins, then we will try to false start. If the
|
||||
+ * server's Finished message wins, then ssl3_HandleFinished will
|
||||
+ * reset restartTarget to ssl3_FinishHandshake.
|
||||
+ */
|
||||
+ ss->ssl3.hs.restartTarget = ssl3_CheckFalseStart;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
rv = ssl3_SendFinished(ss, 0);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser; /* err code was set. */
|
||||
}
|
||||
|
||||
ssl_ReleaseXmitBufLock(ss); /*******************************/
|
||||
|
||||
if (ssl3_ExtensionNegotiated(ss, ssl_session_ticket_xtn))
|
||||
ss->ssl3.hs.ws = wait_new_session_ticket;
|
||||
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);
|
||||
- }
|
||||
-
|
||||
return SECSuccess;
|
||||
|
||||
loser:
|
||||
ssl_ReleaseXmitBufLock(ss);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9411,23 +9440,16 @@ ssl3_AuthCertificate(sslSocket *ss)
|
||||
if (ss->sec.isServer) {
|
||||
errCode = SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SERVERS;
|
||||
rv = SECFailure;
|
||||
goto loser;
|
||||
}
|
||||
|
||||
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) {
|
||||
ssl3_SendAlertForCertError(ss, errCode);
|
||||
goto loser;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10065,16 +10087,21 @@ xmit_loser:
|
||||
ssl_ReleaseSpecReadLock(ss); /*************************************/
|
||||
|
||||
/* If the wrap failed, we don't cache the sid.
|
||||
* The connection continues normally however.
|
||||
*/
|
||||
ss->ssl3.hs.cacheSID = rv == SECSuccess;
|
||||
}
|
||||
|
||||
+ /* Cancel false start check since we already completed the handshake */
|
||||
+ if (ss->ssl3.hs.restartTarget == ssl3_CheckFalseStart) {
|
||||
+ ss->ssl3.hs.restartTarget = NULL;
|
||||
+ }
|
||||
+
|
||||
if (ss->ssl3.hs.authCertificatePending) {
|
||||
if (ss->ssl3.hs.restartTarget) {
|
||||
PR_NOT_REACHED("ssl3_HandleFinished: unexpected restartTarget");
|
||||
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ss->ssl3.hs.restartTarget = ssl3_FinishHandshake;
|
||||
@@ -10083,33 +10110,41 @@ xmit_loser:
|
||||
|
||||
rv = ssl3_FinishHandshake(ss);
|
||||
return rv;
|
||||
}
|
||||
|
||||
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 );
|
||||
|
||||
/* 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);
|
||||
ss->ssl3.hs.cacheSID = PR_FALSE;
|
||||
}
|
||||
|
||||
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)) {
|
||||
+ falseStarted = ss->ssl3.hs.canFalseStart;
|
||||
+ ss->ssl3.hs.canFalseStart = PR_FALSE; /* False Start phase is complete */
|
||||
+
|
||||
+ /* 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 != NULL &&
|
||||
+ !(falseStarted && !ss->canFalseStartCallback)) {
|
||||
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/* Called from ssl3_HandleHandshake() when it has gathered a complete ssl3
|
||||
* hanshake message.
|
||||
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
|
||||
--- a/security/nss/lib/ssl/ssl3gthr.c
|
||||
+++ b/security/nss/lib/ssl/ssl3gthr.c
|
||||
@@ -369,19 +369,17 @@ ssl3_GatherCompleteHandshake(sslSocket *
|
||||
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);
|
||||
}
|
||||
} while (ss->ssl3.hs.ws != idle_handshake &&
|
||||
!canFalseStart &&
|
||||
ss->gs.buf.len == 0);
|
||||
|
||||
ss->gs.readOffset = 0;
|
||||
ss->gs.writeOffset = ss->gs.buf.len;
|
||||
diff --git a/security/nss/lib/ssl/sslauth.c b/security/nss/lib/ssl/sslauth.c
|
||||
--- a/security/nss/lib/ssl/sslauth.c
|
||||
+++ b/security/nss/lib/ssl/sslauth.c
|
||||
@@ -55,17 +55,16 @@ SSL_LocalCertificate(PRFileDesc *fd)
|
||||
/* NEED LOCKS IN HERE. */
|
||||
SECStatus
|
||||
SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
|
||||
char **ip, char **sp)
|
||||
{
|
||||
sslSocket *ss;
|
||||
const char *cipherName;
|
||||
PRBool isDes = PR_FALSE;
|
||||
- PRBool enoughFirstHsDone = PR_FALSE;
|
||||
|
||||
ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
|
||||
SSL_GETPID(), fd));
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
@@ -73,24 +72,17 @@ SSL_SecurityStatus(PRFileDesc *fd, int *
|
||||
if (kp0) *kp0 = 0;
|
||||
if (kp1) *kp1 = 0;
|
||||
if (ip) *ip = 0;
|
||||
if (sp) *sp = 0;
|
||||
if (op) {
|
||||
*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 {
|
||||
cipherName = ssl3_cipherName[ss->sec.cipherType];
|
||||
}
|
||||
PORT_Assert(cipherName);
|
||||
if (cipherName) {
|
||||
if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE;
|
||||
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
|
||||
--- a/security/nss/lib/ssl/sslimpl.h
|
||||
+++ b/security/nss/lib/ssl/sslimpl.h
|
||||
@@ -863,16 +863,18 @@ const ssl3CipherSuiteDef *suite_def;
|
||||
* in progress. */
|
||||
unsigned char cookie[32]; /* The cookie */
|
||||
unsigned char cookieLen; /* The length of the cookie */
|
||||
PRIntervalTime rtTimerStarted; /* When the timer was started */
|
||||
DTLSTimerCb rtTimerCb; /* The function to call on expiry */
|
||||
PRUint32 rtTimeoutMs; /* The length of the current timeout
|
||||
* used for backoff (in ms) */
|
||||
PRUint32 rtRetries; /* The retry counter */
|
||||
+ PRBool canFalseStart; /* Can/did we False Start */
|
||||
+
|
||||
} SSL3HandshakeState;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** This is the "ssl3" struct, as in "ss->ssl3".
|
||||
** note:
|
||||
** usually, crSpec == cwSpec and prSpec == pwSpec.
|
||||
@@ -1111,16 +1113,20 @@ struct sslSocketStr {
|
||||
sslOptions opt;
|
||||
/* Enabled version range */
|
||||
SSLVersionRange vrange;
|
||||
|
||||
/* State flags */
|
||||
unsigned long clientAuthRequested;
|
||||
unsigned long delayDisabled; /* Nagle delay disabled */
|
||||
unsigned long firstHsDone; /* first handshake is complete. */
|
||||
+ unsigned long enoughFirstHsDone; /* enough of the handshake is done
|
||||
+ * for callbacks to be able to
|
||||
+ * retrieve channel security
|
||||
+ * parameters from callback functions. */
|
||||
unsigned long handshakeBegun;
|
||||
unsigned long lastWriteBlocked;
|
||||
unsigned long recvdCloseNotify; /* received SSL EOF. */
|
||||
unsigned long TCPconnected;
|
||||
unsigned long appDataBuffered;
|
||||
unsigned long peerRequestedProtection; /* from old renegotiation */
|
||||
|
||||
/* version of the protocol to use */
|
||||
@@ -1151,16 +1157,18 @@ const unsigned char * preferredCipher;
|
||||
SSLGetClientAuthData getClientAuthData;
|
||||
void *getClientAuthDataArg;
|
||||
SSLSNISocketConfig sniSocketConfig;
|
||||
void *sniSocketConfigArg;
|
||||
SSLBadCertHandler handleBadCert;
|
||||
void *badCertArg;
|
||||
SSLHandshakeCallback handshakeCallback;
|
||||
void *handshakeCallbackData;
|
||||
+ SSLCanFalseStartCallback canFalseStartCallback;
|
||||
+ void *canFalseStartCallbackData;
|
||||
void *pkcs11PinArg;
|
||||
SSLNextProtoCallback nextProtoCallback;
|
||||
void *nextProtoArg;
|
||||
|
||||
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
|
||||
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
|
||||
PRIntervalTime cTimeout; /* timeout for NSPR I/O */
|
||||
|
||||
@@ -1353,17 +1361,16 @@ extern int ssl3_SendApplicationDat
|
||||
extern PRBool ssl_FdIsBlocking(PRFileDesc *fd);
|
||||
|
||||
extern PRBool ssl_SocketIsBlocking(sslSocket *ss);
|
||||
|
||||
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,
|
||||
PRBool isDTLS,
|
||||
PRBool capRecordVersion,
|
||||
SSL3ContentType type,
|
||||
const SSL3Opaque * pIn,
|
||||
PRUint32 contentLen,
|
||||
diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c
|
||||
--- a/security/nss/lib/ssl/sslinfo.c
|
||||
+++ b/security/nss/lib/ssl/sslinfo.c
|
||||
@@ -21,41 +21,33 @@ ssl_GetCompressionMethodName(SSLCompress
|
||||
}
|
||||
|
||||
SECStatus
|
||||
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);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ss = ssl_FindSocket(fd);
|
||||
if (!ss) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo",
|
||||
SSL_GETPID(), fd));
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
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;
|
||||
inf.keaKeyBits = ss->sec.keaKeyBits;
|
||||
if (ss->version < SSL_LIBRARY_VERSION_3_0) { /* SSL2 */
|
||||
inf.cipherSuite = ss->sec.cipherType | 0xff00;
|
||||
inf.compressionMethod = ssl_compression_null;
|
||||
inf.compressionMethodName = "N/A";
|
||||
diff --git a/security/nss/lib/ssl/sslreveal.c b/security/nss/lib/ssl/sslreveal.c
|
||||
--- a/security/nss/lib/ssl/sslreveal.c
|
||||
+++ b/security/nss/lib/ssl/sslreveal.c
|
||||
@@ -72,40 +72,33 @@ SSL_RevealURL(PRFileDesc * fd)
|
||||
|
||||
SECStatus
|
||||
SSL_HandshakeNegotiatedExtension(PRFileDesc * socket,
|
||||
SSLExtensionType extId,
|
||||
PRBool *pYes)
|
||||
{
|
||||
/* some decisions derived from SSL_GetChannelInfo */
|
||||
sslSocket * sslsocket = NULL;
|
||||
- PRBool enoughFirstHsDone = PR_FALSE;
|
||||
|
||||
if (!pYes) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
sslsocket = ssl_FindSocket(socket);
|
||||
if (!sslsocket) {
|
||||
SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeNegotiatedExtension",
|
||||
SSL_GETPID(), socket));
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
*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 && sslsocket->enoughFirstHsDone) {
|
||||
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
|
||||
* ssl3_ExtensionNegotiated();
|
||||
* Member xtnData appears to get accessed in functions that handle
|
||||
* the handshake (hello messages and extension sending),
|
||||
* therefore the handshake lock should be sufficient.
|
||||
*/
|
||||
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
|
||||
--- a/security/nss/lib/ssl/sslsecur.c
|
||||
+++ b/security/nss/lib/ssl/sslsecur.c
|
||||
@@ -103,20 +103,22 @@ ssl_Do1stHandshake(sslSocket *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->firstHsDone = PR_TRUE;
|
||||
+ ss->enoughFirstHsDone = PR_TRUE;
|
||||
(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
|
||||
}
|
||||
- ss->firstHsDone = PR_TRUE;
|
||||
+ ss->firstHsDone = PR_TRUE;
|
||||
+ ss->enoughFirstHsDone = PR_TRUE;
|
||||
ss->gs.writeOffset = 0;
|
||||
ss->gs.readOffset = 0;
|
||||
break;
|
||||
}
|
||||
rv = (*ss->handshake)(ss);
|
||||
++loopCount;
|
||||
/* This code must continue to loop on SECWouldBlock,
|
||||
* or any positive value. See XXX_1 comments.
|
||||
@@ -201,31 +203,34 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool
|
||||
|
||||
SSL_LOCK_READER(ss);
|
||||
SSL_LOCK_WRITER(ss);
|
||||
|
||||
/* Reset handshake state */
|
||||
ssl_Get1stHandshakeLock(ss);
|
||||
|
||||
ss->firstHsDone = PR_FALSE;
|
||||
+ ss->enoughFirstHsDone = PR_FALSE;
|
||||
if ( asServer ) {
|
||||
ss->handshake = ssl2_BeginServerHandshake;
|
||||
ss->handshaking = sslHandshakingAsServer;
|
||||
} else {
|
||||
ss->handshake = ssl2_BeginClientHandshake;
|
||||
ss->handshaking = sslHandshakingAsClient;
|
||||
}
|
||||
ss->nextHandshake = 0;
|
||||
ss->securityHandshake = 0;
|
||||
|
||||
ssl_GetRecvBufLock(ss);
|
||||
status = ssl_InitGather(&ss->gs);
|
||||
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.
|
||||
*/
|
||||
ssl_GetXmitBufLock(ss);
|
||||
ssl_ResetSecurityInfo(&ss->sec, PR_TRUE);
|
||||
status = ssl_CreateSecurityInfo(ss);
|
||||
ssl_ReleaseXmitBufLock(ss);
|
||||
@@ -326,16 +331,84 @@ SSL_HandshakeCallback(PRFileDesc *fd, SS
|
||||
ss->handshakeCallbackData = client_data;
|
||||
|
||||
ssl_ReleaseSSL3HandshakeLock(ss);
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
|
||||
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 CanFalseStartCallback
|
||||
+** 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_NOT_INITIALIZED);
|
||||
+ return SECFailure;
|
||||
+ }
|
||||
+
|
||||
+ if (ss->version <= SSL_LIBRARY_VERSION_3_0) {
|
||||
+ PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION);
|
||||
+ 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
|
||||
** read the next handshake from the underlying socket.
|
||||
** For SSLv2, returns when handshake is complete or fatal error occurs.
|
||||
** For SSLv3, returns when handshake is complete, or application data has
|
||||
** arrived that must be taken by application before handshake can continue,
|
||||
** or a fatal error occurs.
|
||||
@@ -1190,22 +1263,17 @@ ssl_SecureSend(sslSocket *ss, const unsi
|
||||
if (len > 0)
|
||||
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) {
|
||||
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 &&
|
||||
(ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
|
||||
rv = ssl_Do1stHandshake(ss);
|
||||
}
|
||||
ssl_Release1stHandshakeLock(ss);
|
||||
}
|
||||
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
|
||||
--- a/security/nss/lib/ssl/sslsock.c
|
||||
+++ b/security/nss/lib/ssl/sslsock.c
|
||||
@@ -2336,19 +2336,23 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_fla
|
||||
** The code should select on write, not read.
|
||||
*/
|
||||
new_flags ^= PR_POLL_READ; /* don't select on read. */
|
||||
new_flags |= PR_POLL_WRITE; /* do select on write. */
|
||||
}
|
||||
} 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. */
|
||||
+ 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)) {
|
||||
*p_out_flags = PR_POLL_READ; /* it's ready already. */
|
||||
return new_flags;
|
||||
} else if ((ss->lastWriteBlocked) && (how_flags & PR_POLL_READ) &&
|
||||
(ss->pendingBuf.len != 0)) { /* write data waiting to be sent */
|
Загрузка…
Ссылка в новой задаче