Bug 783448: When renegotiating, continue to use the client_version used in

the initial ClientHello to work around a Windows SChannel bug.
r=ryan.sleevi,bsmith.


git-svn-id: svn://10.0.0.236/trunk@264269 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
wtc%google.com
2012-09-28 04:51:22 +00:00
parent 42106ed168
commit e79fac955c

View File

@@ -5,7 +5,7 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* $Id: ssl3con.c,v 1.190 2012-09-28 01:46:45 wtc%google.com Exp $ */
/* $Id: ssl3con.c,v 1.191 2012-09-28 04:51:22 wtc%google.com Exp $ */
/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */
@@ -4060,6 +4060,23 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
return rv;
}
/*
* During a renegotiation, ss->clientHelloVersion will be used again to
* work around a Windows SChannel bug. Ensure that it is still enabled.
*/
if (ss->firstHsDone) {
if (SSL3_ALL_VERSIONS_DISABLED(&ss->vrange)) {
PORT_SetError(SSL_ERROR_SSL_DISABLED);
return SECFailure;
}
if (ss->clientHelloVersion < ss->vrange.min ||
ss->clientHelloVersion > ss->vrange.max) {
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
}
}
/* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
* handles expired entries and other details.
* XXX If we've been called from ssl2_BeginClientHandshake, then
@@ -4107,9 +4124,41 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
sidOK = PR_FALSE;
}
if (sidOK && ssl3_NegotiateVersion(ss, sid->version,
PR_FALSE) != SECSuccess) {
sidOK = PR_FALSE;
/* TLS 1.0 (RFC 2246) Appendix E says:
* Whenever a client already knows the highest protocol known to
* a server (for example, when resuming a session), it should
* initiate the connection in that native protocol.
* So we pass sid->version to ssl3_NegotiateVersion() here, except
* when renegotiating.
*
* Windows SChannel compares the client_version inside the RSA
* EncryptedPreMasterSecret of a renegotiation with the
* client_version of the initial ClientHello rather than the
* ClientHello in the renegotiation. To work around this bug, we
* continue to use the client_version used in the initial
* ClientHello when renegotiating.
*/
if (sidOK) {
if (ss->firstHsDone) {
/*
* The client_version of the initial ClientHello is still
* available in ss->clientHelloVersion. Ensure that
* sid->version is bounded within
* [ss->vrange.min, ss->clientHelloVersion], otherwise we
* can't use sid.
*/
if (sid->version >= ss->vrange.min &&
sid->version <= ss->clientHelloVersion) {
ss->version = ss->clientHelloVersion;
} else {
sidOK = PR_FALSE;
}
} else {
if (ssl3_NegotiateVersion(ss, sid->version,
PR_FALSE) != SECSuccess) {
sidOK = PR_FALSE;
}
}
}
if (!sidOK) {
@@ -4137,10 +4186,22 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
} else {
SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_misses );
rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED,
PR_TRUE);
if (rv != SECSuccess)
return rv; /* error code was set */
/*
* Windows SChannel compares the client_version inside the RSA
* EncryptedPreMasterSecret of a renegotiation with the
* client_version of the initial ClientHello rather than the
* ClientHello in the renegotiation. To work around this bug, we
* continue to use the client_version used in the initial
* ClientHello when renegotiating.
*/
if (ss->firstHsDone) {
ss->version = ss->clientHelloVersion;
} else {
rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_MAX_SUPPORTED,
PR_TRUE);
if (rv != SECSuccess)
return rv; /* error code was set */
}
sid = ssl3_NewSessionID(ss, PR_FALSE);
if (!sid) {
@@ -4240,6 +4301,11 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
return rv; /* err set by ssl3_AppendHandshake* */
}
if (ss->firstHsDone) {
/* The client hello version must stay unchanged to work around
* the Windows SChannel bug described above. */
PORT_Assert(ss->version == ss->clientHelloVersion);
}
ss->clientHelloVersion = ss->version;
if (IS_DTLS(ss)) {
PRUint16 version;