Skip to content

Commit

Permalink
Use different Symantec console message for Chrome
Browse files Browse the repository at this point in the history
Add a ContentBrowserClient method to customize the console message for upcoming
Symantec distrust events. ChromeContentBrowserClient implements this method to
customize the message for pre- and post-June 2016 issuance: the latter will be
distrusted in Chrome 66.

Bug: 763984
Change-Id: Idb8ca04347b91054faaf9fc4a913d019bc932a7c
Reviewed-on: https://chromium-review.googlesource.com/674062
Commit-Queue: Emily Stark <estark@chromium.org>
Reviewed-by: Ryan Sleevi <rsleevi@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#503376}
  • Loading branch information
estark37 authored and Commit Bot committed Sep 21, 2017
1 parent cafcc82 commit 70614f6
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 7 deletions.
18 changes: 18 additions & 0 deletions chrome/browser/chrome_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3427,6 +3427,24 @@ ChromeContentBrowserClient::CreateURLLoaderThrottles(
return result;
}

bool ChromeContentBrowserClient::OverrideLegacySymantecCertConsoleMessage(
const GURL& url,
const scoped_refptr<net::X509Certificate>& cert,
std::string* console_message) {
// Certificates issued before June 1, 2016 will be distrusted in Chrome 66.
base::Time chrome_66_not_before = base::Time::FromDoubleT(1464739200);
std::string in_future_string = cert->valid_start() <= chrome_66_not_before
? "in Chrome 66"
: "in an upcoming release of Chrome";
*console_message =
"The certificate used to load " + url.spec() +
" uses an SSL certificate that will be distrusted " + in_future_string +
". Once distrusted, users will be prevented from "
"loading this resource. See https://g.co/chrome/symantecpkicerts for "
"more information.";
return true;
}

// Static; handles rewriting Web UI URLs.
bool ChromeContentBrowserClient::HandleWebUI(
GURL* url,
Expand Down
4 changes: 4 additions & 0 deletions chrome/browser/chrome_content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
std::vector<std::unique_ptr<content::URLLoaderThrottle>>
CreateURLLoaderThrottles(
const base::Callback<content::WebContents*()>& wc_getter) override;
bool OverrideLegacySymantecCertConsoleMessage(
const GURL& url,
const scoped_refptr<net::X509Certificate>& cert,
std::string* console_messsage) override;

protected:
static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context);
Expand Down
117 changes: 117 additions & 0 deletions chrome/browser/ssl/ssl_browser_tests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/pattern.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
Expand Down Expand Up @@ -6047,6 +6048,122 @@ IN_PROC_BROWSER_TEST_F(SuperfishSSLUITest, SuperfishInterstitialDisabled) {
interstitial_page, expected_title));
}

// Allows tests to effectively turn off CT requirements. Used by
// SymantecMessageSSLUITest below to test Symantec certificates issued after the
// CT requirement date.
class NoRequireCTDelegate
: public net::TransportSecurityState::RequireCTDelegate {
public:
NoRequireCTDelegate() {}
~NoRequireCTDelegate() override = default;

CTRequirementLevel IsCTRequiredForHost(const std::string& hostname) override {
return CTRequirementLevel::NOT_REQUIRED;
}
};

void SetRequireCTDelegateOnIOThread(
scoped_refptr<net::URLRequestContextGetter> context_getter,
net::TransportSecurityState::RequireCTDelegate* delegate) {
net::TransportSecurityState* state =
context_getter->GetURLRequestContext()->transport_security_state();
state->SetRequireCTDelegate(delegate);
}

// A test fixture that mocks certificate verifications for legacy Symantec
// certificates that are slated to be distrusted in future Chrome releases.
class SymantecMessageSSLUITest : public CertVerifierBrowserTest {
public:
SymantecMessageSSLUITest()
: CertVerifierBrowserTest(),
https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
~SymantecMessageSSLUITest() override {}

void SetUpOnMainThread() override {
CertVerifierBrowserTest::SetUpOnMainThread();

require_ct_delegate_ = base::MakeUnique<NoRequireCTDelegate>();
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(
&SetRequireCTDelegateOnIOThread,
base::RetainedRef(browser()->profile()->GetRequestContext()),
require_ct_delegate_.get()));
}

protected:
void SetUpCertVerifier(bool use_chrome_66_date) {
net::CertVerifyResult verify_result;
{
base::ThreadRestrictions::ScopedAllowIO allow_io;
verify_result.verified_cert = net::CreateCertificateChainFromFile(
net::GetTestCertsDirectory(),
use_chrome_66_date ? "pre_june_2016.pem" : "post_june_2016.pem",
net::X509Certificate::FORMAT_AUTO);
}
ASSERT_TRUE(verify_result.verified_cert);
verify_result.cert_status = 0;

// Collect the hashes of the leaf and intermediates.
verify_result.public_key_hashes.push_back(
GetSPKIHash(verify_result.verified_cert.get()));
for (const net::X509Certificate::OSCertHandle& intermediate :
verify_result.verified_cert->GetIntermediateCertificates()) {
scoped_refptr<net::X509Certificate> intermediate_x509 =
net::X509Certificate::CreateFromHandle(
intermediate, net::X509Certificate::OSCertHandles());
ASSERT_TRUE(intermediate_x509);
verify_result.public_key_hashes.push_back(
GetSPKIHash(intermediate_x509.get()));
}

mock_cert_verifier()->AddResultForCert(https_server_.GetCertificate().get(),
verify_result, net::OK);
}

