blob: 216e7fc2ad6bafd94f0d6472b032d81ebdca6b27 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_COMMON_NET_X509_CERTIFICATE_MODEL_H_
#define CHROME_COMMON_NET_X509_CERTIFICATE_MODEL_H_
#include <string>
#include <string_view>
#include <variant>
#include <vector>
#include "base/containers/span.h"
#include "base/time/time.h"
#include "third_party/boringssl/src/include/openssl/pool.h"
#include "third_party/boringssl/src/pki/parse_certificate.h"
#include "third_party/boringssl/src/pki/parse_name.h"
// This namespace defines a set of functions to be used in UI-related bits of
// X509 certificates.
namespace x509_certificate_model {
struct Extension {
std::string name;
std::string value;
};
struct NotPresent : std::monostate {};
struct Error : std::monostate {};
using OptionalStringOrError = std::variant<Error, NotPresent, std::string>;
class X509CertificateModel {
public:
// Construct an X509CertificateModel from |cert_data|, which must must not be
// nullptr.
explicit X509CertificateModel(bssl::UniquePtr<CRYPTO_BUFFER> cert_data);
X509CertificateModel(X509CertificateModel&& other);
X509CertificateModel& operator=(X509CertificateModel&& other) = default;
~X509CertificateModel();
// ---------------------------------------------------------------------------
// These methods are always safe to call even if |cert_data| could not be
// parsed.
// Returns lower case hex SHA256 hash of the certificate data.
std::string HashCertSHA256() const;
// Get something that can be used as a title for the certificate, using the
// following priority:
// subject commonName
// full subject
// dnsName or email address from subjectAltNames
// If none of those are present, or certificate could not be parsed,
// the hex SHA256 hash of the certificate data will be returned.
std::string GetTitle() const;
CRYPTO_BUFFER* cert_buffer() const { return cert_data_.get(); }
bool is_valid() const { return parsed_successfully_; }
// ---------------------------------------------------------------------------
// The rest of the methods should only be called if |is_valid()| returns true.
// Returns lower case hex SHA256 hash of the SPKI.
std::string HashSpkiSHA256() const;
std::string GetVersion() const;
std::string GetSerialNumberHexified() const;
// Get the validity notBefore and notAfter times, returning true on success
// or false on error in parsing or converting to a base::Time.
bool GetTimes(base::Time* not_before, base::Time* not_after) const;
// These methods returns the issuer/subject commonName/orgName/orgUnitName
// formatted as a string, if present. Returns NotPresent if the attribute
// type was not present, or Error if there was a parsing error.
// The Get{Issuer,Subject}CommonName methods return the last (most specific)
// commonName, while the other methods return the first (most general) value.
// This matches the NSS behaviour of CERT_GetCommonName, CERT_GetOrgName,
// CERT_GetOrgUnitName.
OptionalStringOrError GetIssuerCommonName() const;
OptionalStringOrError GetIssuerOrgName() const;
OptionalStringOrError GetIssuerOrgUnitName() const;
OptionalStringOrError GetSubjectCommonName() const;
OptionalStringOrError GetSubjectOrgName() const;
OptionalStringOrError GetSubjectOrgUnitName() const;
// Get the issuer/subject name as a text block with one line per
// attribute-value pair. Will process IDN in commonName, showing original and
// decoded forms. Returns NotPresent if the Name was an empty sequence.
// (Although note that technically an empty issuer name is invalid.)
OptionalStringOrError GetIssuerName() const;
OptionalStringOrError GetSubjectName() const;
// Returns textual representations of the certificate's extensions, if any.
// |critical_label| and |non_critical_label| will be used in the returned
// extension.value fields to describe extensions that are critical or
// non-critical.
std::vector<Extension> GetExtensions(
std::string_view critical_label,
std::string_view non_critical_label) const;
std::string ProcessSecAlgorithmSignature() const;
std::string ProcessSecAlgorithmSubjectPublicKey() const;
std::string ProcessSecAlgorithmSignatureWrap() const;
std::string ProcessSubjectPublicKeyInfo() const;
std::string ProcessRawBitsSignatureWrap() const;
private:
bool ParseExtensions(const bssl::der::Input& extensions_tlv);
std::string ProcessExtension(std::string_view critical_label,
std::string_view non_critical_label,
const bssl::ParsedExtension& extension) const;
std::optional<std::string> ProcessExtensionData(
const bssl::ParsedExtension& extension) const;
bool parsed_successfully_ = false;
bssl::UniquePtr<CRYPTO_BUFFER> cert_data_;
bssl::der::Input tbs_certificate_tlv_;
bssl::der::Input signature_algorithm_tlv_;
bssl::der::BitString signature_value_;
bssl::ParsedTbsCertificate tbs_;
bssl::RDNSequence subject_rdns_;
bssl::RDNSequence issuer_rdns_;
std::vector<bssl::ParsedExtension> extensions_;
// Parsed SubjectAltName extension.
std::unique_ptr<bssl::GeneralNames> subject_alt_names_;
};
// For host values, if they contain IDN Punycode-encoded A-labels, this will
// return a string suitable for display that contains both the original and the
// decoded U-label form. Otherwise, the string will be returned as is.
std::string ProcessIDN(const std::string& input);
// Parses |public_key_spki_der| as a DER-encoded X.509 SubjectPublicKeyInfo,
// then formats the public key as a string for displaying. Returns an empty
// string on error.
std::string ProcessRawSubjectPublicKeyInfo(base::span<const uint8_t> spki_der);
} // namespace x509_certificate_model
#endif // CHROME_COMMON_NET_X509_CERTIFICATE_MODEL_H_