blob: d2fbe6bc097c4c5bd0d94a98e8769ceefb7d1f30 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ssl/security_state_model.h"
#include "chrome/browser/ssl/security_state_model_client.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/cert_store.h"
#include "content/public/common/origin_util.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/test_data_directory.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_certificate_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kUrl[] = "https://foo.test";
class TestSecurityStateModelClient : public SecurityStateModelClient {
public:
TestSecurityStateModelClient()
: initial_security_style_(content::SECURITY_STYLE_AUTHENTICATED),
connection_status_(net::SSL_CONNECTION_VERSION_TLS1_2
<< net::SSL_CONNECTION_VERSION_SHIFT),
cert_status_(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT),
displayed_mixed_content_(false),
ran_mixed_content_(false) {
cert_ =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_2016.pem");
}
~TestSecurityStateModelClient() override {}
void set_connection_status(int connection_status) {
connection_status_ = connection_status;
}
void SetCipherSuite(uint16 ciphersuite) {
net::SSLConnectionStatusSetCipherSuite(ciphersuite, &connection_status_);
}
void AddCertStatus(net::CertStatus cert_status) {
cert_status_ |= cert_status;
}
void SetDisplayedMixedContent(bool displayed_mixed_content) {
displayed_mixed_content_ = displayed_mixed_content;
}
void SetRanMixedContent(bool ran_mixed_content) {
ran_mixed_content_ = ran_mixed_content;
}
void set_initial_security_style(content::SecurityStyle security_style) {
initial_security_style_ = security_style;
}
// SecurityStateModelClient:
void GetVisibleSecurityState(
SecurityStateModel::VisibleSecurityState* state) override {
state->url = GURL(kUrl);
state->initial_security_style = initial_security_style_;
state->cert_id = 1;
state->cert_status = cert_status_;
state->connection_status = connection_status_;
state->security_bits = 256;
state->displayed_mixed_content = displayed_mixed_content_;
state->ran_mixed_content = ran_mixed_content_;
}
bool RetrieveCert(scoped_refptr<net::X509Certificate>* cert) override {
*cert = cert_;
return true;
}
bool UsedPolicyInstalledCertificate() override { return false; }
bool IsOriginSecure(const GURL& url) override {
return content::IsOriginSecure(url);
}
private:
content::SecurityStyle initial_security_style_;
scoped_refptr<net::X509Certificate> cert_;
int connection_status_;
net::CertStatus cert_status_;
bool displayed_mixed_content_;
bool ran_mixed_content_;
};
class SecurityStateModelTest : public ChromeRenderViewHostTestHarness {};
// Tests that SHA1-signed certificates expiring in 2016 downgrade the
// security state of the page.
TEST_F(SecurityStateModelTest, SHA1Warning) {
SecurityStateModel::SecurityInfo security_info;
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
scoped_refptr<net::X509Certificate> cert;
ASSERT_TRUE(client.RetrieveCert(&cert));
SecurityStateModel::VisibleSecurityState visible_security_state;
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info.sha1_deprecation_status);
EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level);
}
// Tests that SHA1 warnings don't interfere with the handling of mixed
// content.
TEST_F(SecurityStateModelTest, SHA1WarningMixedContent) {
SecurityStateModel::SecurityInfo security_info;
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
scoped_refptr<net::X509Certificate> cert;
ASSERT_TRUE(client.RetrieveCert(&cert));
client.SetDisplayedMixedContent(true);
SecurityStateModel::VisibleSecurityState visible_security_state;
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info.sha1_deprecation_status);
EXPECT_EQ(SecurityStateModel::DISPLAYED_MIXED_CONTENT,
security_info.mixed_content_status);
EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level);
client.set_initial_security_style(
content::SECURITY_STYLE_AUTHENTICATION_BROKEN);
client.SetDisplayedMixedContent(false);
client.SetRanMixedContent(true);
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info.sha1_deprecation_status);
EXPECT_EQ(SecurityStateModel::RAN_MIXED_CONTENT,
security_info.mixed_content_status);
EXPECT_EQ(SecurityStateModel::SECURITY_ERROR, security_info.security_level);
}
// Tests that SHA1 warnings don't interfere with the handling of major
// cert errors.
TEST_F(SecurityStateModelTest, SHA1WarningBrokenHTTPS) {
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
scoped_refptr<net::X509Certificate> cert;
ASSERT_TRUE(client.RetrieveCert(&cert));
SecurityStateModel::SecurityInfo security_info;
client.set_initial_security_style(
content::SECURITY_STYLE_AUTHENTICATION_BROKEN);
client.AddCertStatus(net::CERT_STATUS_DATE_INVALID);
SecurityStateModel::VisibleSecurityState visible_security_state;
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_EQ(SecurityStateModel::DEPRECATED_SHA1_MINOR,
security_info.sha1_deprecation_status);
EXPECT_EQ(SecurityStateModel::SECURITY_ERROR, security_info.security_level);
}
// Tests that |security_info.is_secure_protocol_and_ciphersuite| is
// computed correctly.
TEST_F(SecurityStateModelTest, SecureProtocolAndCiphersuite) {
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
scoped_refptr<net::X509Certificate> cert;
ASSERT_TRUE(client.RetrieveCert(&cert));
SecurityStateModel::SecurityInfo security_info;
// TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-4
const uint16 ciphersuite = 0xc02f;
client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2
<< net::SSL_CONNECTION_VERSION_SHIFT);
client.SetCipherSuite(ciphersuite);
SecurityStateModel::VisibleSecurityState visible_security_state;
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_TRUE(security_info.is_secure_protocol_and_ciphersuite);
}
TEST_F(SecurityStateModelTest, NonsecureProtocol) {
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
scoped_refptr<net::X509Certificate> cert;
ASSERT_TRUE(client.RetrieveCert(&cert));
// TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-4
const uint16 ciphersuite = 0xc02f;
client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_1
<< net::SSL_CONNECTION_VERSION_SHIFT);
client.SetCipherSuite(ciphersuite);
SecurityStateModel::SecurityInfo security_info;
SecurityStateModel::VisibleSecurityState visible_security_state;
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_FALSE(security_info.is_secure_protocol_and_ciphersuite);
}
TEST_F(SecurityStateModelTest, NonsecureCiphersuite) {
TestSecurityStateModelClient client;
SecurityStateModel model;
model.SetClient(&client);
scoped_refptr<net::X509Certificate> cert;
ASSERT_TRUE(client.RetrieveCert(&cert));
// TLS_RSA_WITH_AES_128_CCM_8 from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-4
const uint16 ciphersuite = 0xc0a0;
client.set_connection_status(net::SSL_CONNECTION_VERSION_TLS1_2
<< net::SSL_CONNECTION_VERSION_SHIFT);
SecurityStateModel::SecurityInfo security_info;
client.SetCipherSuite(ciphersuite);
SecurityStateModel::VisibleSecurityState visible_security_state;
client.GetVisibleSecurityState(&visible_security_state);
SecurityStateModel::SecurityInfoForRequest(&client, visible_security_state,
cert, &security_info);
EXPECT_FALSE(security_info.is_secure_protocol_and_ciphersuite);
}
} // namespace