Commit e300b6ba authored by Lorne Mitchell's avatar Lorne Mitchell Committed by Commit Bot

DevTools: Modified Security.securityStateChanged to use types and data instead...

DevTools: Modified Security.securityStateChanged to use types and data instead of pre-processed English strings

This change modifies the shape of the Security.securityStateChanged (https://chromedevtools.github.io/devtools-protocol/tot/Security#event-securityStateChanged) CDP event to include the type of state that has changed along with the data needed to generate the details that are shown in the Security tool.

The strings that are currently present in security_state_strings.grdp will be moved to the DevTools frontend. security_state_strings.grdp will remain in place, so that we don't break backwards compat with Security.securityStateChanged. This will come in a separate CL.

Bug: 946860
Change-Id: I18a2ff879bf201d36cf02af88963dcb996c4811f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1646792
Commit-Queue: Lorne Mitchell <lomitch@microsoft.com>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#703417}
parent d3db848c
......@@ -26,6 +26,8 @@ if (!is_android) {
"protocol/page.h",
"protocol/protocol.cc",
"protocol/protocol.h",
"protocol/security.cc",
"protocol/security.h",
"protocol/target.cc",
"protocol/target.h",
]
......@@ -198,8 +200,10 @@ static_library("devtools") {
sources += [ "devtools_dock_tile.cc" ]
}
if (!is_android) {
deps += [ ":protocol_generated_sources",
"//third_party/inspector_protocol:encoding" ]
deps += [
":protocol_generated_sources",
"//third_party/inspector_protocol:encoding",
]
sources += [
"protocol/browser_handler.cc",
"protocol/browser_handler.h",
......@@ -207,6 +211,8 @@ static_library("devtools") {
"protocol/cast_handler.h",
"protocol/page_handler.cc",
"protocol/page_handler.h",
"protocol/security_handler.cc",
"protocol/security_handler.h",
"protocol/target_handler.cc",
"protocol/target_handler.h",
]
......
......@@ -9,6 +9,7 @@
#include "chrome/browser/devtools/protocol/browser_handler.h"
#include "chrome/browser/devtools/protocol/cast_handler.h"
#include "chrome/browser/devtools/protocol/page_handler.h"
#include "chrome/browser/devtools/protocol/security_handler.h"
#include "chrome/browser/devtools/protocol/target_handler.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_agent_host_client.h"
......@@ -64,6 +65,8 @@ ChromeDevToolsSession::ChromeDevToolsSession(
agent_host->GetType() == content::DevToolsAgentHost::kTypePage) {
page_handler_ = std::make_unique<PageHandler>(agent_host->GetWebContents(),
dispatcher_.get());
security_handler_ = std::make_unique<SecurityHandler>(
agent_host->GetWebContents(), dispatcher_.get());
if (client->MayAttachToBrowser()) {
cast_handler_ = std::make_unique<CastHandler>(
agent_host->GetWebContents(), dispatcher_.get());
......
......@@ -22,6 +22,7 @@ class DevToolsAgentHostClient;
class BrowserHandler;
class CastHandler;
class PageHandler;
class SecurityHandler;
class TargetHandler;
class WindowManagerHandler;
......@@ -61,6 +62,7 @@ class ChromeDevToolsSession : public protocol::FrontendChannel {
std::unique_ptr<BrowserHandler> browser_handler_;
std::unique_ptr<CastHandler> cast_handler_;
std::unique_ptr<PageHandler> page_handler_;
std::unique_ptr<SecurityHandler> security_handler_;
std::unique_ptr<TargetHandler> target_handler_;
#if defined(OS_CHROMEOS)
std::unique_ptr<WindowManagerHandler> window_manager_protocl_handler_;
......
......@@ -28,6 +28,11 @@
},
{
"domain": "WindowManager"
},
{
"domain": "Security",
"include": [ "enable", "disable" ],
"include_events": [ "visibleSecurityStateChanged" ]
}
]
},
......
// Copyright 2019 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/devtools/protocol/security_handler.h"
#include <string>
#include <vector>
#include "base/base64.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "components/security_state/content/content_utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/origin_util.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "net/ssl/ssl_cipher_suite_names.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
namespace {
const char kInsecureOriginSecurityStateIssueId[] = "insecure-origin";
const char kSchemeIsNotCryptographicSecurityStateIssueId[] =
"scheme-is-not-cryptographic";
const char kMalicousContentSecurityStateIssueId[] = "malicious-content";
const char kDisplayedMixedContentSecurityStateIssueId[] =
"displayed-mixed-content";
const char kContainedMixedFormSecurityStateIssueId[] = "contained-mixed-form";
const char kRanMixedContentSecurityStateIssueId[] = "ran-mixed-content";
const char kDisplayedContentWithCertErrorsSecurityStateIssueId[] =
"displayed-content-with-cert-errors";
const char kRanContentWithCertErrorSecurityStateIssueId[] =
"ran-content-with-cert-error";
const char kPkpBypassedSecurityStateIssueId[] = "pkp-bypassed";
const char kIsErrorPageSecurityStateIssueId[] = "is-error-page";
const char kInsecureInputEventsSecurityStateIssueId[] = "insecure-input-events";
std::string SecurityLevelToProtocolSecurityState(
security_state::SecurityLevel security_level) {
switch (security_level) {
case security_state::NONE:
case security_state::WARNING:
return protocol::Security::SecurityStateEnum::Neutral;
case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
case security_state::EV_SECURE:
case security_state::SECURE:
return protocol::Security::SecurityStateEnum::Secure;
case security_state::DANGEROUS:
return protocol::Security::SecurityStateEnum::Insecure;
case security_state::SECURITY_LEVEL_COUNT:
NOTREACHED();
return protocol::Security::SecurityStateEnum::Neutral;
}
NOTREACHED();
return protocol::Security::SecurityStateEnum::Neutral;
}
std::unique_ptr<protocol::Security::CertificateSecurityState>
CreateCertificateSecurityState(
const security_state::VisibleSecurityState& state) {
auto certificate = std::make_unique<protocol::Array<protocol::String>>();
if (state.certificate) {
certificate->emplace_back();
base::Base64Encode(net::x509_util::CryptoBufferAsStringPiece(
state.certificate->cert_buffer()),
&certificate->back());
for (const auto& cert : state.certificate->intermediate_buffers()) {
certificate->emplace_back();
base::Base64Encode(net::x509_util::CryptoBufferAsStringPiece(cert.get()),
&certificate->back());
}
}
int ssl_version = net::SSLConnectionStatusToVersion(state.connection_status);
const char* protocol;
net::SSLVersionToString(&protocol, ssl_version);
const char* key_exchange_str;
const char* cipher;
const char* mac;
bool is_aead;
bool is_tls13;
uint16_t cipher_suite =
net::SSLConnectionStatusToCipherSuite(state.connection_status);
net::SSLCipherSuiteToStrings(&key_exchange_str, &cipher, &mac, &is_aead,
&is_tls13, cipher_suite);
std::string key_exchange;
if (key_exchange_str)
key_exchange = key_exchange_str;
const char* key_exchange_group = SSL_get_curve_name(state.key_exchange_group);
std::string subject_name;
std::string issuer_name;
double valid_from = 0.0;
double valid_to = 0.0;
if (state.certificate) {
subject_name = state.certificate->subject().common_name;
issuer_name = state.certificate->issuer().common_name;
valid_from = state.certificate->valid_start().ToDoubleT();
valid_to = state.certificate->valid_expiry().ToDoubleT();
}
bool certificate_has_weak_signature =
(state.cert_status & net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
int status = net::ObsoleteSSLStatus(state.connection_status,
state.peer_signature_algorithm);
bool modern_ssl = status == net::OBSOLETE_SSL_NONE;
bool obsolete_ssl_protocol = status & net::OBSOLETE_SSL_MASK_PROTOCOL;
bool obsolete_ssl_key_exchange = status & net::OBSOLETE_SSL_MASK_KEY_EXCHANGE;
bool obsolete_ssl_cipher = status & net::OBSOLETE_SSL_MASK_CIPHER;
bool obsolete_ssl_signature = status & net::OBSOLETE_SSL_MASK_SIGNATURE;
auto certificate_security_state =
protocol::Security::CertificateSecurityState::Create()
.SetProtocol(protocol)
.SetKeyExchange(key_exchange)
.SetCipher(cipher)
.SetCertificate(std::move(certificate))
.SetSubjectName(subject_name)
.SetIssuer(issuer_name)
.SetValidFrom(valid_from)
.SetValidTo(valid_to)
.SetCertifcateHasWeakSignature(certificate_has_weak_signature)
.SetModernSSL(modern_ssl)
.SetObsoleteSslProtocol(obsolete_ssl_protocol)
.SetObsoleteSslKeyExchange(obsolete_ssl_key_exchange)
.SetObsoleteSslCipher(obsolete_ssl_cipher)
.SetObsoleteSslSignature(obsolete_ssl_signature)
.Build();
if (key_exchange_group)
certificate_security_state->SetKeyExchangeGroup(key_exchange_group);
if (mac)
certificate_security_state->SetMac(mac);
return certificate_security_state;
}
std::unique_ptr<protocol::Security::VisibleSecurityState>
CreateVisibleSecurityState(const security_state::VisibleSecurityState& state,
content::WebContents* web_contents) {
SecurityStateTabHelper* helper =
SecurityStateTabHelper::FromWebContents(web_contents);
DCHECK(helper);
std::string security_state =
SecurityLevelToProtocolSecurityState(helper->GetSecurityLevel());
bool scheme_is_cryptographic =
security_state::IsSchemeCryptographic(state.url);
bool malicious_content = state.malicious_content_status !=
security_state::MALICIOUS_CONTENT_STATUS_NONE;
bool insecure_input_events =
state.insecure_input_events.insecure_field_edited;
bool secure_origin = scheme_is_cryptographic;
if (!scheme_is_cryptographic)
secure_origin = content::IsOriginSecure(state.url);
std::vector<std::string> security_state_issue_ids;
if (!secure_origin)
security_state_issue_ids.push_back(kInsecureOriginSecurityStateIssueId);
if (!scheme_is_cryptographic)
security_state_issue_ids.push_back(
kSchemeIsNotCryptographicSecurityStateIssueId);
if (malicious_content)
security_state_issue_ids.push_back(kMalicousContentSecurityStateIssueId);
if (state.displayed_mixed_content)
security_state_issue_ids.push_back(
kDisplayedMixedContentSecurityStateIssueId);
if (state.contained_mixed_form)
security_state_issue_ids.push_back(kContainedMixedFormSecurityStateIssueId);
if (state.ran_mixed_content)
security_state_issue_ids.push_back(kRanMixedContentSecurityStateIssueId);
if (state.displayed_content_with_cert_errors)
security_state_issue_ids.push_back(
kDisplayedContentWithCertErrorsSecurityStateIssueId);
if (state.ran_content_with_cert_errors)
security_state_issue_ids.push_back(
kRanContentWithCertErrorSecurityStateIssueId);
if (state.pkp_bypassed)
security_state_issue_ids.push_back(kPkpBypassedSecurityStateIssueId);
if (state.is_error_page)
security_state_issue_ids.push_back(kIsErrorPageSecurityStateIssueId);
if (insecure_input_events)
security_state_issue_ids.push_back(
kInsecureInputEventsSecurityStateIssueId);
auto visible_security_state =
protocol::Security::VisibleSecurityState::Create()
.SetSecurityState(security_state)
.SetSecurityStateIssueIds(
std::make_unique<protocol::Array<std::string>>(
security_state_issue_ids))
.Build();
if (state.connection_status != 0) {
auto certificate_security_state = CreateCertificateSecurityState(state);
visible_security_state->SetCertificateSecurityState(
std::move(certificate_security_state));
}
return visible_security_state;
}
} // namespace
SecurityHandler::SecurityHandler(content::WebContents* web_contents,
protocol::UberDispatcher* dispatcher)
: content::WebContentsObserver(web_contents) {
DCHECK(web_contents);
frontend_ =
std::make_unique<protocol::Security::Frontend>(dispatcher->channel());
protocol::Security::Dispatcher::wire(dispatcher, this);
}
SecurityHandler::~SecurityHandler() {}
protocol::Response SecurityHandler::Enable() {
if (enabled_)
return protocol::Response::FallThrough();
enabled_ = true;
DidChangeVisibleSecurityState();
// Do not mark the command as handled. Let it fall through instead, so that
// the handler in content gets a chance to process the command.
return protocol::Response::FallThrough();
}
protocol::Response SecurityHandler::Disable() {
enabled_ = false;
// Do not mark the command as handled. Let it fall through instead, so that
// the handler in content gets a chance to process the command.
return protocol::Response::FallThrough();
}
void SecurityHandler::DidChangeVisibleSecurityState() {
if (!enabled_)
return;
auto state = security_state::GetVisibleSecurityState(web_contents());
auto visible_security_state =
CreateVisibleSecurityState(*state.get(), web_contents());
frontend_->VisibleSecurityStateChanged(std::move(visible_security_state));
}
// Copyright 2019 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.
#ifndef CHROME_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
#define CHROME_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
#include "chrome/browser/devtools/protocol/forward.h"
#include "chrome/browser/devtools/protocol/security.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
class WebContents;
} // namespace content
class SecurityHandler : public protocol::Security::Backend,
public content::WebContentsObserver {
public:
SecurityHandler(content::WebContents* web_contents,
protocol::UberDispatcher* dispatcher);
~SecurityHandler() override;
// Security::Backend:
protocol::Response Enable() override;
protocol::Response Disable() override;
private:
// WebContentsObserver overrides
void DidChangeVisibleSecurityState() override;
bool enabled_ = false;
std::unique_ptr<protocol::Security::Frontend> frontend_;
DISALLOW_COPY_AND_ASSIGN(SecurityHandler);
};
#endif // CHROME_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
......@@ -872,6 +872,7 @@ if (!is_android) {
"../browser/devtools/device/usb/android_usb_browsertest.cc",
"../browser/devtools/devtools_sanity_browsertest.cc",
"../browser/devtools/global_confirm_info_bar_browsertest.cc",
"../browser/devtools/protocol/devtools_protocol_browsertest.cc",
"../browser/dom_distiller/distillable_page_utils_browsertest.cc",
"../browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc",
"../browser/dom_distiller/tab_utils_browsertest.cc",
......
......@@ -6058,6 +6058,52 @@ domain Security
secure
info
# Details about the security state of the page certificate.
experimental type CertificateSecurityState extends object
properties
# Protocol name (e.g. "TLS 1.2" or "QUIC").
string protocol
# Key Exchange used by the connection, or the empty string if not applicable.
string keyExchange
# (EC)DH group used by the connection, if applicable.
optional string keyExchangeGroup
# Cipher name.
string cipher
# TLS MAC. Note that AEAD ciphers do not have separate MACs.
optional string mac
# Page certificate.
array of string certificate
# Certificate subject name.
string subjectName
# Name of the issuing CA.
string issuer
# Certificate valid from date.
Network.TimeSinceEpoch validFrom
# Certificate valid to (expiration) date
Network.TimeSinceEpoch validTo
# True if the certificate uses a weak signature aglorithm.
boolean certifcateHasWeakSignature
# True if modern SSL
boolean modernSSL
# True if the connection is using an obsolete SSL protocol.
boolean obsoleteSslProtocol
# True if the connection is using an obsolete SSL key exchange.
boolean obsoleteSslKeyExchange
# True if the connection is using an obsolete SSL cipher.
boolean obsoleteSslCipher
# True if the connection is using an obsolete SSL signature.
boolean obsoleteSslSignature
# Security state information about the page.
experimental type VisibleSecurityState extends object
properties
# The security level of the page.
SecurityState securityState
# Security state details about the page certificate.
optional CertificateSecurityState certificateSecurityState
# Array of security state issues ids.
array of string securityStateIssueIds
# An explanation of an factor contributing to the security state.
type SecurityStateExplanation extends object
properties
......@@ -6141,6 +6187,12 @@ domain Security
# The url that was requested.
string requestURL
# The security state of the page changed.
experimental event visibleSecurityStateChanged
parameters
# Security state information about the page.
VisibleSecurityState visibleSecurityState
# The security state of the page changed.
event securityStateChanged
parameters
......
......@@ -106,6 +106,12 @@ Security.SecurityDispatcher = class {
this._model.dispatchEventToListeners(Security.SecurityModel.Events.SecurityStateChanged, pageSecurityState);
}
/**
* @override
* @param {!Protocol.Security.VisibleSecurityState} visibleSecurityState
*/
visibleSecurityStateChanged(visibleSecurityState) {
}
/**
* @override
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment