// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/trusted_vault/recovery_key_store_certificate.h"

#include <string>
#include <string_view>
#include <vector>

#include "base/base64.h"
#include "base/containers/span.h"
#include "base/memory/scoped_refptr.h"
#include "base/notimplemented.h"
#include "base/strings/string_view_util.h"
#include "components/trusted_vault/securebox.h"
#include "crypto/signature_verifier.h"
#include "net/cert/asn1_util.h"
#include "net/cert/time_conversions.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "third_party/boringssl/src/pki/cert_issuer_source_static.h"
#include "third_party/boringssl/src/pki/parse_certificate.h"
#include "third_party/boringssl/src/pki/parsed_certificate.h"
#include "third_party/boringssl/src/pki/path_builder.h"
#include "third_party/boringssl/src/pki/simple_path_builder_delegate.h"
#include "third_party/boringssl/src/pki/trust_store_in_memory.h"
#include "third_party/libxml/chromium/xml_reader.h"

namespace trusted_vault {

namespace {

// This is the root of trust for the backend certificate list verification. This
// is generated by the trusted execution platforms team
// (trusted-execution-platforms@google.com) and hardcoded in the server code
// that uses this cert in the google3 codebase. As a root CA cert, it should
// very rarely be changed.
constexpr uint8_t kRecoverableKeyStoreServiceRootCaCert[] = {
    0x30, 0x82, 0x05, 0x0f, 0x30, 0x82, 0x02, 0xf7, 0xa0, 0x03, 0x02, 0x01,
    0x02, 0x02, 0x10, 0x6c, 0xd7, 0x6e, 0x79, 0x4d, 0xa8, 0xd2, 0xf3, 0x3d,
    0x80, 0x6a, 0xb8, 0x37, 0xa6, 0xe1, 0x8f, 0x30, 0x0d, 0x06, 0x09, 0x2a,
    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x31,
    0x31, 0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x47,
    0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20,
    0x4b, 0x65, 0x79, 0x20, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x53, 0x65,
    0x72, 0x76, 0x69, 0x63, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
    0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x35, 0x30, 0x37, 0x31,
    0x38, 0x32, 0x34, 0x30, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x35,
    0x30, 0x38, 0x31, 0x39, 0x32, 0x34, 0x30, 0x32, 0x5a, 0x30, 0x31, 0x31,
    0x2f, 0x30, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x26, 0x47, 0x6f,
    0x6f, 0x67, 0x6c, 0x65, 0x20, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x4b,
    0x65, 0x79, 0x20, 0x56, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x53, 0x65, 0x72,
    0x76, 0x69, 0x63, 0x65, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41,
    0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00,
    0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xad, 0x48, 0x33,
    0xbb, 0xee, 0x28, 0xf7, 0x29, 0x76, 0xd9, 0xea, 0xa5, 0xd4, 0x18, 0x86,
    0x06, 0xad, 0xe0, 0x59, 0x7a, 0x28, 0x87, 0x6a, 0xa5, 0xdc, 0x9f, 0xaf,
    0x56, 0xec, 0xdf, 0xfd, 0x38, 0x63, 0xcd, 0xd2, 0x20, 0xd3, 0x19, 0x24,
    0x93, 0x0f, 0xcd, 0x00, 0x5c, 0x58, 0x16, 0x2e, 0x3d, 0x12, 0x8d, 0x5f,
    0x6b, 0xf8, 0x5f, 0xf3, 0x00, 0x88, 0xa0, 0x0a, 0x82, 0x12, 0xcd, 0x65,
    0x0f, 0xab, 0x44, 0xdd, 0xc0, 0x83, 0xdd, 0x3d, 0xfe, 0x11, 0x03, 0xea,
    0xba, 0x1e, 0x82, 0x07, 0x62, 0xa6, 0x64, 0x32, 0x7a, 0x98, 0xf9, 0xd7,
    0xbd, 0x55, 0x25, 0x52, 0xe1, 0x6b, 0xd0, 0xed, 0x8c, 0xc1, 0x99, 0x30,
    0xca, 0x5a, 0x81, 0x11, 0x3c, 0xca, 0xd3, 0x1e, 0x4d, 0x08, 0x78, 0x0b,
    0xfe, 0x9e, 0x3b, 0xbe, 0x48, 0xe1, 0x1f, 0x1e, 0x8b, 0xa9, 0x56, 0xa8,
    0x6e, 0x28, 0x0a, 0x94, 0x7c, 0x6c, 0xce, 0xf5, 0x62, 0xe1, 0xf9, 0x2d,
    0xfe, 0xaa, 0xbb, 0x29, 0x6d, 0xd8, 0x4d, 0x5c, 0x61, 0xc1, 0xd2, 0xc6,
    0x11, 0xa6, 0xfe, 0x3a, 0xa4, 0x9f, 0xc0, 0xcc, 0x5d, 0x04, 0xb8, 0x4c,
    0x7c, 0x4d, 0x0a, 0xd1, 0xdb, 0xc5, 0xb7, 0xc6, 0xec, 0xf3, 0x22, 0x40,
    0x17, 0x4e, 0x03, 0x26, 0xc3, 0x1b, 0x44, 0x28, 0x45, 0x14, 0x1a, 0x53,
    0xd7, 0xb6, 0x74, 0xbb, 0x9d, 0xe2, 0x20, 0x00, 0x2e, 0xe6, 0xa5, 0x50,
    0x84, 0xaa, 0xd0, 0x5e, 0x22, 0x00, 0xc2, 0x06, 0xe8, 0x66, 0xa7, 0x7e,
    0x26, 0x41, 0xcb, 0x5d, 0x4d, 0x5f, 0x25, 0xe5, 0x53, 0xe5, 0x62, 0x4e,
    0x26, 0x0a, 0x09, 0x15, 0x61, 0xe4, 0x75, 0x69, 0x07, 0xb5, 0xae, 0x26,
    0x49, 0x89, 0x52, 0xef, 0x62, 0x75, 0x43, 0xdd, 0xbb, 0x24, 0x3d, 0x49,
    0x74, 0x44, 0xf5, 0x90, 0x5b, 0x47, 0xf8, 0x40, 0xed, 0x60, 0x0b, 0x71,
    0xef, 0x1e, 0xc5, 0xf7, 0x10, 0x00, 0x6d, 0xbd, 0xad, 0x30, 0x84, 0xf0,
    0xb3, 0xfc, 0x30, 0x77, 0x6a, 0xc0, 0xcd, 0x94, 0xd7, 0xfe, 0x4c, 0x51,
    0x6c, 0x39, 0x57, 0x54, 0xb4, 0xe8, 0x53, 0x4e, 0x4b, 0x15, 0x83, 0xeb,
    0xf9, 0xd1, 0x55, 0xd7, 0x0b, 0xd7, 0x9a, 0x2d, 0x23, 0x96, 0x42, 0x31,
    0x9e, 0x17, 0x5a, 0x54, 0x1a, 0x96, 0x0b, 0xdd, 0xe9, 0xe7, 0x6f, 0x14,
    0x89, 0x47, 0x0b, 0xa6, 0x26, 0xfe, 0x1d, 0x5c, 0xcc, 0x58, 0x67, 0x58,
    0x23, 0x71, 0xb5, 0x34, 0xe6, 0xbf, 0x95, 0x3a, 0x74, 0x73, 0xc2, 0xdc,
    0x6c, 0x98, 0xda, 0xa6, 0x28, 0x95, 0x9d, 0xe4, 0x50, 0x27, 0x77, 0x08,
    0xa8, 0x33, 0xce, 0x48, 0x49, 0xc4, 0xab, 0x8d, 0x21, 0xc9, 0x97, 0x75,
    0x8f, 0x1d, 0xc9, 0x9c, 0xec, 0x49, 0x33, 0x01, 0xec, 0xf2, 0xfe, 0x2c,
    0xf4, 0x62, 0x25, 0x6f, 0x70, 0x5c, 0x3a, 0x60, 0xef, 0x03, 0xf3, 0x2e,
    0xd3, 0xdc, 0x44, 0x30, 0xac, 0x29, 0x1c, 0x19, 0xb8, 0x4c, 0x50, 0xca,
    0x5d, 0xe1, 0x87, 0x39, 0x68, 0x5a, 0xed, 0xc7, 0x16, 0x10, 0x40, 0x9b,
    0xc8, 0xee, 0x67, 0x72, 0xee, 0x97, 0xb8, 0xdd, 0xa2, 0xcb, 0x3f, 0x52,
    0xf9, 0x3b, 0x8c, 0xca, 0x36, 0x41, 0x13, 0x9e, 0x76, 0xa7, 0xa3, 0xee,
    0xe6, 0x01, 0x02, 0xdb, 0x19, 0x3e, 0xa9, 0xa6, 0xf4, 0x34, 0x60, 0xd3,
    0x1d, 0xd2, 0xca, 0x2d, 0xbc, 0x96, 0x9f, 0x72, 0x31, 0x76, 0x60, 0x47,
    0xc9, 0x3a, 0xfb, 0x88, 0xf0, 0xaa, 0x9a, 0x9c, 0x87, 0x9e, 0x09, 0x02,
    0xfe, 0x96, 0xc6, 0x7e, 0xf1, 0xae, 0xb1, 0xce, 0x41, 0xa4, 0x1b, 0xa0,
    0xb0, 0x1b, 0x65, 0xcf, 0xae, 0xe6, 0xe1, 0x15, 0x8b, 0x27, 0xbd, 0xb2,
    0x01, 0xe5, 0x4f, 0x3b, 0xf9, 0x72, 0xff, 0xcc, 0x38, 0xa2, 0xb3, 0x6c,
    0x19, 0x68, 0xe7, 0xde, 0xcd, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23,
    0x30, 0x21, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
    0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d,
    0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
    0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
    0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x68, 0x96, 0x96, 0xef, 0xb8,
    0xab, 0x2c, 0x60, 0x3d, 0xbe, 0x91, 0xb0, 0x0d, 0x26, 0xc1, 0x1e, 0xd5,
    0xdb, 0x55, 0x09, 0xf6, 0xb1, 0x29, 0x62, 0x14, 0x8d, 0xf8, 0x04, 0x69,
    0x4d, 0x61, 0xa2, 0x23, 0x6d, 0x91, 0x08, 0x94, 0x86, 0x2b, 0x46, 0x6b,
    0x3c, 0x67, 0x85, 0x43, 0x31, 0x36, 0x06, 0x99, 0xd5, 0x45, 0xd9, 0x8b,
    0x4d, 0x5e, 0x63, 0x7f, 0xd2, 0x54, 0x4a, 0xd8, 0xc7, 0xa0, 0xfb, 0xcd,
    0x60, 0x59, 0xf0, 0x2d, 0x32, 0x74, 0x13, 0x67, 0xbd, 0x3a, 0x58, 0xfc,
    0x32, 0xb1, 0xeb, 0x02, 0xe7, 0x00, 0x50, 0x52, 0xe1, 0x97, 0x8c, 0x28,
    0x5b, 0x3d, 0x24, 0x53, 0xf5, 0xf4, 0x10, 0x1d, 0x63, 0xe9, 0x8d, 0x92,
    0x5e, 0xb0, 0x1a, 0x64, 0xf8, 0x8c, 0x32, 0x9a, 0xbc, 0x04, 0xa8, 0xf7,
    0x98, 0x7d, 0x4c, 0x6d, 0x5e, 0x2c, 0xb5, 0x9d, 0x24, 0x88, 0x75, 0x29,
    0x66, 0xee, 0x8f, 0x12, 0x6a, 0xe8, 0x8d, 0x81, 0xbb, 0x14, 0xa2, 0x8d,
    0xdf, 0x49, 0xda, 0xdb, 0x15, 0xdf, 0x88, 0xe7, 0xe5, 0xd8, 0x9b, 0xac,
    0x56, 0xcc, 0x87, 0x0e, 0xa9, 0x94, 0x9f, 0xf1, 0xe3, 0x4e, 0x1e, 0xb3,
    0x01, 0x22, 0xaa, 0x13, 0xa8, 0x71, 0x13, 0xe1, 0x49, 0x46, 0x5d, 0x95,
    0x43, 0x87, 0x5c, 0xaf, 0x84, 0xaf, 0x88, 0x7b, 0x5d, 0x6e, 0x29, 0x8c,
    0xcb, 0x62, 0xe0, 0x84, 0xb9, 0xd9, 0xe0, 0x51, 0x38, 0x5e, 0x12, 0x60,
    0x46, 0x7c, 0x3d, 0x4d, 0xe4, 0x55, 0xe4, 0x2f, 0x52, 0x9f, 0xba, 0x66,
    0x9c, 0x00, 0x39, 0x5f, 0x40, 0xbc, 0x65, 0x78, 0x57, 0xbd, 0xfb, 0xeb,
    0x77, 0x1e, 0x1f, 0x2f, 0x75, 0x0a, 0x96, 0x4d, 0x4b, 0xaa, 0x56, 0xf9,
    0xb2, 0x4c, 0x68, 0x2b, 0x54, 0x7d, 0xc3, 0x0a, 0xfe, 0x68, 0xd2, 0x0e,
    0xf9, 0xcb, 0x91, 0xf0, 0x90, 0x39, 0x0e, 0x61, 0x03, 0x58, 0x5c, 0x39,
    0x06, 0xe7, 0x61, 0xfe, 0xe5, 0x96, 0x66, 0x50, 0x53, 0xc9, 0x55, 0xb6,
    0xc9, 0xb6, 0xd3, 0x07, 0xab, 0x64, 0x98, 0xe7, 0x3c, 0x73, 0x4f, 0x17,
    0x3a, 0x0c, 0x41, 0x68, 0xaa, 0xec, 0x5c, 0x02, 0xe6, 0x25, 0xc9, 0x6e,
    0x69, 0xb8, 0xe6, 0x37, 0x58, 0xe9, 0xf3, 0x56, 0x9e, 0xd5, 0xea, 0x5e,
    0x37, 0x7d, 0x63, 0x27, 0x83, 0x79, 0x20, 0x4e, 0x5a, 0xab, 0xb5, 0xdb,
    0x4c, 0x59, 0x8a, 0x93, 0x0a, 0x60, 0x4d, 0x3b, 0xc9, 0x9a, 0xa0, 0x91,
    0xd9, 0x7c, 0xd6, 0xba, 0x39, 0x6f, 0x75, 0xb7, 0x63, 0x7e, 0x20, 0x01,
    0x96, 0x25, 0xac, 0x9c, 0xbc, 0xcb, 0x40, 0x23, 0xfc, 0x79, 0x9c, 0x1c,
    0x33, 0x82, 0xc0, 0xe5, 0x42, 0xb7, 0x7f, 0x59, 0x2d, 0x1e, 0x89, 0x6b,
    0xd4, 0xe2, 0x3d, 0x7a, 0xd4, 0x8e, 0x91, 0xe6, 0xc4, 0xda, 0x9c, 0xbc,
    0x2c, 0xf6, 0x01, 0x25, 0x69, 0x57, 0xdf, 0xab, 0x51, 0x01, 0xa8, 0x19,
    0x85, 0x4f, 0xcd, 0xa3, 0x23, 0xad, 0xbe, 0x14, 0x73, 0xab, 0xda, 0xdb,
    0xde, 0xb6, 0xdf, 0xf7, 0xa0, 0x0f, 0x10, 0x72, 0x94, 0x16, 0xc5, 0xc6,
    0xf6, 0x70, 0x44, 0x77, 0x60, 0x54, 0x29, 0x98, 0x21, 0x2c, 0xa3, 0xdf,
    0xf8, 0x93, 0x42, 0x53, 0xfd, 0xa9, 0x38, 0x6c, 0x74, 0x8d, 0xd3, 0x1c,
    0x7f, 0xe2, 0xbe, 0x6b, 0x50, 0xde, 0x1b, 0x46, 0x33, 0x19, 0x83, 0x11,
    0x90, 0x5b, 0xe9, 0x37, 0x78, 0x6f, 0x1d, 0x8a, 0xc9, 0x74, 0x1c, 0x8b,
    0xde, 0x44, 0x8f, 0xdd, 0x4b, 0x43, 0xd0, 0x7d, 0xa0, 0xf0, 0xfb, 0x3b,
    0x81, 0x12, 0xc4, 0x2c, 0x6d, 0x87, 0x38, 0x3c, 0x5b, 0x4a, 0x7f, 0x0f,
    0x57, 0x75, 0xed, 0xb9, 0x2b, 0xf1, 0x55, 0xa9, 0xc0, 0xea, 0xec, 0x9a,
    0x69, 0x2d, 0xc0, 0x67, 0xa4, 0xb1, 0x79, 0x52, 0xef, 0x9b, 0x0e, 0x74,
    0xed, 0xa6, 0x08};

// Returns a list of certificates from a certificate tag, traversing its entire
// contents. Ignores anything that is not a <cert> tag directly below the
// certificate tag.
// |xml_reader| must be pointing at the opening element that wraps certificates.
// After processing, |xml_reader| will be pointing at the matching closing tag.
// <intermediates>  <-- Point xml_reader here to start.
//   <cert>cert1</cert>
//   <not-cert>not a certificate</not-cert>  <-- ignored
//   <cert>cert2</cert>
// </intermediates>  <-- xml_reader will point here after processing.
// In this case, the return value would be { cert1, cert2 }.
std::vector<std::string> ParseCertList(XmlReader* xml_reader) {
  std::vector<std::string> cert_list;
  const int starting_depth = xml_reader->Depth();
  while (xml_reader->Read() && xml_reader->Depth() > starting_depth) {
    // Look for a <cert> element nested just under the starting tag.
    if (!xml_reader->IsElement() || xml_reader->Depth() != starting_depth + 1 ||
        xml_reader->NodeName() != "cert") {
      continue;
    }
    std::string cert;
    if (!xml_reader->ReadElementContent(&cert) || cert.empty()) {
      continue;
    }
    cert_list.push_back(std::move(cert));
  }
  return cert_list;
}

// Given a base64-encoded x509 certificate, returns the bssl representation (or
// nullptr if decoding failed).
std::shared_ptr<const bssl::ParsedCertificate> CertificateFromBase64(
    std::string_view b64) {
  std::optional<std::vector<uint8_t>> certificate_data =
      base::Base64Decode(b64);
  if (!certificate_data) {
    return nullptr;
  }
  return bssl::ParsedCertificate::Create(
      net::x509_util::CreateCryptoBuffer(*certificate_data),
      net::x509_util::DefaultParseCertificateOptions(), /*errors=*/nullptr);
}

// Returns a fresh trusted cert store for the cloud root.
std::unique_ptr<bssl::TrustStoreInMemory> ConstructTrustedCertStore() {
  // This code will run at most once a day. So there's no point keeping the
  // trust store around after use.
  auto trust_store = std::make_unique<bssl::TrustStoreInMemory>();
  std::shared_ptr<const bssl::ParsedCertificate> root_cert =
      bssl::ParsedCertificate::Create(
          net::x509_util::CreateCryptoBuffer(
              kRecoverableKeyStoreServiceRootCaCert),
          net::x509_util::DefaultParseCertificateOptions(), /*errors=*/nullptr);
  CHECK(root_cert);
  trust_store->AddTrustAnchor(root_cert);
  return trust_store;
}

}  // namespace

namespace internal {

ParsedRecoveryKeyStoreCertXML::ParsedRecoveryKeyStoreCertXML(
    std::vector<std::string> intermediates,
    std::vector<std::string> endpoints)
    : intermediates(std::move(intermediates)),
      endpoints(std::move(endpoints)) {}

ParsedRecoveryKeyStoreCertXML::ParsedRecoveryKeyStoreCertXML(
    ParsedRecoveryKeyStoreCertXML&&) = default;
ParsedRecoveryKeyStoreCertXML& ParsedRecoveryKeyStoreCertXML::operator=(
    ParsedRecoveryKeyStoreCertXML&&) = default;

ParsedRecoveryKeyStoreCertXML::~ParsedRecoveryKeyStoreCertXML() = default;

ParsedRecoveryKeyStoreSigXML::ParsedRecoveryKeyStoreSigXML(
    std::vector<std::string> intermediates,
    std::string certificate,
    std::string signature)
    : intermediates(std::move(intermediates)),
      certificate(std::move(certificate)),
      signature(std::move(signature)) {}

ParsedRecoveryKeyStoreSigXML::ParsedRecoveryKeyStoreSigXML(
    ParsedRecoveryKeyStoreSigXML&&) = default;
ParsedRecoveryKeyStoreSigXML& ParsedRecoveryKeyStoreSigXML::operator=(
    ParsedRecoveryKeyStoreSigXML&&) = default;

ParsedRecoveryKeyStoreSigXML::~ParsedRecoveryKeyStoreSigXML() = default;

std::optional<ParsedRecoveryKeyStoreCertXML> ParseRecoveryKeyStoreCertXML(
    std::string_view cert_xml) {
  XmlReader xml_reader;
  xml_reader.Load(cert_xml);
  if (!xml_reader.Read() || xml_reader.NodeName() != "certificate") {
    return std::nullopt;
  }
  std::vector<std::string> intermediates;
  std::vector<std::string> endpoints;
  while (xml_reader.Read()) {
    // Skip anything that is not an element nested under the root.
    if (!xml_reader.IsElement() || xml_reader.Depth() != 1) {
      continue;
    }
    // We expect a single <intermediates> and <endpoints> tags. This code only
    // has the last tags take effect, but that should be okay.
    if (xml_reader.NodeName() == "intermediates") {
      intermediates = ParseCertList(&xml_reader);
    } else if (xml_reader.NodeName() == "endpoints") {
      endpoints = ParseCertList(&xml_reader);
    }
  }
  if (intermediates.empty() || endpoints.empty()) {
    return std::nullopt;
  }
  return ParsedRecoveryKeyStoreCertXML(std::move(intermediates),
                                       std::move(endpoints));
}

std::optional<ParsedRecoveryKeyStoreSigXML> ParseRecoveryKeyStoreSigXML(
    std::string_view sig_xml) {
  XmlReader xml_reader;
  xml_reader.Load(sig_xml);
  if (!xml_reader.Read() || xml_reader.NodeName() != "signature") {
    return std::nullopt;
  }
  std::vector<std::string> intermediates;
  std::string certificate;
  std::string signature;
  while (xml_reader.Read()) {
    // Skip anything that is not an element nested under the root.
    if (!xml_reader.IsElement() || xml_reader.Depth() != 1) {
      continue;
    }
    // We expect a single <intermediates>, <certificate>, and <value> tags. This
    // code only has the last tags take effect, but that should be okay.
    if (xml_reader.NodeName() == "intermediates") {
      intermediates = ParseCertList(&xml_reader);
    } else if (xml_reader.NodeName() == "certificate") {
      if (!xml_reader.ReadElementContent(&certificate)) {
        return std::nullopt;
      }
    } else if (xml_reader.NodeName() == "value") {
      if (!xml_reader.ReadElementContent(&signature)) {
        return std::nullopt;
      }
    }
  }
  if (intermediates.empty() || certificate.empty() || signature.empty()) {
    return std::nullopt;
  }
  return ParsedRecoveryKeyStoreSigXML(
      std::move(intermediates), std::move(certificate), std::move(signature));
}

std::shared_ptr<const bssl::ParsedCertificate> VerifySignatureChain(
    std::string_view certificate_b64,
    base::span<std::string> intermediates_b64,
    base::Time current_time) {
  std::shared_ptr<const bssl::ParsedCertificate> certificate =
      CertificateFromBase64(certificate_b64);
  if (!certificate) {
    return nullptr;
  }

  bssl::CertIssuerSourceStatic intermediates;
  for (const auto& intermediate_b64 : intermediates_b64) {
    std::shared_ptr<const bssl::ParsedCertificate> intermediate =
        CertificateFromBase64(intermediate_b64);
    if (!intermediate) {
      // Ignore invalid base64. We may still be able to build a valid path.
      continue;
    }
    intermediates.AddCert(std::move(intermediate));
  }

  std::unique_ptr<bssl::TrustStoreInMemory> trusted_cert_store =
      ConstructTrustedCertStore();
  bssl::SimplePathBuilderDelegate builder_delegate(
      /*min_rsa_modulus_length_bits=*/2048,
      bssl::SimplePathBuilderDelegate::DigestPolicy::kStrong);
  bssl::der::GeneralizedTime verification_time;
  CHECK(net::EncodeTimeAsGeneralizedTime(current_time, &verification_time));
  bssl::CertPathBuilder path_builder(certificate, trusted_cert_store.get(),
                                     &builder_delegate, verification_time,
                                     bssl::KeyPurpose::ANY_EKU,
                                     bssl::InitialExplicitPolicy::kFalse,
                                     {bssl::der::Input(bssl::kAnyPolicyOid)},
                                     bssl::InitialPolicyMappingInhibit::kFalse,
                                     bssl::InitialAnyPolicyInhibit::kFalse);
  path_builder.AddCertIssuerSource(&intermediates);
  bssl::CertPathBuilder::Result result = path_builder.Run();
  if (!result.HasValidPath()) {
    return nullptr;
  }
  return certificate;
}

bool VerifySignature(std::shared_ptr<const bssl::ParsedCertificate> certificate,
                     std::string_view cert_xml,
                     std::string_view signature_b64) {
  std::optional<std::vector<uint8_t>> signature =
      base::Base64Decode(signature_b64);
  if (!signature) {
    return false;
  }
  size_t size_bits;
  net::X509Certificate::PublicKeyType type;
  net::X509Certificate::GetPublicKeyInfo(certificate->cert_buffer(), &size_bits,
                                         &type);
  crypto::SignatureVerifier::SignatureAlgorithm algo;
  switch (type) {
    case net::X509Certificate::PublicKeyType::kPublicKeyTypeECDSA:
      algo = crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256;
      break;
    case net::X509Certificate::PublicKeyType::kPublicKeyTypeRSA:
      algo = crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256;
      break;
    case net::X509Certificate::PublicKeyType::kPublicKeyTypeUnknown:
      return false;
  }
  crypto::SignatureVerifier signature_verifier;
  if (!net::x509_util::SignatureVerifierInitWithCertificate(
          &signature_verifier, algo, *signature, certificate->cert_buffer())) {
    return false;
  }
  signature_verifier.VerifyUpdate(base::as_byte_span(cert_xml));
  return signature_verifier.VerifyFinal();
}

std::vector<std::unique_ptr<SecureBoxPublicKey>> ExtractEndpointPublicKeys(
    ParsedRecoveryKeyStoreCertXML cert_xml,
    base::Time current_time) {
  std::vector<std::unique_ptr<SecureBoxPublicKey>> result;
  for (const auto& endpoint : cert_xml.endpoints) {
    std::shared_ptr<const bssl::ParsedCertificate> certificate =
        VerifySignatureChain(endpoint, cert_xml.intermediates, current_time);
    if (!certificate) {
      continue;
    }
    // Only ECDSA public keys are supported.
    size_t size_bits;
    net::X509Certificate::PublicKeyType type;
    net::X509Certificate::GetPublicKeyInfo(certificate->cert_buffer(),
                                           &size_bits, &type);
    if (type != net::X509Certificate::kPublicKeyTypeECDSA) {
      continue;
    }
    // Extract the public key from the SPKI.
    std::string_view ec_point_oct;
    if (!net::asn1::ExtractSubjectPublicKeyFromSPKI(
            base::as_string_view(certificate->tbs().spki_tlv), &ec_point_oct)) {
      continue;
    }
    // ExtractSubjectPublicKeyFromSPKI does not remove the initial octet
    // encoding the number of unused bits in the ASN.1 BIT STRING so we do it
    // here. The public key is always byte-aligned.
    ec_point_oct.remove_prefix(1);

    std::unique_ptr<SecureBoxPublicKey> key =
        SecureBoxPublicKey::CreateByImport(base::as_byte_span(ec_point_oct));
    if (!key) {
      continue;
    }
    result.push_back(std::move(key));
  }
  return result;
}

}  // namespace internal

// static
std::optional<RecoveryKeyStoreCertificate> RecoveryKeyStoreCertificate::Parse(
    std::string_view cert_xml,
    std::string_view sig_xml,
    base::Time current_time) {
  std::optional<internal::ParsedRecoveryKeyStoreSigXML> parsed_sig_xml =
      internal::ParseRecoveryKeyStoreSigXML(sig_xml);
  if (!parsed_sig_xml) {
    return std::nullopt;
  }
  std::shared_ptr<const bssl::ParsedCertificate> signing_certificate =
      internal::VerifySignatureChain(std::move(parsed_sig_xml->certificate),
                                     parsed_sig_xml->intermediates,
                                     current_time);
  if (!signing_certificate || !signing_certificate->has_key_usage() ||
      !signing_certificate->key_usage().AssertsBit(
          bssl::KEY_USAGE_BIT_DIGITAL_SIGNATURE)) {
    return std::nullopt;
  }
  if (!internal::VerifySignature(std::move(signing_certificate), cert_xml,
                                 parsed_sig_xml->signature)) {
    return std::nullopt;
  }
  std::optional<internal::ParsedRecoveryKeyStoreCertXML> parsed_cert_xml =
      internal::ParseRecoveryKeyStoreCertXML(cert_xml);
  if (!parsed_cert_xml) {
    return std::nullopt;
  }
  std::vector<std::unique_ptr<SecureBoxPublicKey>> endpoint_public_keys =
      internal::ExtractEndpointPublicKeys(std::move(*parsed_cert_xml),
                                          current_time);
  if (endpoint_public_keys.empty()) {
    return std::nullopt;
  }
  return RecoveryKeyStoreCertificate(std::move(endpoint_public_keys));
}

RecoveryKeyStoreCertificate::RecoveryKeyStoreCertificate(
    RecoveryKeyStoreCertificate&& other) = default;
RecoveryKeyStoreCertificate& RecoveryKeyStoreCertificate::operator=(
    RecoveryKeyStoreCertificate&& other) = default;
RecoveryKeyStoreCertificate::~RecoveryKeyStoreCertificate() = default;

RecoveryKeyStoreCertificate::RecoveryKeyStoreCertificate(
    std::vector<std::unique_ptr<SecureBoxPublicKey>> endpoint_public_keys)
    : endpoint_public_keys_(std::move(endpoint_public_keys)) {}

}  // namespace trusted_vault
