diff options
author | eranm@google.com <eranm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 13:23:32 +0000 |
---|---|---|
committer | eranm@google.com <eranm@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 13:23:32 +0000 |
commit | 7819e54ba24410465281d5175135cc83c60ceea0 (patch) | |
tree | c68ad13ca2d75340d010875c5817de2d1d355fda | |
parent | 8c3ac46c6cf1906d190d0dc3fd6c91f176f66b04 (diff) | |
download | chromium_src-7819e54ba24410465281d5175135cc83c60ceea0.zip chromium_src-7819e54ba24410465281d5175135cc83c60ceea0.tar.gz chromium_src-7819e54ba24410465281d5175135cc83c60ceea0.tar.bz2 |
A simple viewer for the Signed Certificate Timestamps.
This is modeled somewhat after the CollectedCookiesView.
There are two main components introduced:
* SignedCertificateTimestampInfoView: A grid layout for showing the details of a single SCT. That's where translation of numeric fields to names happens.
* SignedCertificateTimestampsViews is the dialogue itself, containing a SignedCertificateTimestampInfoView and a combo-box listing all SCTs available. This is also a grid layout with two padding columns.
Additionally, a function for translating between SCT ids and actual SCTs (ShowSignedCertificateTimestampsViewerByIds) was added in signed_certificate_timestamps_viewer.h.
Please ignore the changes under net - I am having them reviewed in a separate patch.
BUG=338370
Review URL: https://codereview.chromium.org/106833002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249680 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/generated_resources.grd | 95 | ||||
-rw-r--r-- | chrome/browser/ui/browser_dialogs.h | 7 | ||||
-rw-r--r-- | chrome/browser/ui/views/signed_certificate_timestamp_info_view.cc | 246 | ||||
-rw-r--r-- | chrome/browser/ui/views/signed_certificate_timestamp_info_view.h | 78 | ||||
-rw-r--r-- | chrome/browser/ui/views/signed_certificate_timestamps_views.cc | 199 | ||||
-rw-r--r-- | chrome/browser/ui/views/signed_certificate_timestamps_views.h | 78 | ||||
-rw-r--r-- | chrome/browser/ui/views/website_settings/website_settings_popup_view.cc | 29 | ||||
-rw-r--r-- | chrome/browser/ui/views/website_settings/website_settings_popup_view.h | 7 | ||||
-rw-r--r-- | chrome/chrome_browser_ui.gypi | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 4 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 |
11 files changed, 744 insertions, 4 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index cdd6dbf..75303bc 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3308,6 +3308,95 @@ Even if you have downloaded files from this website before, the website might ha </message> </if> + <!-- Signed Certificate Timestamps (SCTs) viewer --> + <message name="IDS_SCT_VIEWER_TITLE" desc="Title of Signed Certificate Timestamps viewer window"> + Signed Certificate Timestamps viewer + </message> + <message name="IDS_SCT_LOG_DESCRIPTION" desc="Name of the Certificate Transparency Log that issued this signed certificate timestamp"> + Log name + </message> + <message name="IDS_SCT_VALIDATION_INFO" desc="Signed Certificate Timestamp validation status"> + Validation status + </message> + <message name="IDS_SCT_STATUS_NONE" desc="SCT validation status: No SCT present"> + Not present + </message> + <message name="IDS_SCT_STATUS_LOG_UNKNOWN" desc="SCT validation status: SCT from unknown log"> + From an unknown log + </message> + <message name="IDS_SCT_STATUS_INVALID" desc="SCT validation status: Invalid"> + Validation failed + </message> + <message name="IDS_SCT_STATUS_OK" desc="SCT validation status: Verified OK"> + Verified + </message> + <message name="IDS_SCT_ORIGIN" desc="SCT Origin label"> + Origin + </message> + <message name="IDS_SCT_ORIGIN_EMBEDDED" desc="SCT is embedded in the certificate"> + Embedded + </message> + <message name="IDS_SCT_ORIGIN_TLS_EXTENSION" desc="SCT was provided during the TLS handshake"> + TLS Extension + </message> + <message name="IDS_SCT_ORIGIN_OCSP" desc="SCT was extracted from the OCSP response"> + OCSP response + </message> + <message name="IDS_SCT_ORIGIN_UNKNOWN" desc="SCT came from an unknown origin"> + Unknown + </message> + <message name="IDS_SCT_VERSION" desc="Version of SCT (numeric)"> + Version + </message> + <message name="IDS_SCT_TIMESTAMP" desc="Time when the SCT was issued by the log"> + Issued at + </message> + <message name="IDS_SCT_LOGID" desc="The ID of the Certificate Transparency log issuing this SCT (hex)"> + Log ID + </message> + <message name="IDS_SCT_HASH_ALGORITHM" desc="Hash algorithm used to hash the Precertificate that was signed"> + Hash algorithm + </message> + <message name="IDS_SCT_HASH_ALGORITHM_NONE" desc="None / invalid hash algorithm"> + None + </message> + <message name="IDS_SCT_HASH_ALGORITHM_MD5" desc="MD5 hash alrogithm"> + MD5 + </message> + <message name="IDS_SCT_HASH_ALGORITHM_SHA1" desc="SHA1 hash algorithm"> + SHA1 + </message> + <message name="IDS_SCT_HASH_ALGORITHM_SHA224" desc="SHA224 hash algorithm"> + SHA224 + </message> + <message name="IDS_SCT_HASH_ALGORITHM_SHA256" desc="SHA256 hash algorithm"> + SHA256 + </message> + <message name="IDS_SCT_HASH_ALGORITHM_SHA384" desc="SHA384 hash algorithm"> + SHA384 + </message> + <message name="IDS_SCT_HASH_ALGORITHM_SHA512" desc="SHA512 hash algorithm"> + SHA512 + </message> + <message name="IDS_SCT_SIGNATURE_ALGORITHM" desc="Signature algorithm used to sign over the Precertificate's hash"> + Signature algorithm + </message> + <message name="IDS_SCT_SIGNATURE_ALGORITHM_ANONYMOUS" desc="Unknown signature algorithm"> + Anonymous + </message> + <message name="IDS_SCT_SIGNATURE_ALGORITHM_RSA" desc="RSA signature algorithm"> + RSA + </message> + <message name="IDS_SCT_SIGNATURE_ALGORITHM_DSA" desc="DSA signature algorithm"> + DSA + </message> + <message name="IDS_SCT_SIGNATURE_ALGORITHM_ECDSA" desc="ECDSA signature algorithm"> + ECDSA + </message> + <message name="IDS_SCT_SIGNATURE_DATA" desc="The signature bytes (hex)"> + Signature data + </message> + <if expr="pp_ifdef('chromeos')"> <message name="IDS_CERT_MANAGER_IMPORT_AND_BIND_BUTTON" desc="Label for the button in the certificate manager which allows you to import certificates and bind to your device."> Import and Bind to Device... @@ -9453,11 +9542,17 @@ The following plug-in is unresponsive: <ph name="PLUGIN_NAME">$1 <message name="IDS_PAGEINFO_CERT_INFO_BUTTON" desc="Text of button in the page info that shows the SSL certificate."> Certificate information </message> + <message name="IDS_PAGEINFO_CERT_TRANSPARENCY_INFO_BUTTON" desc="Text of button in the page info that shows Signed Certificate Timestamps."> + Certificate transparency + </message> </if> <if expr="pp_ifdef('use_titlecase')"> <message name="IDS_PAGEINFO_CERT_INFO_BUTTON" desc="In Title Case: Text of button in the page info that shows the SSL certificate."> Certificate Information </message> + <message name="IDS_PAGEINFO_CERT_TRANSPARENCY_INFO_BUTTON" desc="Text of button in the page info that shows Signed Certificate Timestamps."> + Certificate Transparency + </message> </if> <message name="IDS_PAGE_INFO_HELP_CENTER_LINK" desc="This is the text of the link pointing to the Help Center. This appears at the bottom of the SSL dialog and 'this' refers to the sections within the bubble."> What do these mean? diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h index a1f96a6..98c5514 100644 --- a/chrome/browser/ui/browser_dialogs.h +++ b/chrome/browser/ui/browser_dialogs.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_BROWSER_DIALOGS_H_ #include "base/callback.h" +#include "content/public/common/signed_certificate_timestamp_id_and_status.h" #include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/native_widget_types.h" @@ -103,6 +104,12 @@ void ShowUserManager(const base::FilePath& profile_path_to_focus); // Hides the User Manager. void HideUserManager(); +// Shows the Signed Certificate Timestamps viewer, to view the signed +// certificate timestamps in |sct_ids_list| +void ShowSignedCertificateTimestampsViewer( + content::WebContents* web_contents, + const content::SignedCertificateTimestampIDStatusList& sct_ids_list); + } // namespace chrome #endif // CHROME_BROWSER_UI_BROWSER_DIALOGS_H_ diff --git a/chrome/browser/ui/views/signed_certificate_timestamp_info_view.cc b/chrome/browser/ui/views/signed_certificate_timestamp_info_view.cc new file mode 100644 index 0000000..8aeae2a --- /dev/null +++ b/chrome/browser/ui/views/signed_certificate_timestamp_info_view.cc @@ -0,0 +1,246 @@ +// Copyright 2014 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/ui/views/signed_certificate_timestamp_info_view.h" + +#include <algorithm> + +#include "base/i18n/time_formatting.h" +#include "base/strings/string16.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/common/net/x509_certificate_model.h" +#include "grit/generated_resources.h" +#include "net/cert/signed_certificate_timestamp.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/native_theme/native_theme.h" +#include "ui/views/border.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/layout/layout_constants.h" + +namespace { + +// Adjustment to the spacing between subsequent label-field lines. +const int kExtraLineHeightPadding = 3; + +int HashAlgorithmToResourceID( + net::ct::DigitallySigned::HashAlgorithm hash_algorithm) { + switch (hash_algorithm) { + case net::ct::DigitallySigned::HASH_ALGO_NONE: + return IDS_SCT_HASH_ALGORITHM_NONE; + case net::ct::DigitallySigned::HASH_ALGO_MD5: + return IDS_SCT_HASH_ALGORITHM_MD5; + case net::ct::DigitallySigned::HASH_ALGO_SHA1: + return IDS_SCT_HASH_ALGORITHM_SHA1; + case net::ct::DigitallySigned::HASH_ALGO_SHA224: + return IDS_SCT_HASH_ALGORITHM_SHA224; + case net::ct::DigitallySigned::HASH_ALGO_SHA256: + return IDS_SCT_HASH_ALGORITHM_SHA256; + case net::ct::DigitallySigned::HASH_ALGO_SHA384: + return IDS_SCT_HASH_ALGORITHM_SHA384; + case net::ct::DigitallySigned::HASH_ALGO_SHA512: + return IDS_SCT_HASH_ALGORITHM_SHA512; + } + return IDS_SCT_HASH_ALGORITHM_NONE; +} + +int SignatureAlgorithmToResourceID( + net::ct::DigitallySigned::SignatureAlgorithm signature_algorithm) { + switch (signature_algorithm) { + case net::ct::DigitallySigned::SIG_ALGO_ANONYMOUS: + return IDS_SCT_SIGNATURE_ALGORITHM_ANONYMOUS; + case net::ct::DigitallySigned::SIG_ALGO_RSA: + return IDS_SCT_SIGNATURE_ALGORITHM_RSA; + case net::ct::DigitallySigned::SIG_ALGO_DSA: + return IDS_SCT_SIGNATURE_ALGORITHM_DSA; + case net::ct::DigitallySigned::SIG_ALGO_ECDSA: + return IDS_SCT_SIGNATURE_ALGORITHM_ECDSA; + } + return IDS_SCT_SIGNATURE_ALGORITHM_ANONYMOUS; +} + +} // namespace + +namespace chrome { +namespace ct { + +int StatusToResourceID(net::ct::SCTVerifyStatus status) { + switch (status) { + case net::ct::SCT_STATUS_NONE: + return IDS_SCT_STATUS_NONE; + case net::ct::SCT_STATUS_LOG_UNKNOWN: + return IDS_SCT_STATUS_LOG_UNKNOWN; + case net::ct::SCT_STATUS_INVALID: + return IDS_SCT_STATUS_INVALID; + case net::ct::SCT_STATUS_OK: + return IDS_SCT_STATUS_OK; + case net::ct::SCT_STATUS_MAX: + break; + } + + return IDS_SCT_STATUS_NONE; +} + +int SCTOriginToResourceID(const net::ct::SignedCertificateTimestamp& sct) { + switch (sct.origin) { + case net::ct::SignedCertificateTimestamp::SCT_EMBEDDED: + return IDS_SCT_ORIGIN_EMBEDDED; + case net::ct::SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION: + return IDS_SCT_ORIGIN_TLS_EXTENSION; + case net::ct::SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE: + return IDS_SCT_ORIGIN_OCSP; + case net::ct::SignedCertificateTimestamp::SCT_ORIGIN_MAX: + break; + } + return IDS_SCT_ORIGIN_UNKNOWN; +} + +} // namespace ct +} // namespace chrome + +// SignedCertificateTimestampInfoView, public: + +SignedCertificateTimestampInfoView::SignedCertificateTimestampInfoView() + : status_value_field_(NULL), + origin_value_field_(NULL), + version_value_field_(NULL), + log_id_value_field_(NULL), + timestamp_value_field_(NULL), + hash_algorithm_value_field_(NULL), + signature_algorithm_value_field_(NULL), + signature_data_value_field_(NULL) {} + +SignedCertificateTimestampInfoView::~SignedCertificateTimestampInfoView() {} + +void SignedCertificateTimestampInfoView::SetSignedCertificateTimestamp( + const net::ct::SignedCertificateTimestamp& sct, + net::ct::SCTVerifyStatus status) { + status_value_field_->SetText( + l10n_util::GetStringUTF16(chrome::ct::StatusToResourceID(status))); + origin_value_field_->SetText( + l10n_util::GetStringUTF16(chrome::ct::SCTOriginToResourceID(sct))); + version_value_field_->SetText(base::IntToString16(sct.version)); + log_description_value_field_->SetText(base::UTF8ToUTF16(sct.log_description)); + timestamp_value_field_->SetText( + base::TimeFormatFriendlyDateAndTime(sct.timestamp)); + + hash_algorithm_value_field_->SetText(l10n_util::GetStringUTF16( + HashAlgorithmToResourceID(sct.signature.hash_algorithm))); + signature_algorithm_value_field_->SetText(l10n_util::GetStringUTF16( + SignatureAlgorithmToResourceID(sct.signature.signature_algorithm))); + + // The log_id and signature_data fields contain binary data, format it + // accordingly before displaying. + log_id_value_field_->SetText( + base::UTF8ToUTF16(x509_certificate_model::ProcessRawBytesWithSeparators( + reinterpret_cast<const unsigned char*>(sct.log_id.c_str()), + sct.log_id.length(), + ' ', + ' '))); + signature_data_value_field_->SetText( + base::UTF8ToUTF16(x509_certificate_model::ProcessRawBytesWithSeparators( + reinterpret_cast<const unsigned char*>( + sct.signature.signature_data.c_str()), + sct.signature.signature_data.length(), + ' ', + ' '))); + + Layout(); +} + +void SignedCertificateTimestampInfoView::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + if (details.is_add && details.child == this) + Init(); +} + +void SignedCertificateTimestampInfoView::AddLabelRow( + int layout_id, + views::GridLayout* layout, + int label_message_id, + views::Textfield* textfield) { + layout->StartRow(0, layout_id); + layout->AddView( + new views::Label(l10n_util::GetStringUTF16(label_message_id))); + layout->AddView( + textfield, 2, 1, views::GridLayout::FILL, views::GridLayout::CENTER); + layout->AddPaddingRow(0, kExtraLineHeightPadding); + + textfield->SetReadOnly(true); + // Color these borderless text areas the same as the containing dialog. + textfield->SetBackgroundColor(SK_ColorTRANSPARENT); + textfield->SetBorder(views::Border::NullBorder()); +} + +void SignedCertificateTimestampInfoView::Init() { + status_value_field_ = new views::Textfield; + origin_value_field_ = new views::Textfield; + version_value_field_ = new views::Textfield; + log_description_value_field_ = new views::Textfield; + log_id_value_field_ = new views::Textfield; + timestamp_value_field_ = new views::Textfield; + hash_algorithm_value_field_ = new views::Textfield; + signature_algorithm_value_field_ = new views::Textfield; + signature_data_value_field_ = new views::Textfield; + + views::GridLayout* layout = new views::GridLayout(this); + layout->SetInsets( + 0, views::kButtonHEdgeMarginNew, 0, views::kButtonHEdgeMarginNew); + SetLayoutManager(layout); + + const int three_column_layout_id = 0; + views::ColumnSet* column_set = layout->AddColumnSet(three_column_layout_id); + column_set->AddColumn(views::GridLayout::LEADING, + views::GridLayout::CENTER, + 0, + views::GridLayout::USE_PREF, + 0, + 0); + column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); + column_set->AddColumn(views::GridLayout::TRAILING, + views::GridLayout::CENTER, + 0, + views::GridLayout::USE_PREF, + 0, + 0); + column_set->AddColumn(views::GridLayout::FILL, + views::GridLayout::CENTER, + 1, + views::GridLayout::USE_PREF, + 0, + 0); + + AddLabelRow(three_column_layout_id, + layout, + IDS_SCT_VALIDATION_INFO, + status_value_field_); + AddLabelRow( + three_column_layout_id, layout, IDS_SCT_ORIGIN, origin_value_field_); + AddLabelRow( + three_column_layout_id, layout, IDS_SCT_VERSION, version_value_field_); + AddLabelRow(three_column_layout_id, + layout, + IDS_SCT_LOG_DESCRIPTION, + log_description_value_field_); + AddLabelRow( + three_column_layout_id, layout, IDS_SCT_LOGID, log_id_value_field_); + AddLabelRow(three_column_layout_id, + layout, + IDS_SCT_TIMESTAMP, + timestamp_value_field_); + AddLabelRow(three_column_layout_id, + layout, + IDS_SCT_HASH_ALGORITHM, + hash_algorithm_value_field_); + AddLabelRow(three_column_layout_id, + layout, + IDS_SCT_SIGNATURE_ALGORITHM, + signature_algorithm_value_field_); + AddLabelRow(three_column_layout_id, + layout, + IDS_SCT_SIGNATURE_DATA, + signature_data_value_field_); +} diff --git a/chrome/browser/ui/views/signed_certificate_timestamp_info_view.h b/chrome/browser/ui/views/signed_certificate_timestamp_info_view.h new file mode 100644 index 0000000..33fdfb7 --- /dev/null +++ b/chrome/browser/ui/views/signed_certificate_timestamp_info_view.h @@ -0,0 +1,78 @@ +// Copyright 2014 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_UI_VIEWS_SIGNED_CERTIFICATE_TIMESTAMP_INFO_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_SIGNED_CERTIFICATE_TIMESTAMP_INFO_VIEW_H_ + +#include <vector> + +#include "net/cert/sct_status_flags.h" +#include "ui/views/view.h" + +namespace views { +class GridLayout; +class Label; +class Textfield; +} + +namespace net { +namespace ct { +struct SignedCertificateTimestamp; +} +} + +namespace chrome { +namespace ct { + +// Utility function to translate an SCT status to resource ID. +int StatusToResourceID(net::ct::SCTVerifyStatus status); +int SCTOriginToResourceID(const net::ct::SignedCertificateTimestamp& sct); + +} // namespace ct +} // namespace chrome + +// Responsible for displaying a tabular grid of SCT information. +// Only displays information about one SCT at a time. +class SignedCertificateTimestampInfoView : public views::View { + public: + SignedCertificateTimestampInfoView(); + virtual ~SignedCertificateTimestampInfoView(); + + // Updates the display to show information for the given SCT. + void SetSignedCertificateTimestamp( + const net::ct::SignedCertificateTimestamp& sct, + net::ct::SCTVerifyStatus status); + + // Clears the SCT display to indicate that no SCT is selected. + void ClearDisplay(); + + private: + // views::View implementation + virtual void ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) + OVERRIDE; + + // Layout helper routines. + void AddLabelRow(int layout_id, + views::GridLayout* layout, + int label_message_id, + views::Textfield* text_field); + + // Sets up the view layout. + void Init(); + + // Individual property labels + views::Textfield* status_value_field_; + views::Textfield* origin_value_field_; + views::Textfield* version_value_field_; + views::Textfield* log_description_value_field_; + views::Textfield* log_id_value_field_; + views::Textfield* timestamp_value_field_; + views::Textfield* hash_algorithm_value_field_; + views::Textfield* signature_algorithm_value_field_; + views::Textfield* signature_data_value_field_; + + DISALLOW_COPY_AND_ASSIGN(SignedCertificateTimestampInfoView); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_SIGNED_CERTIFICATE_TIMESTAMP_INFO_VIEW_H_ diff --git a/chrome/browser/ui/views/signed_certificate_timestamps_views.cc b/chrome/browser/ui/views/signed_certificate_timestamps_views.cc new file mode 100644 index 0000000..aa11c29 --- /dev/null +++ b/chrome/browser/ui/views/signed_certificate_timestamps_views.cc @@ -0,0 +1,199 @@ +// Copyright 2014 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/ui/views/signed_certificate_timestamps_views.h" + +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/ui/views/constrained_window_views.h" +#include "chrome/browser/ui/views/signed_certificate_timestamp_info_view.h" +#include "components/web_modal/web_contents_modal_dialog_host.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/signed_certificate_timestamp_store.h" +#include "content/public/common/signed_certificate_timestamp_id_and_status.h" +#include "grit/generated_resources.h" +#include "net/cert/signed_certificate_timestamp.h" +#include "net/ssl/signed_certificate_timestamp_and_status.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/models/combobox_model.h" +#include "ui/views/controls/combobox/combobox.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/layout/layout_constants.h" +#include "ui/views/widget/widget.h" + +using web_modal::WebContentsModalDialogManager; +using web_modal::WebContentsModalDialogManagerDelegate; +using views::GridLayout; + +namespace { + +void SignedCertificateTimestampIDsToList( + const content::SignedCertificateTimestampIDStatusList& sct_ids_list, + net::SignedCertificateTimestampAndStatusList* sct_list) { + for (content::SignedCertificateTimestampIDStatusList::const_iterator it = + sct_ids_list.begin(); + it != sct_ids_list.end(); + ++it) { + scoped_refptr<net::ct::SignedCertificateTimestamp> sct; + content::SignedCertificateTimestampStore::GetInstance()->Retrieve(it->id, + &sct); + sct_list->push_back( + net::SignedCertificateTimestampAndStatus(sct, it->status)); + } +} + +} // namespace + +namespace chrome { + +void ShowSignedCertificateTimestampsViewer( + content::WebContents* web_contents, + const content::SignedCertificateTimestampIDStatusList& sct_ids_list) { + net::SignedCertificateTimestampAndStatusList sct_list; + SignedCertificateTimestampIDsToList(sct_ids_list, &sct_list); + new SignedCertificateTimestampsViews(web_contents, sct_list); +} + +} // namespace chrome + +class SCTListModel : public ui::ComboboxModel { + public: + explicit SCTListModel( + const net::SignedCertificateTimestampAndStatusList& sct_list); + virtual ~SCTListModel(); + + // Overridden from ui::ComboboxModel: + virtual int GetItemCount() const OVERRIDE; + virtual base::string16 GetItemAt(int index) OVERRIDE; + + private: + net::SignedCertificateTimestampAndStatusList sct_list_; + + DISALLOW_COPY_AND_ASSIGN(SCTListModel); +}; + +SCTListModel::SCTListModel( + const net::SignedCertificateTimestampAndStatusList& sct_list) + : sct_list_(sct_list) {} + +SCTListModel::~SCTListModel() {} + +int SCTListModel::GetItemCount() const { return sct_list_.size(); } + +base::string16 SCTListModel::GetItemAt(int index) { + DCHECK_LT(static_cast<size_t>(index), sct_list_.size()); + std::string origin = l10n_util::GetStringUTF8( + chrome::ct::SCTOriginToResourceID(*(sct_list_[index].sct))); + + std::string status = l10n_util::GetStringUTF8( + chrome::ct::StatusToResourceID(sct_list_[index].status)); + + // TODO(eranm): Internationalization: If the locale is a RTL one, + // format the string so that the index is on the right, status + // and origin on the left. Specifically: the format part should be a + // localized IDS string where the placeholders get rearranged for RTL locales, + // GetStringFUTF16 is used to replace the placeholders with these + // origin/status strings and the numbered index. + return base::UTF8ToUTF16(base::StringPrintf( + "%d: %s, %s", index + 1, origin.c_str(), status.c_str())); +} + +SignedCertificateTimestampsViews::SignedCertificateTimestampsViews( + content::WebContents* web_contents, + const net::SignedCertificateTimestampAndStatusList& sct_list) + : web_contents_(web_contents), sct_info_view_(NULL), sct_list_(sct_list) { + WebContentsModalDialogManager* web_contents_modal_dialog_manager = + WebContentsModalDialogManager::FromWebContents(web_contents); + WebContentsModalDialogManagerDelegate* modal_delegate = + web_contents_modal_dialog_manager->delegate(); + DCHECK(modal_delegate); + views::Widget* window = views::Widget::CreateWindowAsFramelessChild( + this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); + web_contents_modal_dialog_manager->ShowDialog(window->GetNativeView()); +} + +SignedCertificateTimestampsViews::~SignedCertificateTimestampsViews() {} + +base::string16 SignedCertificateTimestampsViews::GetWindowTitle() const { + return l10n_util::GetStringUTF16(IDS_SCT_VIEWER_TITLE); +} + +int SignedCertificateTimestampsViews::GetDialogButtons() const { + return ui::DIALOG_BUTTON_CANCEL; +} + +ui::ModalType SignedCertificateTimestampsViews::GetModalType() const { +#if defined(USE_ASH) + return ui::MODAL_TYPE_CHILD; +#else + return views::WidgetDelegate::GetModalType(); +#endif +} + +void SignedCertificateTimestampsViews::OnPerformAction( + views::Combobox* combobox) { + DCHECK_EQ(combobox, sct_selector_box_.get()); + DCHECK_LT(combobox->selected_index(), sct_list_model_->GetItemCount()); + ShowSCTInfo(combobox->selected_index()); +} + +gfx::Size SignedCertificateTimestampsViews::GetMinimumSize() { + // Allow UpdateWebContentsModalDialogPosition to clamp the dialog width. + return gfx::Size(View::GetMinimumSize().width() + 300, + View::GetMinimumSize().height()); +} + +void SignedCertificateTimestampsViews::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + if (details.is_add && details.child == this) + Init(); +} + +void SignedCertificateTimestampsViews::Init() { + GridLayout* layout = GridLayout::CreatePanel(this); + SetLayoutManager(layout); + + const int kSelectorBoxLayoutId = 0; + views::ColumnSet* column_set = layout->AddColumnSet(kSelectorBoxLayoutId); + column_set->AddColumn( + GridLayout::FILL, GridLayout::FILL, 1, GridLayout::USE_PREF, 0, 0); + + layout->StartRow(0, kSelectorBoxLayoutId); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Add SCT selector drop-down list. + layout->StartRow(0, kSelectorBoxLayoutId); + sct_list_model_.reset(new SCTListModel(sct_list_)); + sct_selector_box_.reset(new views::Combobox(sct_list_model_.get())); + sct_selector_box_->set_listener(this); + sct_selector_box_->set_owned_by_client(); + layout->AddView(sct_selector_box_.get()); + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + // Add the SCT info view, displaying information about a specific SCT. + layout->StartRow(0, kSelectorBoxLayoutId); + sct_info_view_ = new SignedCertificateTimestampInfoView(); + layout->AddView(sct_info_view_); + + sct_info_view_->SetSignedCertificateTimestamp(*(sct_list_[0].sct), + sct_list_[0].status); +} + +void SignedCertificateTimestampsViews::ShowSCTInfo(int sct_index) { + if ((sct_index < 0) || (static_cast<size_t>(sct_index) > sct_list_.size())) + return; + + sct_info_view_->SetSignedCertificateTimestamp(*(sct_list_[sct_index].sct), + sct_list_[sct_index].status); +} + +void SignedCertificateTimestampsViews::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + GetWidget()->Close(); +} diff --git a/chrome/browser/ui/views/signed_certificate_timestamps_views.h b/chrome/browser/ui/views/signed_certificate_timestamps_views.h new file mode 100644 index 0000000..247cf8a --- /dev/null +++ b/chrome/browser/ui/views/signed_certificate_timestamps_views.h @@ -0,0 +1,78 @@ +// Copyright 2014 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_UI_VIEWS_SIGNED_CERTIFICATE_TIMESTAMPS_VIEWS_H_ +#define CHROME_BROWSER_UI_VIEWS_SIGNED_CERTIFICATE_TIMESTAMPS_VIEWS_H_ + +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/notification_observer.h" +#include "net/cert/signed_certificate_timestamp.h" +#include "net/ssl/signed_certificate_timestamp_and_status.h" +#include "ui/views/controls/combobox/combobox_listener.h" +#include "ui/views/window/dialog_delegate.h" + +namespace content { +class WebContents; +} + +namespace views { +class Combobox; +class Widget; +} + +class SignedCertificateTimestampInfoView; +class SCTListModel; + +// The Views implementation of the signed certificate timestamps viewer. +class SignedCertificateTimestampsViews : public views::DialogDelegateView, + public content::NotificationObserver, + public views::ComboboxListener { + public: + // Use ShowSignedCertificateTimestampsViewer to show. + SignedCertificateTimestampsViews( + content::WebContents* web_contents, + const net::SignedCertificateTimestampAndStatusList& sct_list); + virtual ~SignedCertificateTimestampsViews(); + + // views::DialogDelegate: + virtual base::string16 GetWindowTitle() const OVERRIDE; + virtual int GetDialogButtons() const OVERRIDE; + virtual ui::ModalType GetModalType() const OVERRIDE; + + // views::View: + virtual gfx::Size GetMinimumSize() OVERRIDE; + virtual void ViewHierarchyChanged(const ViewHierarchyChangedDetails& details) + OVERRIDE; + + private: + void Init(); + + void ShowSCTInfo(int sct_index); + + // views::ComboboxListener: + virtual void OnPerformAction(views::Combobox* combobox) OVERRIDE; + + // content::NotificationObserver: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + content::WebContents* web_contents_; + + SignedCertificateTimestampInfoView* sct_info_view_; + + scoped_ptr<SCTListModel> sct_list_model_; + // The Combobox used to select the SCT to display. This class owns the pointer + // as it has to be deleted explicitly before the views c'tor is called: + // The Combobox d'tor refers to the model it holds, which will be destructed + // as part of tearing down this class. So it will not be available when the + // Views d'tor destroys the Combobox, leading to a crash. + // Must be deleted before the model. + scoped_ptr<views::Combobox> sct_selector_box_; + net::SignedCertificateTimestampAndStatusList sct_list_; + + DISALLOW_COPY_AND_ASSIGN(SignedCertificateTimestampsViews); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_SIGNED_CERTIFICATE_TIMESTAMPS_VIEWS_H_ diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc index 10485fd..24f93a5 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc @@ -6,16 +6,19 @@ #include <algorithm> +#include "base/command_line.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/certificate_viewer.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/views/collected_cookies_views.h" #include "chrome/browser/ui/views/website_settings/permission_selector_view.h" #include "chrome/browser/ui/website_settings/website_settings.h" #include "chrome/browser/ui/website_settings/website_settings_utils.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/content_settings_types.h" #include "chrome/common/url_constants.h" #include "content/public/browser/browser_thread.h" @@ -287,6 +290,7 @@ WebsiteSettingsPopupView::WebsiteSettingsPopupView( connection_tab_(NULL), identity_info_content_(NULL), certificate_dialog_link_(NULL), + signed_certificate_timestamps_link_(NULL), cert_id_(0), help_center_link_(NULL), connection_info_content_(NULL), @@ -528,7 +532,14 @@ void WebsiteSettingsPopupView::SetIdentityInfo( l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON)); certificate_dialog_link_->set_listener(this); - // XXX(eranm): Wire the SCT Viewer here. + if (!signed_certificate_timestamp_ids_.empty() && + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableSignedCertificateTimestampsViewer)) { + signed_certificate_timestamps_link_ = + new views::Link(l10n_util::GetStringUTF16( + IDS_PAGEINFO_CERT_TRANSPARENCY_INFO_BUTTON)); + signed_certificate_timestamps_link_->set_listener(this); + } headline = base::UTF8ToUTF16(identity_info.site_identity); } @@ -537,13 +548,15 @@ void WebsiteSettingsPopupView::SetIdentityInfo( WebsiteSettingsUI::GetIdentityIcon(identity_info.identity_status), base::string16(), // The identity section has no headline. base::UTF8ToUTF16(identity_info.identity_status_description), - certificate_dialog_link_); + certificate_dialog_link_, + signed_certificate_timestamps_link_); ResetConnectionSection( connection_info_content_, WebsiteSettingsUI::GetConnectionIcon(identity_info.connection_status), base::string16(), // The connection section has no headline. base::UTF8ToUTF16(identity_info.connection_status_description), + NULL, NULL); connection_tab_->InvalidateLayout(); @@ -558,6 +571,7 @@ void WebsiteSettingsPopupView::SetFirstVisit( WebsiteSettingsUI::GetFirstVisitIcon(first_visit), l10n_util::GetStringUTF16(IDS_PAGE_INFO_SITE_INFO_TITLE), first_visit, + NULL, NULL); connection_tab_->InvalidateLayout(); Layout(); @@ -675,7 +689,8 @@ void WebsiteSettingsPopupView::ResetConnectionSection( const gfx::Image& icon, const base::string16& headline, const base::string16& text, - views::Link* link) { + views::Link* link, + views::Link* secondary_link) { section_container->RemoveAllChildViews(true); views::GridLayout* layout = new views::GridLayout(section_container); @@ -743,6 +758,11 @@ void WebsiteSettingsPopupView::ResetConnectionSection( content_layout->AddView(link); } + if (secondary_link) { + content_layout->StartRow(1, 0); + content_layout->AddView(secondary_link); + } + layout->AddView(content_pane, 1, 1, views::GridLayout::LEADING, views::GridLayout::LEADING); layout->AddPaddingRow(0, kConnectionSectionPaddingBottom); @@ -762,6 +782,9 @@ void WebsiteSettingsPopupView::HandleLinkClickedAsync(views::Link* source) { GetAnchorView() ? GetAnchorView()->GetWidget()->GetNativeWindow() : NULL; ShowCertificateViewerByID(web_contents_, parent, cert_id_); + } else if (source == signed_certificate_timestamps_link_) { + chrome::ShowSignedCertificateTimestampsViewer( + web_contents_, signed_certificate_timestamp_ids_); } else if (source == help_center_link_) { browser_->OpenURL(content::OpenURLParams( GURL(chrome::kPageInfoHelpCenterURL), diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h index be74574..35fefd1 100644 --- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h +++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h @@ -115,7 +115,8 @@ class WebsiteSettingsPopupView const gfx::Image& icon, const base::string16& headline, const base::string16& text, - views::Link* link); + views::Link* link, + views::Link* secondary_link); // Handles LinkClicked asynchronously. void HandleLinkClickedAsync(views::Link* source); @@ -152,6 +153,10 @@ class WebsiteSettingsPopupView // provided by the website. If the site does not provide a certificate then // |certificate_dialog_link_| is NULL. views::Link* certificate_dialog_link_; + // The link to open the signed certificate timestamps viewer for displaying + // Certificate Transparency info. If no such SCTs accompany the certificate + // then |signed_certificate_timestamps_link_| is NULL. + views::Link* signed_certificate_timestamps_link_; // The id of the certificate provided by the site. If the site does not // provide a certificate then |cert_id_| is 0. diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index 3661594..65e9b57 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -2085,6 +2085,10 @@ 'browser/ui/views/select_file_dialog_extension.h', 'browser/ui/views/select_file_dialog_extension_factory.cc', 'browser/ui/views/select_file_dialog_extension_factory.h', + 'browser/ui/views/signed_certificate_timestamps_views.cc', + 'browser/ui/views/signed_certificate_timestamps_views.h', + 'browser/ui/views/signed_certificate_timestamp_info_view.cc', + 'browser/ui/views/signed_certificate_timestamp_info_view.h', 'browser/ui/views/simple_message_box_views.cc', 'browser/ui/views/simple_message_box_win.cc', 'browser/ui/views/simple_message_box_win.h', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 7e9abf9..1d902bf 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -760,6 +760,10 @@ const char kEnableSearchButtonInOmniboxForStr[] = const char kEnableSearchButtonInOmniboxForStrOrIip[] = "enable-search-button-in-omnibox-for-str-or-iip"; +// Certificate Transparency: Enable showing the SCT viewer when an SSL +// certificate is accompanied by, or contains, SCTs. +const char kEnableSignedCertificateTimestampsViewer[] = "enable-sct-viewer"; + // Enable SPDY/2. This is a temporary testing flag. See // http://crbug.com/303957 . const char kEnableSpdy2[] = "enable-spdy2"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index e074f23..7f82a65 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -217,6 +217,7 @@ extern const char kEnableSdch[]; extern const char kEnableSearchButtonInOmniboxAlways[]; extern const char kEnableSearchButtonInOmniboxForStr[]; extern const char kEnableSearchButtonInOmniboxForStrOrIip[]; +extern const char kEnableSignedCertificateTimestampsViewer[]; extern const char kEnableSpdy2[]; extern const char kEnableSpdy4a2[]; extern const char kEnableSpellingAutoCorrect[]; |