blob: 54fa0b036a238f6926328168a18e04704e3b786a [file] [log] [blame]
// Copyright 2016 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 "content/browser/ssl/ssl_manager.h"
#include "base/macros.h"
#include "content/browser/site_instance_impl.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/ssl_status.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_renderer_host.h"
#include "content/test/test_web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace {
// A WebContentsDelegate that exposes the visible SSLStatus at the time
// of the last VisibleSecurityStateChanged() call.
class TestWebContentsDelegate : public WebContentsDelegate {
public:
TestWebContentsDelegate() : WebContentsDelegate() {}
~TestWebContentsDelegate() override {}
const SSLStatus& last_ssl_state() { return last_ssl_state_; }
// WebContentsDelegate:
void VisibleSecurityStateChanged(WebContents* source) override {
NavigationEntry* entry = source->GetController().GetVisibleEntry();
EXPECT_TRUE(entry);
last_ssl_state_ = entry->GetSSL();
}
private:
SSLStatus last_ssl_state_;
DISALLOW_COPY_AND_ASSIGN(TestWebContentsDelegate);
};
class SSLManagerTest : public RenderViewHostTestHarness {
public:
SSLManagerTest() : RenderViewHostTestHarness() {}
~SSLManagerTest() override {}
private:
DISALLOW_COPY_AND_ASSIGN(SSLManagerTest);
};
// Tests that VisibleSecurityStateChanged() is called when a password input
// is shown on an HTTP page.
TEST_F(SSLManagerTest, NotifyVisibleSSLStateChangeOnHttpPassword) {
TestWebContentsDelegate delegate;
web_contents()->SetDelegate(&delegate);
SSLManager manager(
static_cast<NavigationControllerImpl*>(&web_contents()->GetController()));
NavigateAndCommit(GURL("http://example.test"));
EXPECT_FALSE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
web_contents()->OnPasswordInputShownOnHttp();
EXPECT_TRUE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
}
// Tests that VisibleSecurityStateChanged() is called when a credit card input
// is shown on an HTTP page.
TEST_F(SSLManagerTest, NotifyVisibleSSLStateChangeOnHttpCreditCard) {
TestWebContentsDelegate delegate;
web_contents()->SetDelegate(&delegate);
SSLManager manager(
static_cast<NavigationControllerImpl*>(&web_contents()->GetController()));
NavigateAndCommit(GURL("http://example.test"));
EXPECT_FALSE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP);
web_contents()->OnCreditCardInputShownOnHttp();
EXPECT_TRUE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP);
}
// Tests that VisibleSecurityStateChanged() is called when password and
// credit card inputs are shown on an HTTP page.
TEST_F(SSLManagerTest, NotifyVisibleSSLStateChangeOnPasswordAndHttpCreditCard) {
TestWebContentsDelegate delegate;
web_contents()->SetDelegate(&delegate);
SSLManager manager(
static_cast<NavigationControllerImpl*>(&web_contents()->GetController()));
NavigateAndCommit(GURL("http://example.test"));
EXPECT_FALSE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
EXPECT_FALSE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP);
web_contents()->OnPasswordInputShownOnHttp();
web_contents()->OnCreditCardInputShownOnHttp();
EXPECT_TRUE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
EXPECT_TRUE(delegate.last_ssl_state().content_status &
SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP);
}
// Returns true if the given |sink| has received a Symantec warning console
// message, and false otherwise.
bool FindSymantecConsoleMessage(const IPC::TestSink& sink) {
for (size_t i = 0; i < sink.message_count(); i++) {
const IPC::Message* message = sink.GetMessageAt(i);
if (message->type() != FrameMsg_AddMessageToConsole::ID)
continue;
std::tuple<ConsoleMessageLevel, std::string> params;
FrameMsg_AddMessageToConsole::Read(message, &params);
if (std::get<0>(params) == CONSOLE_MESSAGE_LEVEL_WARNING &&
std::get<1>(params).find("will be distrusted") != std::string::npos) {
return true;
}
}
return false;
}
TEST_F(SSLManagerTest, SymantecConsoleMessage) {
SSLManager manager(
static_cast<NavigationControllerImpl*>(&web_contents()->GetController()));
// Set up a navigation entry with a Symantec public key hash and simulate
// navigation to that entry.
NavigateAndCommit(GURL("https://example.test"));
net::SHA256HashValue symantec_hash_value = {
{0xb2, 0xde, 0xf5, 0x36, 0x2a, 0xd3, 0xfa, 0xcd, 0x04, 0xbd, 0x29,
0x04, 0x7a, 0x43, 0x84, 0x4f, 0x76, 0x70, 0x34, 0xea, 0x48, 0x92,
0xf8, 0x0e, 0x56, 0xbe, 0xe6, 0x90, 0x24, 0x3e, 0x25, 0x02}};
web_contents()
->GetController()
.GetLastCommittedEntry()
->GetSSL()
.public_key_hashes.push_back(net::HashValue(symantec_hash_value));
process()->sink().ClearMessages();
// Navigate to the current entry, which now looks like a Symantec certificate.
Reload();
// Check that the expected console message was sent to the renderer to log.
EXPECT_TRUE(FindSymantecConsoleMessage(process()->sink()));
// Check that the console message is not logged when the certificate chain
// includes an excluded subCA.
net::SHA256HashValue google_hash_value = {
{0xec, 0x72, 0x29, 0x69, 0xcb, 0x64, 0x20, 0x0a, 0xb6, 0x63, 0x8f,
0x68, 0xac, 0x53, 0x8e, 0x40, 0xab, 0xab, 0x5b, 0x19, 0xa6, 0x48,
0x56, 0x61, 0x04, 0x2a, 0x10, 0x61, 0xc4, 0x61, 0x27, 0x76}};
web_contents()
->GetController()
.GetLastCommittedEntry()
->GetSSL()
.public_key_hashes.push_back(net::HashValue(google_hash_value));
process()->sink().ClearMessages();
// Navigate to the current entry, which now includes an excluded subCA.
Reload();
// Check that the expected console message was not sent to the renderer to
// log.
EXPECT_FALSE(FindSymantecConsoleMessage(process()->sink()));
}
} // namespace
} // namespace content