summaryrefslogtreecommitdiffstats
path: root/net/third_party/nss/ssl/ssl3con.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/third_party/nss/ssl/ssl3con.c')
-rw-r--r--net/third_party/nss/ssl/ssl3con.c90
1 files changed, 78 insertions, 12 deletions
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index e7741a0..0a61db5 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -2285,9 +2285,10 @@ ssl3_SendRecord( sslSocket * ss,
capRecordVersion = ((flags & ssl_SEND_FLAG_CAP_RECORD_VERSION) != 0);
if (capRecordVersion) {
- /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with
- * TLS ClientHello. */
+ /* ssl_SEND_FLAG_CAP_RECORD_VERSION can only be used with the
+ * TLS initial ClientHello. */
PORT_Assert(!IS_DTLS(ss));
+ PORT_Assert(!ss->firstHsDone);
PORT_Assert(type == content_handshake);
PORT_Assert(ss->ssl3.hs.ws == wait_server_hello);
}
@@ -4010,7 +4011,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
int num_suites;
int actual_count = 0;
PRBool isTLS = PR_FALSE;
- PRBool serverVersionKnown = PR_FALSE;
+ PRBool requestingResume = PR_FALSE;
PRInt32 total_exten_len = 0;
unsigned numCompressionMethods;
PRInt32 flags;
@@ -4040,6 +4041,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
@@ -4087,9 +4105,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) {
@@ -4101,7 +4151,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
}
if (sid) {
- serverVersionKnown = PR_TRUE;
+ requestingResume = PR_TRUE;
SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits );
/* Are we attempting a stateless session resume? */
@@ -4116,10 +4166,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) {
@@ -4219,6 +4281,10 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
return rv; /* err set by ssl3_AppendHandshake* */
}
+ if (ss->firstHsDone) {
+ /* Work around the Windows SChannel bug described above. */
+ PORT_Assert(ss->version == ss->clientHelloVersion);
+ }
ss->clientHelloVersion = ss->version;
if (IS_DTLS(ss)) {
PRUint16 version;
@@ -4338,7 +4404,7 @@ ssl3_SendClientHello(sslSocket *ss, PRBool resending)
}
flags = 0;
- if (!serverVersionKnown && !IS_DTLS(ss)) {
+ if (!ss->firstHsDone && !requestingResume && !IS_DTLS(ss)) {
flags |= ssl_SEND_FLAG_CAP_RECORD_VERSION;
}
rv = ssl3_FlushHandshake(ss, flags);