diff options
author | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-11 23:07:52 +0000 |
---|---|---|
committer | agl@chromium.org <agl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-11 23:07:52 +0000 |
commit | 563cbcc6bb0759b23ab67b5074f66de45f7b546a (patch) | |
tree | e01ca3683194db3aeceae741c74d8d819e752b2b | |
parent | 79b1f324791fec657c1f62ec7a4cbef5ab9057cc (diff) | |
download | chromium_src-563cbcc6bb0759b23ab67b5074f66de45f7b546a.zip chromium_src-563cbcc6bb0759b23ab67b5074f66de45f7b546a.tar.gz chromium_src-563cbcc6bb0759b23ab67b5074f66de45f7b546a.tar.bz2 |
net: detect and error out with ESET HTTPS interception + False Start
ESET products (anti-virus) and NetNanny can intercept HTTPS connections. However,
they're False Start intolerant. Rather than have connections hang
forever, we detect them by the leaf certificate's issuer common name
and give a helpful error message.
BUG=58152
TEST=Install ESET anti-virus. Configure to intercept HTTPS connections. Goto https://mail.google.com. Confirm that a helpful error page appears.
Review URL: http://codereview.chromium.org/3723001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@62209 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 35 | ||||
-rw-r--r-- | chrome/renderer/localized_error.cc | 28 | ||||
-rw-r--r-- | net/base/net_error_list.h | 18 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.cc | 50 | ||||
-rw-r--r-- | net/socket/ssl_client_socket_nss.h | 8 |
5 files changed, 122 insertions, 17 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 275fdd2..1c8a6b0 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -5583,6 +5583,15 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_ERRORPAGES_HEADING_PROXY_CONNECTION_FAILED" desc="Heading in the error page when the proxy server connection failed."> Unable to connect to the proxy server. </message> + <message name="IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY" desc="Heading of the error page when the server has a weak Diffie-Hellman public key. Diffie-Hellman is a technical term and the conjuction of two names so may be best left untranslated. 'key' here is used as the technical name for a large number with certain mathematical properties that allow it to be used to encrypt and decrypt data. 'weak' here means that the number is too small to resist an exhaustive attempt to find certain mathematical structures in it, the secrecy of which is critical."> + Server has a weak ephemeral Diffie-Hellman public key + </message> + <message name="IDS_ERRORPAGES_HEADING_ESET_ANTI_VIRUS_SSL_INTERCEPTION" desc="Heading of the error page when we detect that ESET anti-virus is running and intercepting our HTTPS connections. 'ESET' is a product name and may be best left untranslated."> + Cannot make secure connection because of ESET anti-virus + </message> + <message name="IDS_ERRORPAGES_HEADING_NETNANNY_SSL_INTERCEPTION" desc="Heading of the error page when we detect that NetNanny is running and intercepting our HTTPS connections. 'NetNanny' is a product name and may be best left untranslated."> + Cannot make secure connection because of NetNanny + </message> <message name="IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED" desc="Heading of the error page when the network connection failed."> Unable to connect to the internet. </message> @@ -5637,6 +5646,32 @@ Keep your key file in a safe place. You will need it to create new versions of y and uncheck "Use a proxy server for your LAN." </message> </if> + <message name="IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY" desc="Summary in the error page when the server has a weak Diffie-Hellman public key"> + This error can occur when connecting to a secure (HTTPS) server. It + means that the server is trying to setup a secure connection but, due to + a disastrous misconfiguration, the connection wouldn’t be secure at all! + <ph name="LINE_BREAK"><br /><br /></ph> In this case the + server needs to be fixed. Chrome won’t use insecure connections in order + to protect your privacy. + </message> + + <message name="IDS_ERRORPAGES_SUMMARY_ESET_ANTI_VIRUS_SSL_INTERCEPTION" desc="Summary in the error page when we detect that ESET anti-virus is running and intercepting our HTTPS connections. 'ESET' is a product name and may be best left untranslated. 'Learn more' should be the contents of IDS_OPTIONS_LEARN_MORE_LABEL."> + <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> has detected that + an ESET product is intercepting secure connections. This is typically + not a security issue as the ESET software is usually running on the same + computer. However, due to an intolerance to specific aspects of Chrome's + secure connections, ESET products have to be configured to not perform + this interception. Click the 'Learn more' link for instructions. + </message> + + <message name="IDS_ERRORPAGES_SUMMARY_NETNANNY_SSL_INTERCEPTION" desc="Summary in the error page when we detect that NetNanny is running and intercepting our HTTPS connections. 'NetNanny' is a product name and may be best left untranslated. 'Learn more' should be the contents of IDS_OPTIONS_LEARN_MORE_LABEL."> + <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> has detected that + NetNanny is intercepting secure connections. This is typically + not a security issue as the NetNanny software is usually running on the + same computer. However, due to an intolerance to specific aspects of + Chrome's secure connections, NetNanny has to be configured to not + perform this interception. Click the 'Learn more' link for instructions. + </message> <message name="IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED" desc="Summary of the error page when the network connection failed, before platform dependent instructions."> <ph name="PRODUCT_NAME"><span jscontent="productName"></span><ex>Google Chrome</ex></ph> diff --git a/chrome/renderer/localized_error.cc b/chrome/renderer/localized_error.cc index 203f7b5..da06d7a 100644 --- a/chrome/renderer/localized_error.cc +++ b/chrome/renderer/localized_error.cc @@ -29,6 +29,10 @@ static const char kRedirectLoopLearnMoreUrl[] = "http://www.google.com/support/chrome/bin/answer.py?answer=95626"; static const char kWeakDHKeyLearnMoreUrl[] = "http://sites.google.com/a/chromium.org/dev/err_ssl_weak_server_ephemeral_dh_key"; +static const char kESETLearnMoreUrl[] = + "http://sites.google.com/a/chromium.org/dev/err_eset_anti_virus_ssl_interception"; +static const char kNetNannyLearnMoreUrl[] = + "http://sites.google.com/a/chromium.org/dev/err_netnanny_ssl_interception"; enum NAV_SUGGESTIONS { SUGGEST_NONE = 0, @@ -112,8 +116,8 @@ const LocalizedErrorMap net_error_options[] = { }, {net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY, IDS_ERRORPAGES_TITLE_LOAD_FAILED, - IDS_ERRORPAGES_HEADING_SSL_PROTOCOL_ERROR, - IDS_ERRORPAGES_SUMMARY_SSL_PROTOCOL_ERROR, + IDS_ERRORPAGES_HEADING_WEAK_SERVER_EPHEMERAL_DH_KEY, + IDS_ERRORPAGES_SUMMARY_WEAK_SERVER_EPHEMERAL_DH_KEY, IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR, SUGGEST_LEARNMORE, }, @@ -124,6 +128,20 @@ const LocalizedErrorMap net_error_options[] = { IDS_ERRORPAGES_DETAILS_PROXY_CONNECTION_FAILED, SUGGEST_NONE, }, + {net::ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION, + IDS_ERRORPAGES_TITLE_LOAD_FAILED, + IDS_ERRORPAGES_HEADING_ESET_ANTI_VIRUS_SSL_INTERCEPTION, + IDS_ERRORPAGES_SUMMARY_ESET_ANTI_VIRUS_SSL_INTERCEPTION, + IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR, + SUGGEST_LEARNMORE, + }, + {net::ERR_NETNANNY_SSL_INTERCEPTION, + IDS_ERRORPAGES_TITLE_LOAD_FAILED, + IDS_ERRORPAGES_HEADING_NETNANNY_SSL_INTERCEPTION, + IDS_ERRORPAGES_SUMMARY_NETNANNY_SSL_INTERCEPTION, + IDS_ERRORPAGES_DETAILS_SSL_PROTOCOL_ERROR, + SUGGEST_LEARNMORE, + }, // TODO(mmenke): Once Linux-specific instructions are added, remove this // conditional, and the one further down as well. #if defined(OS_MACOSX) || defined(OS_WIN) @@ -423,6 +441,12 @@ void LocalizedError::GetStrings(const WebKit::WebURLError& error, case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY: learn_more_url = GURL(kWeakDHKeyLearnMoreUrl); break; + case net::ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION: + learn_more_url = GURL(kESETLearnMoreUrl); + break; + case net::ERR_NETNANNY_SSL_INTERCEPTION: + learn_more_url = GURL(kNetNannyLearnMoreUrl); + break; default: break; } diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index 6e4c7b9..bd5e71e 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -180,12 +180,22 @@ NET_ERROR(SSL_WEAK_SERVER_EPHEMERAL_DH_KEY, -129) // of an HTTP proxy. NET_ERROR(PROXY_CONNECTION_FAILED, -130) -// This means that we tried a Snap Start connection and sent a request, -// predicting the server's NPN protocol support. However, after doing the -// actual handshake, our prediction turned out to be incorrect so we sent a -// request in the wrong protocol. +// We tried a Snap Start connection and sent a request, predicting the server's +// NPN protocol support. However, after doing the actual handshake, our +// prediction turned out to be incorrect so we sent a request in the wrong +// protocol. NET_ERROR(SSL_SNAP_START_NPN_MISPREDICTION, -131) +// We detected an ESET product intercepting our HTTPS connections. Since these +// products are False Start intolerant, we return this error so that we can +// give the user a helpful error message rather than have the connection hang. +NET_ERROR(ESET_ANTI_VIRUS_SSL_INTERCEPTION, -132) + +// We detected NetNanny intercepting our HTTPS connections. Since this product +// is False Start intolerant, we return this error so that we can give the user +// a helpful error message rather than have the connection hang. +NET_ERROR(NETNANNY_SSL_INTERCEPTION, -133) + // Certificate error codes // // The values of certificate error codes must be consecutive. diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc index b24a708..a40b564 100644 --- a/net/socket/ssl_client_socket_nss.cc +++ b/net/socket/ssl_client_socket_nss.cc @@ -421,6 +421,8 @@ SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket, handshake_callback_called_(false), completed_handshake_(false), pseudo_connected_(false), + eset_mitm_detected_(false), + netnanny_mitm_detected_(false), dnssec_provider_(NULL), next_handshake_state_(STATE_NONE), nss_fd_(NULL), @@ -995,6 +997,8 @@ void SSLClientSocketNSS::Disconnect() { server_cert_verify_result_.Reset(); completed_handshake_ = false; pseudo_connected_ = false; + eset_mitm_detected_ = false; + netnanny_mitm_detected_= false; nss_bufs_ = NULL; client_certs_.clear(); client_auth_cert_needed_ = false; @@ -1739,6 +1743,24 @@ SECStatus SSLClientSocketNSS::OwnAuthCertHandler(void* arg, base::TimeDelta::FromMilliseconds(kCorkTimeoutMs), that, &SSLClientSocketNSS::UncorkAfterTimeout); } + + // ESET anti-virus is capable of intercepting HTTPS connections on Windows. + // However, it is False Start intolerant and causes the connections to hang + // forever. We detect ESET by the issuer of the leaf certificate and set a + // flag to return a specific error, giving the user instructions for + // reconfiguring ESET. + CERTCertificate* cert = SSL_PeerCertificate(that->nss_fd_); + if (cert) { + char* common_name = CERT_GetCommonName(&cert->issuer); + if (common_name) { + if (strcmp(common_name, "ESET_RootSslCert") == 0) + that->eset_mitm_detected_ = true; + if (strcmp(common_name, "ContentWatch Root Certificate Authority") == 0) + that->netnanny_mitm_detected_ = true; + PORT_Free(common_name); + } + CERT_DestroyCertificate(cert); + } } #endif @@ -2024,18 +2046,24 @@ int SSLClientSocketNSS::DoHandshake() { } } else if (rv == SECSuccess) { if (handshake_callback_called_) { - SaveSnapStartInfo(); - // SSL handshake is completed. It's possible that we mispredicted the NPN - // agreed protocol. In this case, we've just sent a request in the wrong - // protocol! The higher levels of this network stack aren't prepared for - // switching the protocol like that so we make up an error and rely on - // the fact that the request will be retried. - if (IsNPNProtocolMispredicted()) { - LOG(WARNING) << "Mispredicted NPN protocol for " << hostname_; - net_error = ERR_SSL_SNAP_START_NPN_MISPREDICTION; + if (eset_mitm_detected_) { + net_error = ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION; + } else if (netnanny_mitm_detected_) { + net_error = ERR_NETNANNY_SSL_INTERCEPTION; } else { - // Let's verify the certificate. - GotoState(STATE_VERIFY_DNSSEC); + SaveSnapStartInfo(); + // SSL handshake is completed. It's possible that we mispredicted the NPN + // agreed protocol. In this case, we've just sent a request in the wrong + // protocol! The higher levels of this network stack aren't prepared for + // switching the protocol like that so we make up an error and rely on + // the fact that the request will be retried. + if (IsNPNProtocolMispredicted()) { + LOG(WARNING) << "Mispredicted NPN protocol for " << hostname_; + net_error = ERR_SSL_SNAP_START_NPN_MISPREDICTION; + } else { + // Let's verify the certificate. + GotoState(STATE_VERIFY_DNSSEC); + } } // Done! } else { diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h index 7b9809b..db567c4 100644 --- a/net/socket/ssl_client_socket_nss.h +++ b/net/socket/ssl_client_socket_nss.h @@ -178,6 +178,14 @@ class SSLClientSocketNSS : public SSLClientSocket { // Write call into a Snap Start handshake. bool pseudo_connected_; + // True iff we believe that the user has an ESET product intercepting our + // HTTPS connections. + bool eset_mitm_detected_; + + // True iff we believe that the user has NetNanny intercepting our HTTPS + // connections. + bool netnanny_mitm_detected_; + // This pointer is owned by the caller of UseDNSSEC. DNSSECProvider* dnssec_provider_; // The time when we started waiting for DNSSEC records. |