summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreranm@google.com <eranm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-07 13:23:32 +0000
committereranm@google.com <eranm@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-07 13:23:32 +0000
commit7819e54ba24410465281d5175135cc83c60ceea0 (patch)
treec68ad13ca2d75340d010875c5817de2d1d355fda
parent8c3ac46c6cf1906d190d0dc3fd6c91f176f66b04 (diff)
downloadchromium_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.grd95
-rw-r--r--chrome/browser/ui/browser_dialogs.h7
-rw-r--r--chrome/browser/ui/views/signed_certificate_timestamp_info_view.cc246
-rw-r--r--chrome/browser/ui/views/signed_certificate_timestamp_info_view.h78
-rw-r--r--chrome/browser/ui/views/signed_certificate_timestamps_views.cc199
-rw-r--r--chrome/browser/ui/views/signed_certificate_timestamps_views.h78
-rw-r--r--chrome/browser/ui/views/website_settings/website_settings_popup_view.cc29
-rw-r--r--chrome/browser/ui/views/website_settings/website_settings_popup_view.h7
-rw-r--r--chrome/chrome_browser_ui.gypi4
-rw-r--r--chrome/common/chrome_switches.cc4
-rw-r--r--chrome/common/chrome_switches.h1
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[];