net::EmbeddedTestServer* https_server() { return &https_server_; }

private:
net::EmbeddedTestServer https_server_;
std::unique_ptr<NoRequireCTDelegate> require_ct_delegate_;

DISALLOW_COPY_AND_ASSIGN(SymantecMessageSSLUITest);
};

// Tests that the Symantec console message is properly overridden for pre-June
// 2016 certificates.
IN_PROC_BROWSER_TEST_F(SymantecMessageSSLUITest, PreJune2016) {
ASSERT_NO_FATAL_FAILURE(
SetUpCertVerifier(true /* use Chrome 66 distrust date */));
ASSERT_TRUE(https_server()->Start());
GURL url(https_server()->GetURL("/ssl/google.html"));
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
content::ConsoleObserverDelegate console_observer(
tab, "*distrusted in Chrome 66*");
tab->SetDelegate(&console_observer);
ui_test_utils::NavigateToURL(browser(), url);
console_observer.Wait();
EXPECT_TRUE(base::MatchPattern(console_observer.message(),
"*The certificate used to load*"));
}

// Tests that the Symantec console message is properly overridden for post-June
// 2016 certificates.
IN_PROC_BROWSER_TEST_F(SymantecMessageSSLUITest, PostJune2016) {
ASSERT_NO_FATAL_FAILURE(
SetUpCertVerifier(false /* use Chrome 66 distrust date */));
ASSERT_TRUE(https_server()->Start());
GURL url(https_server()->GetURL("/ssl/google.html"));
WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
content::ConsoleObserverDelegate console_observer(
tab, "*distrusted in Chrome 66*");
tab->SetDelegate(&console_observer);
ui_test_utils::NavigateToURL(browser(), url);
console_observer.Wait();
EXPECT_TRUE(base::MatchPattern(console_observer.message(),
"*The certificate used to load*"));
}

// TODO(jcampan): more tests to do below.

// Visit a page over https that contains a frame with a redirect.
Expand Down
22 changes: 16 additions & 6 deletions content/browser/ssl/ssl_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum SSLGoodCertSeenEvent {
// certificate |cert|, and if so, logs a console warning in |web_contents|.
void MaybeLogLegacySymantecWarning(
const LoadCommittedDetails& details,
const scoped_refptr<net::X509Certificate>& cert,
const net::HashValueVector& public_key_hashes,
content::WebContents* web_contents) {
// No need to log on same-page navigations, because the message would be
Expand All @@ -57,13 +58,21 @@ void MaybeLogLegacySymantecWarning(
return;
if (!net::IsLegacySymantecCert(public_key_hashes))
return;
std::string content_client_message;
GURL url = details.entry->GetURL();
bool message_overridden =
GetContentClient()->browser()->OverrideLegacySymantecCertConsoleMessage(
url, cert, &content_client_message);
web_contents->GetMainFrame()->AddMessageToConsole(
CONSOLE_MESSAGE_LEVEL_WARNING,
"The certificate used to load " + details.entry->GetURL().spec() +
" uses an SSL certificate that will be distrusted in an upcoming "
"release of Chrome. Once distrusted, users will be prevented from "
"loading this resource. See https://g.co/chrome/symantecpkicerts for "
"more information.");
message_overridden ? content_client_message
: "The certificate used to load " + url.spec() +
" uses an SSL certificate that will be "
"distrusted in the future. "
"Once distrusted, users will be prevented from "
"loading this resource. See "
"https://g.co/chrome/symantecpkicerts for "
"more information.");
}

void OnAllowCertificateWithRecordDecision(
Expand Down Expand Up @@ -218,7 +227,8 @@ void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) {
int add_content_status_flags = 0;
int remove_content_status_flags = 0;

MaybeLogLegacySymantecWarning(details, entry->GetSSL().public_key_hashes,
MaybeLogLegacySymantecWarning(details, entry->GetSSL().certificate,
entry->GetSSL().public_key_hashes,
controller_->delegate()->GetWebContents());

if (!details.is_main_frame) {
Expand Down
7 changes: 7 additions & 0 deletions content/public/browser/content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -507,4 +507,11 @@ mojom::NetworkContextPtr ContentBrowserClient::CreateNetworkContext(
return network_context;
}

bool ContentBrowserClient::OverrideLegacySymantecCertConsoleMessage(
const GURL& url,
const scoped_refptr<net::X509Certificate>& cert,
std::string* console_messsage) {
return false;
}

} // namespace content
11 changes: 11 additions & 0 deletions content/public/browser/content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,17 @@ class CONTENT_EXPORT ContentBrowserClient {
BrowserContext* context,
bool in_memory,
const base::FilePath& relative_partition_path);

// Called when a main-frame navigation to |url| commits using a legacy
// Symantec certificate that will be distrusted in future. Allows the embedder
// to override the message that is added to the console to inform developers
// that their certificate will be distrusted in future. If the method returns
// true, then |*console_message| will be printed to the console; otherwise a
// generic mesage will be used.
virtual bool OverrideLegacySymantecCertConsoleMessage(
const GURL& url,
const scoped_refptr<net::X509Certificate>& cert,
std::string* console_messsage);
};

} // namespace content
Expand Down
5 changes: 4 additions & 1 deletion net/data/ssl/certificates/README
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ unit tests.
- pre_june_2016.pem
- post_june_2016.pem
Certs to test that policies related to enforcing CT on Symantec are
properly gated on the issuance date.
properly gated on the issuance date. These files also contain legacy
Symantec roots to simulate a chain for testing the upcoming Symantec
distrust events; see https://g.co/chrome/symantecpkicerts. (Note,
however, that the leaf and root do not actually form a chain.)

