| Index: net/socket/ssl_client_socket_nss.cc
|
| diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
|
| index bb923431f94a9c8d463302ac29f0ed035617a729..61294c908875f64321474a8b3c72b5ea04928758 100644
|
| --- a/net/socket/ssl_client_socket_nss.cc
|
| +++ b/net/socket/ssl_client_socket_nss.cc
|
| @@ -570,12 +570,14 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> {
|
| void* arg,
|
| PRBool* can_false_start);
|
|
|
| - // Called by NSS once the handshake has completed.
|
| + // Called by NSS each time a handshake completely finishes.
|
| // |arg| contains a pointer to the current SSLClientSocketNSS::Core.
|
| static void HandshakeCallback(PRFileDesc* socket, void* arg);
|
|
|
| - // Called once the handshake has succeeded.
|
| - void HandshakeSucceeded();
|
| + // Called once for each successful handshake. If the initial handshake false
|
| + // starts, it is called when it false starts and not when it completely
|
| + // finishes. is_initial is true if this is the initial handshake.
|
| + void HandshakeSucceeded(bool is_initial);
|
|
|
| // Handles an NSS error generated while handshaking or performing IO.
|
| // Returns a network error code mapped from the original NSS error.
|
| @@ -637,6 +639,9 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> {
|
| // Record TLS extension used for protocol negotiation (NPN or ALPN).
|
| void UpdateExtensionUsed();
|
|
|
| + // Returns true if renegotiations are allowed.
|
| + bool IsRenegotiationAllowed() const;
|
| +
|
| ////////////////////////////////////////////////////////////////////////////
|
| // Methods that are ONLY called on the network task runner:
|
| ////////////////////////////////////////////////////////////////////////////
|
| @@ -741,7 +746,8 @@ class SSLClientSocketNSS::Core : public base::RefCountedThreadSafe<Core> {
|
| bool channel_id_needed_;
|
| // True if the handshake state machine was interrupted for client auth.
|
| bool client_auth_cert_needed_;
|
| - // True if NSS has False Started.
|
| + // True if NSS has False Started in the initial handshake, but the initial
|
| + // handshake has not yet completely finished..
|
| bool false_started_;
|
| // True if NSS has called HandshakeCallback.
|
| bool handshake_callback_called_;
|
| @@ -1280,6 +1286,7 @@ void SSLClientSocketNSS::Core::HandshakeCallback(
|
| Core* core = reinterpret_cast<Core*>(arg);
|
| DCHECK(core->OnNSSTaskRunner());
|
|
|
| + bool is_initial = !core->handshake_callback_called_;
|
| core->handshake_callback_called_ = true;
|
| if (core->false_started_) {
|
| core->false_started_ = false;
|
| @@ -1296,10 +1303,10 @@ void SSLClientSocketNSS::Core::HandshakeCallback(
|
| // called HandshakeSucceeded(), so return now.
|
| return;
|
| }
|
| - core->HandshakeSucceeded();
|
| + core->HandshakeSucceeded(is_initial);
|
| }
|
|
|
| -void SSLClientSocketNSS::Core::HandshakeSucceeded() {
|
| +void SSLClientSocketNSS::Core::HandshakeSucceeded(bool is_initial) {
|
| DCHECK(OnNSSTaskRunner());
|
|
|
| PRBool last_handshake_resumed;
|
| @@ -1318,6 +1325,22 @@ void SSLClientSocketNSS::Core::HandshakeSucceeded() {
|
| UpdateNextProto();
|
| UpdateExtensionUsed();
|
|
|
| + if (is_initial && IsRenegotiationAllowed()) {
|
| + // For compatibility, do not enforce RFC 5746 support. Per section 4.1,
|
| + // enforcement falls largely on the server.
|
| + //
|
| + // This is done in a callback rather than after SSL_ForceHandshake returns
|
| + // because SSL_ForceHandshake will otherwise greedly consume renegotiations
|
| + // before returning if Finished and HelloRequest are in the same
|
| + // record.
|
| + //
|
| + // Note that SSL_OptionSet should only be called for an initial
|
| + // handshake. See https://crbug.com/125299.
|
| + SECStatus rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_RENEGOTIATION,
|
| + SSL_RENEGOTIATE_TRANSITIONAL);
|
| + DCHECK_EQ(SECSuccess, rv);
|
| + }
|
| +
|
| // Update the network task runners view of the handshake state whenever
|
| // a handshake has completed.
|
| PostOrRunCallback(
|
| @@ -1448,7 +1471,7 @@ int SSLClientSocketNSS::Core::DoHandshake() {
|
| } else if (rv == SECSuccess) {
|
| if (!handshake_callback_called_) {
|
| false_started_ = true;
|
| - HandshakeSucceeded();
|
| + HandshakeSucceeded(true);
|
| }
|
| } else {
|
| PRErrorCode prerr = PR_GetError();
|
| @@ -2121,6 +2144,20 @@ void SSLClientSocketNSS::Core::UpdateExtensionUsed() {
|
| }
|
| }
|
|
|
| +bool SSLClientSocketNSS::Core::IsRenegotiationAllowed() const {
|
| + DCHECK(OnNSSTaskRunner());
|
| +
|
| + if (nss_handshake_state_.next_proto_status == kNextProtoUnsupported)
|
| + return ssl_config_.renego_allowed_default;
|
| +
|
| + NextProto next_proto = NextProtoFromString(nss_handshake_state_.next_proto);
|
| + for (NextProto allowed : ssl_config_.renego_allowed_for_protos) {
|
| + if (next_proto == allowed)
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| void SSLClientSocketNSS::Core::RecordChannelIDSupportOnNSSTaskRunner() {
|
| DCHECK(OnNSSTaskRunner());
|
| if (nss_handshake_state_.resumed_handshake)
|
| @@ -2792,13 +2829,9 @@ int SSLClientSocketNSS::InitializeSSLOptions() {
|
| if (rv != SECSuccess)
|
| LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_FALSE_START");
|
|
|
| - // We allow servers to request renegotiation. Since we're a client,
|
| - // prohibiting this is rather a waste of time. Only servers are in a
|
| - // position to prevent renegotiation attacks.
|
| - // http://extendedsubset.com/?p=8
|
| -
|
| - rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_RENEGOTIATION,
|
| - SSL_RENEGOTIATE_TRANSITIONAL);
|
| + // By default, renegotiations are rejected. After the initial handshake
|
| + // completes, some application protocols may re-enable it.
|
| + rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
|
| if (rv != SECSuccess) {
|
| LogFailedNSSFunction(
|
| net_log_, "SSL_OptionSet", "SSL_ENABLE_RENEGOTIATION");
|
|
|