0

x509_certificate_model: Use new implementation in cert viewer

Delete most of the old NSS implementation, except for a few functions
that are used by the cert manager or chromeos stuff.

Bug: 953425
Change-Id: I220dbb30270a100318eac056bc9091f115ae3a4b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3680650
Commit-Queue: Matt Mueller <mattm@chromium.org>
Reviewed-by: Rebekah Potter <rbpotter@chromium.org>
Reviewed-by: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1013723}
This commit is contained in:
Matt Mueller
2022-06-13 23:48:01 +00:00
committed by Chromium LUCI CQ
parent 3bb0b4dafd
commit 651522a2b3
20 changed files with 328 additions and 1733 deletions

@ -3756,6 +3756,9 @@ are declared in tools/grit/grit_rule.gni.
<message name="IDS_CERT_EXTENSION_NON_CRITICAL" desc="The text displayed in the certificate details dialog for a given extension which is not critical">
Not Critical
</message>
<message name="IDS_CERT_DUMP_ERROR" desc="The text displayed in the certificate viewer dialog for a given field which could not be decoded">
Error: Unable to decode certificate
</message>
<message name="IDS_CERT_EXTENSION_DUMP_ERROR" desc="The text displayed in the certificate details dialog for a given extension which could not be decoded">
Error: Unable to decode extension
</message>

@ -0,0 +1 @@
93bc3903698ab1e98b05471d98eb715aa314e7df

@ -18,7 +18,13 @@
</div>
<!-- General -->
<div slot="panel" id="general" aria-labelledby="general-tab">
<div class="groups">
<div id="general-error" class="groups" hidden>
<div>
<h3 role="heading">$i18n{certError}</h3>
</div>
</div>
<div id="general-fields" class="groups">
<!-- Issued to -->
<div>
<h3 role="heading">$i18n{issuedTo}</h3>
@ -65,7 +71,9 @@
<div class="attribute">$i18n{expiresOn}</div>
<div id="expiry-date" class="value"></div>
</div>
</div>
<div class="groups">
<!-- Fingerprints -->
<div>
<h3 role="heading">$i18n{fingerprints}</h3>