- tls_feature_extension.pem
A certificate that contains the TLS Feature Extension.
Expand Down
73 changes: 73 additions & 0 deletions net/data/ssl/certificates/post_june_2016.pem
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,76 @@ gc5OuYdfLv0Sisr7U0a1LRZX/cpkXncmSPZSKXChZ8JcEBMHWhvVnzgZXNih4xsJ
O/9W/X1XdF+cFJKzPo/2C/D1JU8LBd6th5pP5Le0Ld4xLBRJv+8KDLZPHlPUUCPH
tHhm
-----END CERTIFICATE-----

Certificate:
Data:
Version: 3 (0x2)
Serial Number: 903804111 (0x35def4cf)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, O=Equifax, OU=Equifax Secure Certificate Authority
Validity
Not Before: Aug 22 16:41:51 1998 GMT
Not After : Aug 22 16:41:51 2018 GMT
Subject: C=US, O=Equifax, OU=Equifax Secure Certificate Authority
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:c1:5d:b1:58:67:08:62:ee:a0:9a:2d:1f:08:6d:
91:14:68:98:0a:1e:fe:da:04:6f:13:84:62:21:c3:
d1:7c:ce:9f:05:e0:b8:01:f0:4e:34:ec:e2:8a:95:
04:64:ac:f1:6b:53:5f:05:b3:cb:67:80:bf:42:02:
8e:fe:dd:01:09:ec:e1:00:14:4f:fc:fb:f0:0c:dd:
43:ba:5b:2b:e1:1f:80:70:99:15:57:93:16:f1:0f:
97:6a:b7:c2:68:23:1c:cc:4d:59:30:ac:51:1e:3b:
af:2b:d6:ee:63:45:7b:c5:d9:5f:50:d2:e3:50:0f:
3a:88:e7:bf:14:fd:e0:c7:b9
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 CRL Distribution Points:

Full Name:
DirName: C = US, O = Equifax, OU = Equifax Secure Certificate Authority, CN = CRL1

X509v3 Private Key Usage Period:
Not After: Aug 22 16:41:51 2018 GMT
X509v3 Key Usage:
Certificate Sign, CRL Sign
X509v3 Authority Key Identifier:
keyid:48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4

X509v3 Subject Key Identifier:
48:E6:68:F9:2B:D2:B2:95:D7:47:D8:23:20:10:4F:33:98:90:9F:D4
X509v3 Basic Constraints:
CA:TRUE
1.2.840.113533.7.65.0:
0...V3.0c....
Signature Algorithm: sha1WithRSAEncryption
58:ce:29:ea:fc:f7:de:b5:ce:02:b9:17:b5:85:d1:b9:e3:e0:
95:cc:25:31:0d:00:a6:92:6e:7f:b6:92:63:9e:50:95:d1:9a:
6f:e4:11:de:63:85:6e:98:ee:a8:ff:5a:c8:d3:55:b2:66:71:
57:de:c0:21:eb:3d:2a:a7:23:49:01:04:86:42:7b:fc:ee:7f:
a2:16:52:b5:67:67:d3:40:db:3b:26:58:b2:28:77:3d:ae:14:
77:61:d6:fa:2a:66:27:a0:0d:fa:a7:73:5c:ea:70:f1:94:21:
65:44:5f:fa:fc:ef:29:68:a9:a2:87:79:ef:79:ef:4f:ac:07:
77:38
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----

Loading

0 comments on commit 70614f6

Please sign in to comment.