From 54545a8a6e2fd0d38ea68ef4271810d1f037adaf Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Mon, 11 Apr 2016 15:06:33 +0530 Subject: [PATCH] provide security style for devtools security panel --- atom/browser/api/atom_api_web_contents.cc | 3 + .../atom_security_state_model_client.cc | 105 +++++++++++++++++ .../atom_security_state_model_client.h | 42 +++++++ atom/browser/common_web_contents_delegate.cc | 107 ++++++++++++++++++ atom/browser/common_web_contents_delegate.h | 3 + atom/common/atom_constants.cc | 18 ++- atom/common/atom_constants.h | 12 +- filenames.gypi | 2 + 8 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 atom/browser/atom_security_state_model_client.cc create mode 100644 atom/browser/atom_security_state_model_client.h diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 81e2423a3519..02f3023bd178 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -13,6 +13,7 @@ #include "atom/browser/atom_browser_client.h" #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" +#include "atom/browser/atom_security_state_model_client.h" #include "atom/browser/native_window.h" #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/web_contents_permission_helper.h" @@ -277,6 +278,8 @@ WebContents::WebContents(v8::Isolate* isolate, // Intialize permission helper. WebContentsPermissionHelper::CreateForWebContents(web_contents); + // Intialize security state client. + AtomSecurityStateModelClient::CreateForWebContents(web_contents); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); diff --git a/atom/browser/atom_security_state_model_client.cc b/atom/browser/atom_security_state_model_client.cc new file mode 100644 index 000000000000..911849c5c2d1 --- /dev/null +++ b/atom/browser/atom_security_state_model_client.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/atom_security_state_model_client.h" + +#include "content/public/browser/cert_store.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/origin_util.h" +#include "content/public/common/ssl_status.h" +#include "net/cert/x509_certificate.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::AtomSecurityStateModelClient); + +using security_state::SecurityStateModel; + +namespace atom { + +namespace { + +SecurityStateModel::SecurityLevel GetSecurityLevelForSecurityStyle( + content::SecurityStyle style) { + switch (style) { + case content::SECURITY_STYLE_UNKNOWN: + return SecurityStateModel::NONE; + case content::SECURITY_STYLE_UNAUTHENTICATED: + return SecurityStateModel::NONE; + case content::SECURITY_STYLE_AUTHENTICATION_BROKEN: + return SecurityStateModel::SECURITY_ERROR; + case content::SECURITY_STYLE_WARNING: + return SecurityStateModel::SECURITY_WARNING; + case content::SECURITY_STYLE_AUTHENTICATED: + return SecurityStateModel::SECURE; + } + return SecurityStateModel::NONE; +} + +} // namespace + +AtomSecurityStateModelClient::AtomSecurityStateModelClient( + content::WebContents* web_contents) + : web_contents_(web_contents), + security_state_model_(new SecurityStateModel()) { + security_state_model_->SetClient(this); +} + +AtomSecurityStateModelClient::~AtomSecurityStateModelClient() { +} + +const SecurityStateModel::SecurityInfo& +AtomSecurityStateModelClient::GetSecurityInfo() const { + return security_state_model_->GetSecurityInfo(); +} + +bool AtomSecurityStateModelClient::RetrieveCert( + scoped_refptr* cert) { + content::NavigationEntry* entry = + web_contents_->GetController().GetVisibleEntry(); + if (!entry) + return false; + return content::CertStore::GetInstance()->RetrieveCert( + entry->GetSSL().cert_id, cert); +} + +bool AtomSecurityStateModelClient::UsedPolicyInstalledCertificate() { + return false; +} + +bool AtomSecurityStateModelClient::IsOriginSecure(const GURL& url) { + return content::IsOriginSecure(url); +} + +void AtomSecurityStateModelClient::GetVisibleSecurityState( + SecurityStateModel::VisibleSecurityState* state) { + content::NavigationEntry* entry = + web_contents_->GetController().GetVisibleEntry(); + if (!entry || + entry->GetSSL().security_style == content::SECURITY_STYLE_UNKNOWN) { + *state = SecurityStateModel::VisibleSecurityState(); + return; + } + + state->initialized = true; + state->url = entry->GetURL(); + const content::SSLStatus& ssl = entry->GetSSL(); + state->initial_security_level = + GetSecurityLevelForSecurityStyle(ssl.security_style); + state->cert_id = ssl.cert_id; + state->cert_status = ssl.cert_status; + state->connection_status = ssl.connection_status; + state->security_bits = ssl.security_bits; + state->sct_verify_statuses.clear(); + for (const auto& sct : ssl.signed_certificate_timestamp_ids) + state->sct_verify_statuses.push_back(sct.status); + state->displayed_mixed_content = + (ssl.content_status & content::SSLStatus::DISPLAYED_INSECURE_CONTENT) + ? true + : false; + state->ran_mixed_content = + (ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT) ? true + : false; +} + +} // namespace atom diff --git a/atom/browser/atom_security_state_model_client.h b/atom/browser/atom_security_state_model_client.h new file mode 100644 index 000000000000..cc943eb7f949 --- /dev/null +++ b/atom/browser/atom_security_state_model_client.h @@ -0,0 +1,42 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ +#define ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ + +#include "components/security_state/security_state_model.h" +#include "components/security_state/security_state_model_client.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace atom { + +class AtomSecurityStateModelClient + : public security_state::SecurityStateModelClient, + public content::WebContentsUserData { + public: + ~AtomSecurityStateModelClient() override; + + const security_state::SecurityStateModel::SecurityInfo& + GetSecurityInfo() const; + + // security_state::SecurityStateModelClient: + void GetVisibleSecurityState( + security_state::SecurityStateModel::VisibleSecurityState* state) override; + bool RetrieveCert(scoped_refptr* cert) override; + bool UsedPolicyInstalledCertificate() override; + bool IsOriginSecure(const GURL& url) override; + + private: + explicit AtomSecurityStateModelClient(content::WebContents* web_contents); + friend class content::WebContentsUserData; + + content::WebContents* web_contents_; + scoped_ptr security_state_model_; + + DISALLOW_COPY_AND_ASSIGN(AtomSecurityStateModelClient); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_ATOM_SECURITY_STATE_MODEL_CLIENT_H_ diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 62e854ac5655..4bebf7480b89 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -10,9 +10,11 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_javascript_dialog_manager.h" +#include "atom/browser/atom_security_state_model_client.h" #include "atom/browser/native_window.h" #include "atom/browser/ui/file_dialog.h" #include "atom/browser/web_dialog_helper.h" +#include "atom/common/atom_constants.h" #include "base/files/file_util.h" #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" @@ -25,6 +27,8 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" +#include "content/public/browser/security_style_explanation.h" +#include "content/public/browser/security_style_explanations.h" #include "storage/browser/fileapi/isolated_context.h" #if defined(TOOLKIT_VIEWS) @@ -36,6 +40,7 @@ #endif using content::BrowserThread; +using security_state::SecurityStateModel; namespace atom { @@ -140,6 +145,24 @@ std::set GetAddedFileSystemPaths( return result; } +content::SecurityStyle SecurityLevelToSecurityStyle( + SecurityStateModel::SecurityLevel security_level) { + switch (security_level) { + case SecurityStateModel::NONE: + return content::SECURITY_STYLE_UNAUTHENTICATED; + case SecurityStateModel::SECURITY_WARNING: + case SecurityStateModel::SECURITY_POLICY_WARNING: + return content::SECURITY_STYLE_WARNING; + case SecurityStateModel::EV_SECURE: + case SecurityStateModel::SECURE: + return content::SECURITY_STYLE_AUTHENTICATED; + case SecurityStateModel::SECURITY_ERROR: + return content::SECURITY_STYLE_AUTHENTICATION_BROKEN; + } + + return content::SECURITY_STYLE_UNKNOWN; +} + } // namespace CommonWebContentsDelegate::CommonWebContentsDelegate() @@ -265,6 +288,90 @@ bool CommonWebContentsDelegate::IsFullscreenForTabOrPending( return html_fullscreen_; } +content::SecurityStyle CommonWebContentsDelegate::GetSecurityStyle( + content::WebContents* web_contents, + content::SecurityStyleExplanations* explanations) { + auto model_client = + AtomSecurityStateModelClient::FromWebContents(web_contents); + + const SecurityStateModel::SecurityInfo& security_info = + model_client->GetSecurityInfo(); + + const content::SecurityStyle security_style = + SecurityLevelToSecurityStyle(security_info.security_level); + + explanations->ran_insecure_content_style = + SecurityLevelToSecurityStyle( + SecurityStateModel::kRanInsecureContentLevel); + explanations->displayed_insecure_content_style = + SecurityLevelToSecurityStyle( + SecurityStateModel::kDisplayedInsecureContentLevel); + + explanations->scheme_is_cryptographic = security_info.scheme_is_cryptographic; + if (!security_info.scheme_is_cryptographic) + return security_style; + + if (security_info.sha1_deprecation_status == + SecurityStateModel::DEPRECATED_SHA1_MAJOR) { + explanations->broken_explanations.push_back( + content::SecurityStyleExplanation( + kSHA1Certificate, + kSHA1MajorDescription, + security_info.cert_id)); + } else if (security_info.sha1_deprecation_status == + SecurityStateModel::DEPRECATED_SHA1_MINOR) { + explanations->unauthenticated_explanations.push_back( + content::SecurityStyleExplanation( + kSHA1Certificate, + kSHA1MinorDescription, + security_info.cert_id)); + } + + explanations->ran_insecure_content = + security_info.mixed_content_status == + SecurityStateModel::RAN_MIXED_CONTENT || + security_info.mixed_content_status == + SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; + explanations->displayed_insecure_content = + security_info.mixed_content_status == + SecurityStateModel::DISPLAYED_MIXED_CONTENT || + security_info.mixed_content_status == + SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT; + + if (net::IsCertStatusError(security_info.cert_status)) { + std::string error_string = net::ErrorToString( + net::MapCertStatusToNetError(security_info.cert_status)); + + content::SecurityStyleExplanation explanation( + kCertificateError, + "There are issues with the site's certificate chain " + error_string, + security_info.cert_id); + + if (net::IsCertStatusMinorError(security_info.cert_status)) + explanations->unauthenticated_explanations.push_back(explanation); + else + explanations->broken_explanations.push_back(explanation); + } else { + if (security_info.sha1_deprecation_status == + SecurityStateModel::NO_DEPRECATED_SHA1) { + explanations->secure_explanations.push_back( + content::SecurityStyleExplanation( + kValidCertificate, + kValidCertificateDescription, + security_info.cert_id)); + } + } + + if (security_info.is_secure_protocol_and_ciphersuite) { + explanations->secure_explanations.push_back( + content::SecurityStyleExplanation( + kSecureProtocol, + kSecureProtocolDescription)); + } + + return security_style; +} + void CommonWebContentsDelegate::DevToolsSaveToFile( const std::string& url, const std::string& content, bool save_as) { base::FilePath path; diff --git a/atom/browser/common_web_contents_delegate.h b/atom/browser/common_web_contents_delegate.h index 61ff63793df5..699d00e18bce 100644 --- a/atom/browser/common_web_contents_delegate.h +++ b/atom/browser/common_web_contents_delegate.h @@ -76,6 +76,9 @@ class CommonWebContentsDelegate void ExitFullscreenModeForTab(content::WebContents* source) override; bool IsFullscreenForTabOrPending( const content::WebContents* source) const override; + content::SecurityStyle GetSecurityStyle( + content::WebContents* web_contents, + content::SecurityStyleExplanations* explanations) override; // brightray::InspectableWebContentsDelegate: void DevToolsSaveToFile(const std::string& url, diff --git a/atom/common/atom_constants.cc b/atom/common/atom_constants.cc index dacda3c816c8..f66c947aa24c 100644 --- a/atom/common/atom_constants.cc +++ b/atom/common/atom_constants.cc @@ -6,6 +6,22 @@ namespace atom { -const char* kCORSHeader = "Access-Control-Allow-Origin: *"; +const char kCORSHeader[] = "Access-Control-Allow-Origin: *"; + +const char kSHA1Certificate[] = "SHA-1 Certificate"; +const char kSHA1MajorDescription[] = + "The certificate for this site expires in 2017 or later, " + "and the certificate chain contains a certificate signed using SHA-1."; +const char kSHA1MinorDescription[] = + "The certificate for this site expires in 2016, " + "and the certificate chain contains a certificate signed using SHA-1."; +const char kCertificateError[] = "Certificate Error"; +const char kValidCertificate[] = "Valid Certificate"; +const char kValidCertificateDescription[] = + "The connection to this site is using a valid, trusted server certificate."; +const char kSecureProtocol[] = "Secure TLS connection"; +const char kSecureProtocolDescription[] = + "The connection to this site is using a strong protocol version " + "and cipher suite."; } // namespace atom diff --git a/atom/common/atom_constants.h b/atom/common/atom_constants.h index e0d42e83eef9..b67b7b2e4ae5 100644 --- a/atom/common/atom_constants.h +++ b/atom/common/atom_constants.h @@ -8,7 +8,17 @@ namespace atom { // Header to ignore CORS. -extern const char* kCORSHeader; +extern const char kCORSHeader[]; + +// Strings describing Chrome security policy for DevTools security panel. +extern const char kSHA1Certificate[]; +extern const char kSHA1MajorDescription[]; +extern const char kSHA1MinorDescription[]; +extern const char kCertificateError[]; +extern const char kValidCertificate[]; +extern const char kValidCertificateDescription[]; +extern const char kSecureProtocol[]; +extern const char kSecureProtocolDescription[]; } // namespace atom diff --git a/filenames.gypi b/filenames.gypi index 688886b5b9cc..dd9edb409f59 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -157,6 +157,8 @@ 'atom/browser/atom_quota_permission_context.h', 'atom/browser/atom_resource_dispatcher_host_delegate.cc', 'atom/browser/atom_resource_dispatcher_host_delegate.h', + 'atom/browser/atom_security_state_model_client.cc', + 'atom/browser/atom_security_state_model_client.h', 'atom/browser/atom_speech_recognition_manager_delegate.cc', 'atom/browser/atom_speech_recognition_manager_delegate.h', 'atom/browser/bridge_task_runner.cc',