@ -20,6 +20,7 @@ type TreeInfo = {
type CertificateInfo = {
general: {[key: string]: string},
hierarchy: TreeInfo[],
isError: boolean,
};
type TreeItemDetail = {
@ -140,6 +141,12 @@ function revealTree(tree: CrTreeElement|CrTreeItemElement) {
* @param certInfo Certificate information in named fields.
*/
function getCertificateInfo(certInfo: CertificateInfo) {
const generalError = document.querySelector<HTMLElement>('#general-error');
assert(generalError);
generalError.hidden = !certInfo.isError;
const generalFields = document.querySelector<HTMLElement>('#general-fields');
assert(generalFields);
generalFields.hidden = certInfo.isError;
for (const key in certInfo.general) {
const el = document.querySelector<HTMLElement>(`#${key}`);
assert(el);

@ -18,6 +18,7 @@
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/common/net/x509_certificate_model.h"
#include "chrome/common/net/x509_certificate_model_nss.h"
#include "chrome/grit/generated_resources.h"
#include "components/policy/core/browser/cloud/message_util.h"

@ -44,6 +44,7 @@ content::WebUIDataSource* GetWebUIDataSource(const std::string& host) {
{"hierarchy", IDS_CERT_DETAILS_CERTIFICATE_HIERARCHY_LABEL},
{"certFields", IDS_CERT_DETAILS_CERTIFICATE_FIELDS_LABEL},
{"certFieldVal", IDS_CERT_DETAILS_CERTIFICATE_FIELD_VALUE_LABEL},
{"certError", IDS_CERT_DUMP_ERROR},
};
html_source->AddLocalizedStrings(kStrings);

@ -23,16 +23,21 @@
#include "chrome/browser/ui/certificate_dialogs.h"
#include "chrome/browser/ui/webui/certificate_viewer_ui.h"
#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
#include "chrome/common/net/x509_certificate_model_nss.h"
#include "chrome/common/net/x509_certificate_model.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/host_zoom_map.h"
#include "content/public/browser/web_contents.h"
#include "net/cert/x509_util_nss.h"
#include "net/cert/x509_util.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/geometry/size.h"
#if BUILDFLAG(USE_NSS_CERTS)
#include "chrome/common/net/x509_certificate_model_nss.h"
#include "net/cert/x509_util_nss.h"
#endif
using content::WebContents;
using content::WebUIMessageHandler;
@ -119,25 +124,56 @@ std::unique_ptr<base::DictionaryValue> CertNodeBuilder::Build() {
void ShowCertificateViewer(WebContents* web_contents,
gfx::NativeWindow parent,
net::X509Certificate* cert) {
std::vector<std::string> nicknames;
#if BUILDFLAG(USE_NSS_CERTS)
net::ScopedCERTCertificateList nss_certs =
net::x509_util::CreateCERTCertificateListFromX509Certificate(cert);
if (nss_certs.empty())
return;
// If any of the certs could not be parsed by NSS, |nss_certs| will be an
// empty list and |nicknames| will not be populated, which is fine as a
// fallback.
for (const auto& nss_cert : nss_certs) {
nicknames.push_back(x509_certificate_model::GetRawNickname(nss_cert.get()));
}
#endif
CertificateViewerDialog::ShowConstrained(std::move(nss_certs), web_contents,
parent);
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> cert_buffers;
cert_buffers.push_back(bssl::UpRef(cert->cert_buffer()));
for (const auto& intermediate : cert->intermediate_buffers()) {
cert_buffers.push_back(bssl::UpRef(intermediate));
}
CertificateViewerDialog::ShowConstrained(
std::move(cert_buffers), std::move(nicknames), web_contents, parent);
}
////////////////////////////////////////////////////////////////////////////////
// CertificateViewerDialog
#if BUILDFLAG(USE_NSS_CERTS)
// static
CertificateViewerDialog* CertificateViewerDialog::ShowConstrained(
net::ScopedCERTCertificateList certs,
net::ScopedCERTCertificateList nss_certs,
WebContents* web_contents,
gfx::NativeWindow parent) {
std::vector<std::string> nicknames;
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> cert_buffers;
for (const auto& cert : nss_certs) {
nicknames.push_back(x509_certificate_model::GetRawNickname(cert.get()));
cert_buffers.push_back(net::x509_util::CreateCryptoBuffer(
base::make_span(cert->derCert.data, cert->derCert.len)));
}
return ShowConstrained(std::move(cert_buffers), std::move(nicknames),
web_contents, parent);
}
#endif
// static
CertificateViewerDialog* CertificateViewerDialog::ShowConstrained(
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs,
std::vector<std::string> cert_nicknames,
content::WebContents* web_contents,
gfx::NativeWindow parent) {
CertificateViewerDialog* dialog_ptr =
new CertificateViewerDialog(std::move(certs));
new CertificateViewerDialog(std::move(certs), std::move(cert_nicknames));
auto dialog = base::WrapUnique(dialog_ptr);
// TODO(bshe): UI tweaks needed for Aura HTML Dialog, such as adding padding
@ -160,13 +196,17 @@ gfx::NativeWindow CertificateViewerDialog::GetNativeWebContentsModalDialog() {
}
CertificateViewerDialog::CertificateViewerDialog(
net::ScopedCERTCertificateList certs)
: nss_certs_(std::move(certs)) {
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs,
std::vector<std::string> cert_nicknames) {
for (size_t i = 0; i < certs.size(); ++i) {
std::string nickname;
if (i < cert_nicknames.size())
nickname = std::move(cert_nicknames[i]);
certs_.emplace_back(std::move(certs[i]), std::move(nickname));
}
// Construct the dialog title from the certificate.
title_ = l10n_util::GetStringFUTF16(
IDS_CERT_INFO_DIALOG_TITLE,
base::UTF8ToUTF16(
x509_certificate_model::GetTitle(nss_certs_.front().get())));
IDS_CERT_INFO_DIALOG_TITLE, base::UTF8ToUTF16(certs_.front().GetTitle()));
}
CertificateViewerDialog::~CertificateViewerDialog() = default;
@ -186,8 +226,7 @@ GURL CertificateViewerDialog::GetDialogContentURL() const {
void CertificateViewerDialog::GetWebUIMessageHandlers(
std::vector<WebUIMessageHandler*>* handlers) const {
handlers->push_back(new CertificateViewerDialogHandler(
const_cast<CertificateViewerDialog*>(this),
net::x509_util::DupCERTCertificateList(nss_certs_)));
const_cast<CertificateViewerDialog*>(this), &certs_));
}
void CertificateViewerDialog::GetDialogSize(gfx::Size* size) const {
@ -196,72 +235,79 @@ void CertificateViewerDialog::GetDialogSize(gfx::Size* size) const {
size->SetSize(kDefaultWidth, kDefaultHeight);
}
std::string HandleOptionalOrError(
const x509_certificate_model::OptionalStringOrError& s) {
if (absl::holds_alternative<x509_certificate_model::Error>(s))
return l10n_util::GetStringUTF8(IDS_CERT_DUMP_ERROR);
else if (absl::holds_alternative<x509_certificate_model::NotPresent>(s))
return l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT);
return absl::get<std::string>(s);
}
std::string CertificateViewerDialog::GetDialogArgs() const {
std::string data;
// Certificate information. The keys in this dictionary's general key
// correspond to the IDs in the Html page.
base::DictionaryValue cert_info;
CERTCertificate* cert_hnd = nss_certs_.front().get();
const x509_certificate_model::X509CertificateModel& model = certs_.front();
// Standard certificate details.
const std::string alternative_text =
l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT);
cert_info.SetBoolean("isError", !model.is_valid());
cert_info.SetStringPath(
"general.title",
l10n_util::GetStringFUTF8(
IDS_CERT_INFO_DIALOG_TITLE,
base::UTF8ToUTF16(x509_certificate_model::GetTitle(cert_hnd))));
l10n_util::GetStringFUTF8(IDS_CERT_INFO_DIALOG_TITLE,
base::UTF8ToUTF16(model.GetTitle())));
// Issued to information.
cert_info.SetStringPath(
"general.issued-cn",
x509_certificate_model::GetSubjectCommonName(cert_hnd, alternative_text));
cert_info.SetStringPath(
"general.issued-o",
x509_certificate_model::GetSubjectOrgName(cert_hnd, alternative_text));
cert_info.SetStringPath("general.issued-ou",
x509_certificate_model::GetSubjectOrgUnitName(
cert_hnd, alternative_text));
if (model.is_valid()) {
// Standard certificate details.
const std::string alternative_text =
l10n_util::GetStringUTF8(IDS_CERT_INFO_FIELD_NOT_PRESENT);
// Issuer information.
cert_info.SetStringPath(
"general.issuer-cn",
x509_certificate_model::GetIssuerCommonName(cert_hnd, alternative_text));
cert_info.SetStringPath(
"general.issuer-o",
x509_certificate_model::GetIssuerOrgName(cert_hnd, alternative_text));
cert_info.SetStringPath(
"general.issuer-ou",
x509_certificate_model::GetIssuerOrgUnitName(cert_hnd, alternative_text));
// Issued to information.
cert_info.SetStringPath(
"general.issued-cn",
HandleOptionalOrError(model.GetSubjectCommonName()));
cert_info.SetStringPath("general.issued-o",
HandleOptionalOrError(model.GetSubjectOrgName()));
cert_info.SetStringPath(
"general.issued-ou",
HandleOptionalOrError(model.GetSubjectOrgUnitName()));
// Validity period.
base::Time issued, expires;
std::string issued_str, expires_str;
if (x509_certificate_model::GetTimes(cert_hnd, &issued, &expires)) {
issued_str = base::UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(issued));
expires_str = base::UTF16ToUTF8(
base::TimeFormatFriendlyDateAndTime(expires));
} else {
issued_str = alternative_text;
expires_str = alternative_text;
// Issuer information.
cert_info.SetStringPath("general.issuer-cn",
HandleOptionalOrError(model.GetIssuerCommonName()));
cert_info.SetStringPath("general.issuer-o",
HandleOptionalOrError(model.GetIssuerOrgName()));
cert_info.SetStringPath(
"general.issuer-ou",
HandleOptionalOrError(model.GetIssuerOrgUnitName()));
// Validity period.
base::Time issued, expires;
std::string issued_str, expires_str;
if (model.GetTimes(&issued, &expires)) {
issued_str =
base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(issued));
expires_str =
base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(expires));
} else {
issued_str = alternative_text;
expires_str = alternative_text;
}
cert_info.SetStringPath("general.issue-date", issued_str);
cert_info.SetStringPath("general.expiry-date", expires_str);
}
cert_info.SetStringPath("general.issue-date", issued_str);
cert_info.SetStringPath("general.expiry-date", expires_str);
cert_info.SetStringPath("general.sha256",
x509_certificate_model::HashCertSHA256(cert_hnd));
cert_info.SetStringPath("general.sha1",
x509_certificate_model::HashCertSHA1(cert_hnd));
model.HashCertSHA256WithSeparators());
cert_info.SetStringPath("general.sha1", model.HashCertSHA1WithSeparators());
// Certificate hierarchy is constructed from bottom up.
base::Value children;
int index = 0;
for (const auto& cert : nss_certs_) {
for (const auto& cert : certs_) {
base::Value cert_node(base::Value::Type::DICTIONARY);
cert_node.SetKey("label",
base::Value(x509_certificate_model::GetTitle(cert.get())));
cert_node.SetKey("label", base::Value(cert.GetTitle()));
cert_node.SetPath({"payload", "index"}, base::Value(index));
// Add the child from the previous iteration.
if (!children.is_none())
@ -302,8 +348,8 @@ bool CertificateViewerDialog::ShouldShowDialogTitle() const {
CertificateViewerDialogHandler::CertificateViewerDialogHandler(
CertificateViewerDialog* dialog,
net::ScopedCERTCertificateList cert_chain)
: dialog_(dialog), cert_chain_(std::move(cert_chain)) {}
const std::vector<x509_certificate_model::X509CertificateModel>* certs)
: dialog_(dialog), certs_(certs) {}
CertificateViewerDialogHandler::~CertificateViewerDialogHandler() {
}
@ -329,10 +375,14 @@ void CertificateViewerDialogHandler::HandleExportCertificate(
gfx::NativeWindow window =
platform_util::GetTopLevel(dialog_->GetNativeWebContentsModalDialog());
ShowCertExportDialog(web_ui()->GetWebContents(),
window,
cert_chain_.begin() + cert_index,
cert_chain_.end());
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> export_certs;
for (const auto& cert : base::make_span(*certs_).subspan(cert_index)) {
export_certs.push_back(bssl::UpRef(cert.cert_buffer()));
}
ShowCertExportDialog(web_ui()->GetWebContents(), window,
std::move(export_certs),
(*certs_)[cert_index].GetTitle());
}
void CertificateViewerDialogHandler::HandleRequestCertificateFields(
@ -343,118 +393,96 @@ void CertificateViewerDialogHandler::HandleRequestCertificateFields(
if (cert_index < 0)
return;
CERTCertificate* cert = cert_chain_[cert_index].get();
const x509_certificate_model::X509CertificateModel& model =
(*certs_)[cert_index];
CertNodeBuilder version_node(IDS_CERT_DETAILS_VERSION);
std::string version = x509_certificate_model::GetVersion(cert);
if (!version.empty()) {
version_node.Payload(l10n_util::GetStringFUTF8(
IDS_CERT_DETAILS_VERSION_FORMAT, base::UTF8ToUTF16(version)));
}
CertNodeBuilder contents_builder(IDS_CERT_DETAILS_CERTIFICATE);
CertNodeBuilder issued_node_builder(IDS_CERT_DETAILS_NOT_BEFORE);
CertNodeBuilder expires_node_builder(IDS_CERT_DETAILS_NOT_AFTER);
base::Time issued, expires;
if (x509_certificate_model::GetTimes(cert, &issued, &expires)) {
issued_node_builder.Payload(base::UTF16ToUTF8(
base::TimeFormatShortDateAndTimeWithTimeZone(issued)));
expires_node_builder.Payload(base::UTF16ToUTF8(
base::TimeFormatShortDateAndTimeWithTimeZone(expires)));
}
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions(
l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_CRITICAL),
l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_NON_CRITICAL),
cert, &extensions);
std::unique_ptr<base::DictionaryValue> details_extensions;
if (!extensions.empty()) {
CertNodeBuilder details_extensions_builder(IDS_CERT_DETAILS_EXTENSIONS);
for (const x509_certificate_model::Extension& extension : extensions) {
details_extensions_builder.Child(
CertNodeBuilder(extension.name).Payload(extension.value).Build());
if (model.is_valid()) {
CertNodeBuilder issued_node_builder(IDS_CERT_DETAILS_NOT_BEFORE);
CertNodeBuilder expires_node_builder(IDS_CERT_DETAILS_NOT_AFTER);
base::Time issued, expires;
if (model.GetTimes(&issued, &expires)) {
issued_node_builder.Payload(base::UTF16ToUTF8(
base::TimeFormatShortDateAndTimeWithTimeZone(issued)));
expires_node_builder.Payload(base::UTF16ToUTF8(
base::TimeFormatShortDateAndTimeWithTimeZone(expires)));
}
details_extensions = details_extensions_builder.Build();
std::vector<x509_certificate_model::Extension> extensions =
model.GetExtensions(
l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_CRITICAL),
l10n_util::GetStringUTF8(IDS_CERT_EXTENSION_NON_CRITICAL));
std::unique_ptr<base::DictionaryValue> details_extensions;
if (!extensions.empty()) {
CertNodeBuilder details_extensions_builder(IDS_CERT_DETAILS_EXTENSIONS);
for (const x509_certificate_model::Extension& extension : extensions) {
details_extensions_builder.Child(
CertNodeBuilder(extension.name).Payload(extension.value).Build());
}
details_extensions = details_extensions_builder.Build();
}
contents_builder
// Main certificate fields.
.Child(CertNodeBuilder(IDS_CERT_DETAILS_VERSION)
.Payload(l10n_util::GetStringFUTF8(
IDS_CERT_DETAILS_VERSION_FORMAT,
base::UTF8ToUTF16(model.GetVersion())))
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_SERIAL_NUMBER)
.Payload(model.GetSerialNumberHexified())
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG)
.Payload(model.ProcessSecAlgorithmSignature())
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_ISSUER)
.Payload(HandleOptionalOrError(model.GetIssuerName()))
.Build())
// Validity period.
.Child(CertNodeBuilder(IDS_CERT_DETAILS_VALIDITY)
.Child(issued_node_builder.Build())
.Child(expires_node_builder.Build())
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT)
.Payload(HandleOptionalOrError(model.GetSubjectName()))
.Build())
// Subject key information.
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT_KEY_INFO)
.Child(CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT_KEY_ALG)
.Payload(model.ProcessSecAlgorithmSubjectPublicKey())
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT_KEY)
.Payload(model.ProcessSubjectPublicKeyInfo())
.Build())
.Build())
// Extensions.
.ChildIfNotNull(std::move(details_extensions))
.Child(CertNodeBuilder(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG)
.Payload(model.ProcessSecAlgorithmSignatureWrap())
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE)
.Payload(model.ProcessRawBitsSignatureWrap())
.Build());
}
contents_builder.Child(
CertNodeBuilder(IDS_CERT_INFO_FINGERPRINTS_GROUP)
.Child(CertNodeBuilder(IDS_CERT_INFO_SHA256_FINGERPRINT_LABEL)
.Payload(model.HashCertSHA256WithSeparators())
.Build())
.Child(CertNodeBuilder(IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL)
.Payload(model.HashCertSHA1WithSeparators())
.Build())
.Build());
base::ListValue root_list;
root_list.Append(base::Value::FromUniquePtrValue(
CertNodeBuilder(x509_certificate_model::GetTitle(cert))
.Child(
CertNodeBuilder(
l10n_util::GetStringUTF8(IDS_CERT_DETAILS_CERTIFICATE))
// Main certificate fields.
.Child(version_node.Build())
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_SERIAL_NUMBER)
.Payload(
x509_certificate_model::GetSerialNumberHexified(
cert, l10n_util::GetStringUTF8(
IDS_CERT_INFO_FIELD_NOT_PRESENT)))
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG)
.Payload(x509_certificate_model::
ProcessSecAlgorithmSignature(cert))
.Build())
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_ISSUER)
.Payload(x509_certificate_model::GetIssuerName(cert))
.Build())
// Validity period.
.Child(CertNodeBuilder(IDS_CERT_DETAILS_VALIDITY)
.Child(issued_node_builder.Build())
.Child(expires_node_builder.Build())
.Build())
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT)
.Payload(x509_certificate_model::GetSubjectName(cert))
.Build())
// Subject key information.
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT_KEY_INFO)
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT_KEY_ALG)
.Payload(
x509_certificate_model::
ProcessSecAlgorithmSubjectPublicKey(
cert))
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_SUBJECT_KEY)
.Payload(
x509_certificate_model::
ProcessSubjectPublicKeyInfo(cert))
.Build())
.Build())
// Extensions.
.ChildIfNotNull(std::move(details_extensions))
.Child(
CertNodeBuilder(IDS_CERT_DETAILS_CERTIFICATE_SIG_ALG)
.Payload(x509_certificate_model::
ProcessSecAlgorithmSignatureWrap(cert))
.Build())
.Child(CertNodeBuilder(IDS_CERT_DETAILS_CERTIFICATE_SIG_VALUE)
.Payload(x509_certificate_model::
ProcessRawBitsSignatureWrap(cert))
.Build())
.Child(
CertNodeBuilder(IDS_CERT_INFO_FINGERPRINTS_GROUP)
.Child(CertNodeBuilder(
IDS_CERT_INFO_SHA256_FINGERPRINT_LABEL)
.Payload(
x509_certificate_model::HashCertSHA256(
cert))
.Build())
.Child(
CertNodeBuilder(
IDS_CERT_INFO_SHA1_FINGERPRINT_LABEL)
.Payload(x509_certificate_model::HashCertSHA1(
cert))
.Build())
.Build())
.Build())
.Build()));
root_list.Append(
base::Value::FromUniquePtrValue(CertNodeBuilder(model.GetTitle())
.Child(contents_builder.Build())
.Build()));
// Send certificate information to javascript.
ResolveJavascriptCallback(callback_id, root_list);
}
@ -462,7 +490,7 @@ void CertificateViewerDialogHandler::HandleRequestCertificateFields(
int CertificateViewerDialogHandler::GetCertificateIndex(
int requested_index) const {
int cert_index = requested_index;
if (cert_index < 0 || cert_index >= static_cast<int>(cert_chain_.size()))
if (cert_index < 0 || static_cast<size_t>(cert_index) >= certs_->size())
return -1;
return cert_index;
}

@ -9,26 +9,41 @@
#include <vector>
#include "base/values.h"
#include "chrome/common/net/x509_certificate_model.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "net/cert/scoped_nss_types.h"
#include "crypto/crypto_buildflags.h"
#include "net/cert/x509_certificate.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/web_dialogs/web_dialog_delegate.h"
#if BUILDFLAG(USE_NSS_CERTS)
#include "net/cert/scoped_nss_types.h"
#endif
namespace content {
class WebContents;
}
class ConstrainedWebDialogDelegate;
// TODO(https://crbug.com/953425): Update comment when this is used by other
// platforms.
// Dialog for displaying detailed certificate information. This is used in linux
// and chromeos builds to display detailed information in a floating dialog when
// the user clicks on "Certificate Information" from the lock icon of a web site
// or "View" from the Certificate Manager.
class CertificateViewerDialog : public ui::WebDialogDelegate {
public:
#if BUILDFLAG(USE_NSS_CERTS)
static CertificateViewerDialog* ShowConstrained(
net::ScopedCERTCertificateList certs,
net::ScopedCERTCertificateList nss_certs,
content::WebContents* web_contents,
gfx::NativeWindow parent);
#endif
static CertificateViewerDialog* ShowConstrained(
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs,
std::vector<std::string> cert_nicknames,
content::WebContents* web_contents,
gfx::NativeWindow parent);
@ -45,7 +60,8 @@ class CertificateViewerDialog : public ui::WebDialogDelegate {
// Construct a certificate viewer for the passed in certificate. A reference
// to the certificate pointer is added for the lifetime of the certificate
// viewer.
explicit CertificateViewerDialog(net::ScopedCERTCertificateList certs);
CertificateViewerDialog(std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs,
std::vector<std::string> cert_nicknames);
// ui::WebDialogDelegate:
ui::ModalType GetDialogModalType() const override;
@ -61,8 +77,7 @@ class CertificateViewerDialog : public ui::WebDialogDelegate {
bool* out_close_dialog) override;
bool ShouldShowDialogTitle() const override;
// The certificate chain, as NSS cert objects.
net::ScopedCERTCertificateList nss_certs_;
std::vector<x509_certificate_model::X509CertificateModel> certs_;
// The title of the certificate viewer dialog, Certificate Viewer: CN.
std::u16string title_;
@ -75,8 +90,9 @@ class CertificateViewerDialog : public ui::WebDialogDelegate {
// details and export the certificate.
class CertificateViewerDialogHandler : public content::WebUIMessageHandler {
public:
CertificateViewerDialogHandler(CertificateViewerDialog* dialog,
net::ScopedCERTCertificateList cert_chain);
CertificateViewerDialogHandler(
CertificateViewerDialog* dialog,
const std::vector<x509_certificate_model::X509CertificateModel>* certs);
CertificateViewerDialogHandler(const CertificateViewerDialogHandler&) =
delete;
@ -109,8 +125,7 @@ class CertificateViewerDialogHandler : public content::WebUIMessageHandler {
// The dialog.
CertificateViewerDialog* dialog_;
// The certificate chain.
net::ScopedCERTCertificateList cert_chain_;
const std::vector<x509_certificate_model::X509CertificateModel>* certs_;
};
#endif // CHROME_BROWSER_UI_WEBUI_CERTIFICATE_VIEWER_WEBUI_H_

@ -1199,6 +1199,9 @@ X509CertificateModel::X509CertificateModel(
parsed_successfully_ = true;
}
X509CertificateModel::X509CertificateModel(X509CertificateModel&& other) =
default;
X509CertificateModel::~X509CertificateModel() = default;
std::string X509CertificateModel::HashCertSHA256() const {

@ -34,6 +34,8 @@ class X509CertificateModel {
// nickname for the certificate, if available.
X509CertificateModel(bssl::UniquePtr<CRYPTO_BUFFER> cert_data,
std::string nickname);
X509CertificateModel(X509CertificateModel&& other);
X509CertificateModel& operator=(X509CertificateModel&& other) = default;
~X509CertificateModel();
// ---------------------------------------------------------------------------

@ -6,33 +6,17 @@
#include <cert.h>
#include <certt.h>
#include <hasht.h>
#include <keyhi.h> // SECKEY_DestroyPrivateKey
#include <keythi.h> // SECKEYPrivateKey
#include <pk11pub.h> // PK11_FindKeyByAnyCert
#include <seccomon.h> // SECItem
#include <sechash.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <unicode/uidna.h>
#include <algorithm>
#include <memory>
#include <tuple>
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
#include "crypto/nss_key_util.h"
#include "crypto/nss_util.h"
#include "crypto/scoped_nss_types.h"
#include "net/cert/x509_util_nss.h"
#include "ui/base/l10n/l10n_util.h"
namespace psm = mozilla_security_manager;
@ -49,38 +33,6 @@ std::string Stringize(char* nss_text, const std::string& alternative_text) {
return s;
}
// Hash a certificate using the given algorithm, return the result as a
// colon-seperated hex string. The len specified is the number of bytes
// required for storing the raw fingerprint.
// (It's a bit redundant that the caller needs to specify len in addition to the
// algorithm, but given the limited uses, not worth fixing.)
std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
unsigned char fingerprint[HASH_LENGTH_MAX];
DCHECK(NULL != cert->derCert.data);
DCHECK_NE(0U, cert->derCert.len);
DCHECK_LE(len, HASH_LENGTH_MAX);
memset(fingerprint, 0, len);
SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
cert->derCert.len);
DCHECK_EQ(rv, SECSuccess);
return x509_certificate_model::ProcessRawBytes(fingerprint, len);
}
std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
return psm::GetOIDText(&algorithm_id->algorithm);
}
std::string ProcessExtension(
const std::string& critical_label,
const std::string& non_critical_label,
CERTCertExtension* extension) {
std::string criticality =
extension->critical.data && extension->critical.data[0] ?
critical_label : non_critical_label;
return criticality + "\n" + psm::ProcessExtensionData(extension);
}
std::string GetNickname(CERTCertificate* cert_handle) {
std::string name;
if (cert_handle->nickname) {
@ -100,6 +52,13 @@ namespace x509_certificate_model {
using std::string;
std::string GetRawNickname(CERTCertificate* cert_handle) {
if (cert_handle->nickname) {
return cert_handle->nickname;
}
return std::string();
}
string GetCertNameOrNickname(CERTCertificate* cert_handle) {
string name = ProcessIDN(
Stringize(CERT_GetCommonName(&cert_handle->subject), std::string()));
@ -108,76 +67,19 @@ string GetCertNameOrNickname(CERTCertificate* cert_handle) {
return GetNickname(cert_handle);
}
string GetVersion(CERTCertificate* cert_handle) {
// If the version field is omitted from the certificate, the default
// value is v1(0).
unsigned long version = 0;
if (cert_handle->version.len == 0 ||
SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess) {
return base::NumberToString(base::strict_cast<uint64_t>(version + 1));
}
return std::string();
}
net::CertType GetType(CERTCertificate* cert_handle) {
return psm::GetCertType(cert_handle);
}
string GetSerialNumberHexified(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
alternative_text);
}
string GetIssuerCommonName(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
}
string GetIssuerOrgName(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
}
string GetIssuerOrgUnitName(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
}
string GetSubjectOrgName(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
}
string GetSubjectOrgUnitName(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
alternative_text);
}
string GetSubjectCommonName(CERTCertificate* cert_handle,
const string& alternative_text) {
return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
}
bool GetTimes(CERTCertificate* cert_handle,
base::Time* issued,
base::Time* expires) {
return net::x509_util::GetValidityTimes(cert_handle, issued, expires);
}
string GetTitle(CERTCertificate* cert_handle) {
return psm::GetCertTitle(cert_handle);
}
string GetIssuerName(CERTCertificate* cert_handle) {
return psm::ProcessName(&cert_handle->issuer);
}
string GetSubjectName(CERTCertificate* cert_handle) {
return psm::ProcessName(&cert_handle->subject);
}
std::string GetIssuerDisplayName(CERTCertificate* cert_handle) {
return net::x509_util::GetCERTNameDisplayName(&cert_handle->issuer);
}
@ -186,50 +88,4 @@ std::string GetSubjectDisplayName(CERTCertificate* cert_handle) {
return net::x509_util::GetCERTNameDisplayName(&cert_handle->subject);
}
void GetExtensions(const string& critical_label,
const string& non_critical_label,
CERTCertificate* cert_handle,
Extensions* extensions) {
if (cert_handle->extensions) {
for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
Extension extension;
extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
extension.value = ProcessExtension(
critical_label, non_critical_label, cert_handle->extensions[i]);
extensions->push_back(extension);
}
}
}
string HashCertSHA256(CERTCertificate* cert_handle) {
return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
}
string HashCertSHA1(CERTCertificate* cert_handle) {
return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
}
string ProcessSecAlgorithmSignature(CERTCertificate* cert_handle) {
return ProcessSecAlgorithmInternal(&cert_handle->signature);
}
string ProcessSecAlgorithmSubjectPublicKey(CERTCertificate* cert_handle) {
return ProcessSecAlgorithmInternal(
&cert_handle->subjectPublicKeyInfo.algorithm);
}
string ProcessSecAlgorithmSignatureWrap(CERTCertificate* cert_handle) {
return ProcessSecAlgorithmInternal(
&cert_handle->signatureWrap.signatureAlgorithm);
}
string ProcessSubjectPublicKeyInfo(CERTCertificate* cert_handle) {
return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
}
string ProcessRawBitsSignatureWrap(CERTCertificate* cert_handle) {
return ProcessRawBits(cert_handle->signatureWrap.signature.data,
cert_handle->signatureWrap.signature.len);
}
} // namespace x509_certificate_model

@ -8,82 +8,34 @@
#include <stddef.h>
#include <string>
#include <vector>
#include "base/containers/span.h"
#include "chrome/common/net/x509_certificate_model.h"
#include "net/cert/cert_type.h"
#include "net/cert/scoped_nss_types.h"
typedef struct CERTCertificateStr CERTCertificate;
namespace base {
class Time;
}
// This namespace defines a set of functions to be used in UI-related bits of
// X509 certificates.
namespace x509_certificate_model {
// Returns the NSS nickname field of the certificate without processing. This
// will generally be of the form "<token name> : <nickname>" but it's not
// really documented in NSS.
std::string GetRawNickname(CERTCertificate* cert_handle);
// Returns the commonName of the certificate, or if that is empty, returns the
// NSS certificate nickname (without the token name).
std::string GetCertNameOrNickname(CERTCertificate* cert_handle);
std::string GetVersion(CERTCertificate* cert_handle);
net::CertType GetType(CERTCertificate* cert_handle);
std::string GetSerialNumberHexified(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetIssuerCommonName(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetIssuerOrgName(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetIssuerOrgUnitName(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetSubjectOrgName(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetSubjectOrgUnitName(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetSubjectCommonName(CERTCertificate* cert_handle,
const std::string& alternative_text);
std::string GetIssuerDisplayName(CERTCertificate* cert_handle);
std::string GetSubjectDisplayName(CERTCertificate* cert_handle);
bool GetTimes(CERTCertificate* cert_handle,
base::Time* issued,
base::Time* expires);
std::string GetTitle(CERTCertificate* cert_handle);
std::string GetIssuerName(CERTCertificate* cert_handle);
std::string GetSubjectName(CERTCertificate* cert_handle);
typedef std::vector<Extension> Extensions;
void GetExtensions(const std::string& critical_label,
const std::string& non_critical_label,
CERTCertificate* cert_handle,
Extensions* extensions);
// Hash a certificate using the given algorithm, return the result as a
// colon-seperated hex string.
std::string HashCertSHA256(CERTCertificate* cert_handle);
std::string HashCertSHA1(CERTCertificate* cert_handle);
std::string ProcessSecAlgorithmSignature(CERTCertificate* cert_handle);
std::string ProcessSecAlgorithmSubjectPublicKey(CERTCertificate* cert_handle);
std::string ProcessSecAlgorithmSignatureWrap(CERTCertificate* cert_handle);
// Formats the public key from the X.509 SubjectPublicKeyInfo extracted from
// |cert_handle| as a string for displaying.
std::string ProcessSubjectPublicKeyInfo(CERTCertificate* cert_handle);
std::string ProcessRawBitsSignatureWrap(CERTCertificate* cert_handle);
} // namespace x509_certificate_model

@ -53,156 +53,6 @@ TEST_F(X509CertificateModelTest, GetCertNameOrNicknameAndGetTitle) {
x509_certificate_model::GetTitle(no_cn_cert2.get()));
}
TEST_F(X509CertificateModelTest, GetExtensions) {
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(3U, extensions.size());
EXPECT_EQ("Certificate Basic Constraints", extensions[0].name);
EXPECT_EQ(
"critical\nIs a Certification Authority\n"
"Maximum number of intermediate CAs: unlimited",
extensions[0].value);
EXPECT_EQ("Certificate Subject Key ID", extensions[1].name);
EXPECT_EQ(
"notcrit\nKey ID: 9B 26 0B 8A 98 A9 BB 1D B9 1F 1C E3 1A 40 33 ED\n8E "
"17 88 AB",
extensions[1].value);
EXPECT_EQ("Certificate Key Usage", extensions[2].name);
EXPECT_EQ("critical\nCertificate Signer\nCRL Signer", extensions[2].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "subjectAltName_sanity_check.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(2U, extensions.size());
EXPECT_EQ("Certificate Subject Alternative Name", extensions[1].name);
EXPECT_EQ(
"notcrit\nIP Address: 127.0.0.2\nIP Address: fe80::1\nDNS Name: "
"test.example\nEmail Address: test@test.example\nOID.1.2.3.4: 0C 09 69 "
"67 6E 6F 72 65 20 6D 65\nX.500 Name: CN = 127.0.0.3\n\n",
extensions[1].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "foaf.me.chromium-test-cert.der"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(5U, extensions.size());
EXPECT_EQ("Netscape Certificate Comment", extensions[1].name);
EXPECT_EQ("notcrit\nOpenSSL Generated Certificate", extensions[1].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "2029_globalsign_com_cert.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(9U, extensions.size());
EXPECT_EQ("Certificate Subject Key ID", extensions[0].name);
EXPECT_EQ(
"notcrit\nKey ID: 59 BC D9 69 F7 B0 65 BB C8 34 C5 D2 C2 EF 17 78\nA6 "
"47 1E 8B",
extensions[0].value);
EXPECT_EQ("Certification Authority Key ID", extensions[1].name);
EXPECT_EQ(
"notcrit\nKey ID: 8A FC 14 1B 3D A3 59 67 A5 3B E1 73 92 A6 62 91\n7F "
"E4 78 30\n",
extensions[1].value);
EXPECT_EQ("Authority Information Access", extensions[2].name);
EXPECT_EQ(
"notcrit\nCA Issuers: "
"URI: http://secure.globalsign.net/cacert/SHA256extendval1.crt\n",
extensions[2].value);
EXPECT_EQ("CRL Distribution Points", extensions[3].name);
EXPECT_EQ("notcrit\nURI: http://crl.globalsign.net/SHA256ExtendVal1.crl\n",
extensions[3].value);
EXPECT_EQ("Certificate Basic Constraints", extensions[4].name);
EXPECT_EQ("notcrit\nIs not a Certification Authority\n",
extensions[4].value);
EXPECT_EQ("Certificate Key Usage", extensions[5].name);
EXPECT_EQ(
"critical\nSigning\nNon-repudiation\nKey Encipherment\n"
"Data Encipherment",
extensions[5].value);
EXPECT_EQ("Extended Key Usage", extensions[6].name);
EXPECT_EQ(
"notcrit\nTLS WWW Server Authentication (OID.1.3.6.1.5.5.7.3.1)\n"
"TLS WWW Client Authentication (OID.1.3.6.1.5.5.7.3.2)\n",
extensions[6].value);
EXPECT_EQ("Certificate Policies", extensions[7].name);
EXPECT_EQ(
"notcrit\nOID.1.3.6.1.4.1.4146.1.1:\n"
" Certification Practice Statement Pointer:"
" http://www.globalsign.net/repository/\n",
extensions[7].value);
EXPECT_EQ("Netscape Certificate Type", extensions[8].name);
EXPECT_EQ("notcrit\nSSL Client Certificate\nSSL Server Certificate",
extensions[8].value);
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "diginotar_public_ca_2025.pem"));
ASSERT_TRUE(cert.get());
x509_certificate_model::Extensions extensions;
x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
&extensions);
ASSERT_EQ(7U, extensions.size());
EXPECT_EQ("Authority Information Access", extensions[0].name);
EXPECT_EQ(
"notcrit\nOCSP Responder: "
"URI: http://validation.diginotar.nl\n",
extensions[0].value);
EXPECT_EQ("Certificate Basic Constraints", extensions[2].name);
EXPECT_EQ(
"critical\nIs a Certification Authority\n"
"Maximum number of intermediate CAs: 0",
extensions[2].value);
EXPECT_EQ("Certificate Policies", extensions[3].name);
EXPECT_EQ(
"notcrit\nOID.2.16.528.1.1001.1.1.1.1.5.2.6.4:\n"
" Certification Practice Statement Pointer:"
" http://www.diginotar.nl/cps\n"
" User Notice:\n"
" Conditions, as mentioned on our website (www.diginotar.nl), are "
"applicable to all our products and services.\n",
extensions[3].value);
}
}
TEST_F(X509CertificateModelTest, GetTypeCA) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
@ -253,105 +103,3 @@ TEST_F(X509CertificateModelTest, GetTypeServer) {
EXPECT_EQ(net::SERVER_CERT, x509_certificate_model::GetType(cert.get()));
}
// An X.509 v1 certificate with the version field omitted should get
// the default value v1.
TEST_F(X509CertificateModelTest, GetVersionOmitted) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "ndn.ca.crt"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("1", x509_certificate_model::GetVersion(cert.get()));
}
TEST_F(X509CertificateModelTest, ProcessSecAlgorithms) {
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("PKCS #1 SHA-256 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignature(cert.get()));
EXPECT_EQ(
"PKCS #1 SHA-256 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert.get()));
EXPECT_EQ("PKCS #1 RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(
cert.get()));
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "weak_digest_md5_root.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ("PKCS #1 MD5 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignature(cert.get()));
EXPECT_EQ(
"PKCS #1 MD5 With RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert.get()));
EXPECT_EQ("PKCS #1 RSA Encryption",
x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(
cert.get()));
}
}
TEST_F(X509CertificateModelTest, ProcessSubjectPublicKeyInfo) {
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "root_ca_cert.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(
"Modulus (2048 bits):\n"
" C6 81 1F 92 73 B6 58 85 D9 8D AC B7 20 FD C7 BF\n"
"40 B2 EA FA E5 0B 52 01 8F 9A C1 EB 7A 80 C1 F3\n"
"89 A4 3E D5 1B 61 CC B5 CF 80 B1 1A DB BB 25 E0\n"
"18 BF 92 69 26 50 CD E7 3F FF 0D 3C B4 1F 14 12\n"
"AB 67 37 DE 07 03 6C 12 74 82 36 AC C3 D4 D3 64\n"
"9F 91 ED 5B F6 A9 7A A4 9C 98 E8 65 6C 94 E1 CB\n"
"55 73 AE F8 1D 50 B0 78 E5 74 FF B1 37 2C CB 19\n"
"3D A4 8C E7 76 4E 86 5C 3F DF B3 ED 45 23 4F 54\n"
"9B 33 C6 89 5E 13 1D DD 7D 59 A5 07 34 28 86 27\n"
"1F FA 9E 53 4F 2A B6 42 AD 37 12 62 F5 72 36 B6\n"
"02 12 40 44 FE C7 9E 95 89 43 51 5E B4 6E C7 67\n"
"80 58 43 BE CC 07 28 BD 59 FF 1C 4C 8D 90 42 F4\n"
"CF FD 54 00 4F 48 72 2B E1 67 3C 84 17 68 95 BF\n"
"CA 07 7B DF 86 9D 56 E3 32 E3 70 87 B7 F8 3A F7\n"
"E3 6E 65 14 7C BB 76 B7 17 F1 42 8C 6F 2A 34 64\n"
"10 35 14 8C 85 F6 57 BF F3 5C 55 9D AD 03 10 F3\n"
"\n"
" Public Exponent (24 bits):\n"
" 01 00 01",
x509_certificate_model::ProcessSubjectPublicKeyInfo(cert.get()));
}
{
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "prime256v1-ecdsa-intermediate.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(
"04 D5 C1 4A 32 95 95 C5 88 FA 01 FA C5 9E DC E2\n"
"99 62 EB 13 E5 35 42 B3 7A FC 46 C0 FA 29 12 C8\n"
"2D EA 30 0F D2 9A 47 97 2C 7E 89 E6 EF 49 55 06\n"
"C9 37 C7 99 56 16 B2 2B C9 7C 69 8E 10 7A DD 1F\n"
"42",
x509_certificate_model::ProcessSubjectPublicKeyInfo(cert.get()));
}
}
TEST_F(X509CertificateModelTest, ProcessRawBitsSignatureWrap) {
net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
net::GetTestCertsDirectory(), "google.single.pem"));
ASSERT_TRUE(cert.get());
EXPECT_EQ(
"9F 43 CF 5B C4 50 29 B1 BF E2 B0 9A FF 6A 21 1D\n"
"2D 12 C3 2C 4E 5A F9 12 E2 CE B9 82 52 2D E7 1D\n"
"7E 1A 76 96 90 79 D1 24 52 38 79 BB 63 8D 80 97\n"
"7C 23 20 0F 91 4D 16 B9 EA EE F4 6D 89 CA C6 BD\n"
"CC 24 68 D6 43 5B CE 2A 58 BF 3C 18 E0 E0 3C 62\n"
"CF 96 02 2D 28 47 50 34 E1 27 BA CF 99 D1 50 FF\n"
"29 25 C0 36 36 15 33 52 70 BE 31 8F 9F E8 7F E7\n"
"11 0C 8D BF 84 A0 42 1A 80 89 B0 31 58 41 07 5F",
x509_certificate_model::ProcessRawBitsSignatureWrap(cert.get()));
}

@ -31,10 +31,18 @@ CertificateViewerUITest.prototype = {
* Show the certificate viewer dialog.
*/
testGenPreamble: function() {
GEN('ShowCertificateViewer();');
GEN('ShowCertificateViewerGoogleCert();');
},
};
var CertificateViewerUIInvalidCertTest = class extends CertificateViewerUITest {
get testGenPreamble() {
return () => {
GEN('ShowCertificateViewerInvalidCert();');
};
}
};
// Helper for loading the Mocha test file as a JS module. Not using
// test_loader.html, as the test code needs to be loaded in the context of the
// dialog triggered with the ShowCertificateViewer() C++ call above.
@ -80,3 +88,9 @@ TEST_F('CertificateViewerUITest', 'Details', function() {
mocha.grep('Details').run();
});
});
TEST_F('CertificateViewerUIInvalidCertTest', 'InvalidCert', function() {
loadTestModule().then(() => {
mocha.grep('InvalidCert').run();
});
});

@ -31,6 +31,9 @@ suite('CertificateViewer', function() {
// Tests for the correct common name in the test certificate.
test('CommonName', function() {
assertTrue(document.querySelector('#general-error').hidden);
assertFalse(document.querySelector('#general-fields').hidden);
assertEquals(
'www.google.com', document.querySelector('#issued-cn').textContent);
});
@ -68,4 +71,16 @@ suite('CertificateViewer', function() {
certFields.selectedItem = certFields.items[0];
assertEquals('', certFieldVal.textContent);
});
test('InvalidCert', async function() {
// Error should be shown instead of cert fields.
assertFalse(document.querySelector('#general-error').hidden);
assertTrue(document.querySelector('#general-fields').hidden);
// Cert hash should still be shown.
assertEquals(
'78 71 88 FF A5 CC A4 82 12 ED 29 1E 62 CB 03 E1\n' +
'1C 1F 82 79 DF 07 FE B1 D2 B0 E0 2E 0E 4A A9 E4',
document.querySelector('#sha256').textContent);
});
});

@ -18,7 +18,7 @@
#include "content/public/browser/web_ui.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "net/cert/x509_util_nss.h"
#include "net/cert/x509_util.h"
#include "net/test/test_certificate_data.h"
// Test framework for
@ -29,22 +29,38 @@ class CertificateViewerUITest : public WebUIBrowserTest {
~CertificateViewerUITest() override;
protected:
void ShowCertificateViewer();
void ShowCertificateViewerGoogleCert();
void ShowCertificateViewerInvalidCert();
void ShowCertificateViewer(std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs);
};
void CertificateViewerUITest::ShowCertificateViewer() {
net::ScopedCERTCertificate google_cert(
net::x509_util::CreateCERTCertificateFromBytes(google_der,
sizeof(google_der)));
ASSERT_TRUE(google_cert);
net::ScopedCERTCertificateList certs;
certs.push_back(net::x509_util::DupCERTCertificate(google_cert.get()));
void CertificateViewerUITest::ShowCertificateViewerGoogleCert() {
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs;
certs.push_back(
net::x509_util::CreateCryptoBuffer(base::make_span(google_der)));
ASSERT_TRUE(certs.back());
ShowCertificateViewer(std::move(certs));
}
void CertificateViewerUITest::ShowCertificateViewerInvalidCert() {
const uint8_t kInvalid[] = {42, 42, 42, 42, 42};
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs;
certs.push_back(
net::x509_util::CreateCryptoBuffer(base::make_span(kInvalid)));
ASSERT_TRUE(certs.back());
ShowCertificateViewer(std::move(certs));
}
void CertificateViewerUITest::ShowCertificateViewer(
std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> certs) {
ASSERT_TRUE(browser());
ASSERT_TRUE(browser()->window());
CertificateViewerDialog* dialog = CertificateViewerDialog::ShowConstrained(
std::move(certs), browser()->tab_strip_model()->GetActiveWebContents(),
std::move(certs), /*cert_nicknames=*/{},
browser()->tab_strip_model()->GetActiveWebContents(),
browser()->window()->GetNativeWindow());
content::WebContents* webui_webcontents = dialog->webui_->GetWebContents();
EXPECT_TRUE(content::WaitForLoadStop(webui_webcontents));

File diff suppressed because it is too large Load Diff

@ -43,37 +43,10 @@
#include <cert.h>
#include <string>
#include "net/cert/cert_database.h"
#include "net/cert/cert_type.h"
namespace mozilla_security_manager {
std::string DumpOidString(SECItem* oid);
std::string GetOIDText(SECItem* oid);
std::string ProcessRDN(CERTRDN* rdn);
std::string ProcessName(CERTName* name);
std::string ProcessBasicConstraints(SECItem* extension_data);
std::string ProcessGeneralName(PRArenaPool* arena,
CERTGeneralName* current);
std::string ProcessGeneralNames(PRArenaPool* arena,
CERTGeneralName* name_list);
std::string ProcessAltName(SECItem* extension_data);
std::string ProcessSubjectKeyId(SECItem* extension_data);
std::string ProcessAuthKeyId(SECItem* extension_data);
std::string ProcessCrlDistPoints(SECItem* extension_data);
std::string ProcessAuthInfoAccess(SECItem* extension_data);
std::string ProcessIA5String(SECItem* extension_data);
std::string ProcessBMPString(SECItem* extension_data);
std::string ProcessNSCertTypeExtension(SECItem* extension_data);
std::string ProcessKeyUsageBitString(SECItem* bitstring, char sep);
std::string ProcessKeyUsageExtension(SECItem* extension_data);
std::string ProcessExtKeyUsage(SECItem* extension_data);
std::string ProcessExtensionData(CERTCertExtension* extension);
std::string ProcessSubjectPublicKeyInfo(CERTSubjectPublicKeyInfo* spki);
net::CertType GetCertType(CERTCertificate *cert);
} // namespace mozilla_security_manager

@ -236,6 +236,9 @@ bool ParseAndAddDistributionPoint(
ParsedTbsCertificate::ParsedTbsCertificate() = default;
ParsedTbsCertificate::ParsedTbsCertificate(ParsedTbsCertificate&& other) =
default;
ParsedTbsCertificate::~ParsedTbsCertificate() = default;
bool VerifySerialNumber(const der::Input& value,

@ -190,6 +190,8 @@ enum class CertificateVersion {
// sets.
struct NET_EXPORT ParsedTbsCertificate {
ParsedTbsCertificate();
ParsedTbsCertificate(ParsedTbsCertificate&& other);
ParsedTbsCertificate& operator=(ParsedTbsCertificate&& other) = default;
~ParsedTbsCertificate();
// Corresponds with "version" from RFC 5280: