summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/devtools/protocol/security_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/devtools/protocol/security_handler.cc')
-rw-r--r--chromium/chrome/browser/devtools/protocol/security_handler.cc246
1 files changed, 246 insertions, 0 deletions
diff --git a/chromium/chrome/browser/devtools/protocol/security_handler.cc b/chromium/chrome/browser/devtools/protocol/security_handler.cc
new file mode 100644
index 00000000000..a9db9463a58
--- /dev/null
+++ b/chromium/chrome/browser/devtools/protocol/security_handler.cc
@@ -0,0 +1,246 @@
+// 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));
+}