// Copyright 2016 The Chromium Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BSSL_PKI_TRUST_STORE_H_
#define BSSL_PKI_TRUST_STORE_H_

#include <array>
#include <memory>
#include <optional>

#include <openssl/base.h>
#include <openssl/sha2.h>

#include "cert_issuer_source.h"
#include "merkle_tree.h"
#include "parsed_certificate.h"

BSSL_NAMESPACE_BEGIN

enum class CertificateTrustType {
  // This certificate is explicitly blocked (distrusted).
  DISTRUSTED,

  // The trustedness of this certificate is unknown (inherits trust from
  // its issuer).
  UNSPECIFIED,

  // This certificate is a trust anchor (as defined by RFC 5280).
  TRUSTED_ANCHOR,

  // This certificate can be used as a trust anchor (as defined by RFC 5280) or
  // a trusted leaf, depending on context.
  TRUSTED_ANCHOR_OR_LEAF,

  // This certificate is a directly trusted leaf.
  TRUSTED_LEAF,

  LAST = TRUSTED_ANCHOR
};

struct OPENSSL_EXPORT TrustedSubtree {
  Subtree range;
  std::array<uint8_t, SHA256_DIGEST_LENGTH> hash;
};

// Describes the level of trust in a certificate.
struct OPENSSL_EXPORT CertificateTrust {
  static constexpr CertificateTrust ForTrustAnchor() {
    CertificateTrust result;
    result.type = CertificateTrustType::TRUSTED_ANCHOR;
    return result;
  }

  static constexpr CertificateTrust ForTrustAnchorOrLeaf() {
    CertificateTrust result;
    result.type = CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF;
    return result;
  }

  static constexpr CertificateTrust ForTrustedLeaf() {
    CertificateTrust result;
    result.type = CertificateTrustType::TRUSTED_LEAF;
    return result;
  }

  static constexpr CertificateTrust ForUnspecified() {
    CertificateTrust result;
    return result;
  }

  static constexpr CertificateTrust ForDistrusted() {
    CertificateTrust result;
    result.type = CertificateTrustType::DISTRUSTED;
    return result;
  }

  constexpr CertificateTrust WithEnforceAnchorExpiry(bool value = true) const {
    CertificateTrust result = *this;
    result.enforce_anchor_expiry = value;
    return result;
  }

  constexpr CertificateTrust WithEnforceAnchorConstraints(
      bool value = true) const {
    CertificateTrust result = *this;
    result.enforce_anchor_constraints = value;
    return result;
  }

  constexpr CertificateTrust WithRequireAnchorBasicConstraints(
      bool value = true) const {
    CertificateTrust result = *this;
    result.require_anchor_basic_constraints = value;
    return result;
  }

  constexpr CertificateTrust WithRequireLeafSelfSigned(
      bool value = true) const {
    CertificateTrust result = *this;
    result.require_leaf_selfsigned = value;
    return result;
  }

  bool IsTrustAnchor() const;
  bool IsTrustLeaf() const;
  bool IsDistrusted() const;
  bool HasUnspecifiedTrust() const;

  std::string ToDebugString() const;

  static std::optional<CertificateTrust> FromDebugString(
      const std::string &trust_string);

  // The overall type of trust.
  CertificateTrustType type = CertificateTrustType::UNSPECIFIED;

  // Optionally, enforce extra bits on trust anchors. If these are false, the
  // only fields in a trust anchor certificate that are meaningful are its
  // name and SPKI.
  bool enforce_anchor_expiry = false;
  bool enforce_anchor_constraints = false;
  // Require that X.509v3 trust anchors have a basicConstraints extension.
  // X.509v1 and X.509v2 trust anchors do not support basicConstraints and are
  // not affected.
  // Additionally, this setting only has effect if `enforce_anchor_constraints`
  // is true, which also requires that the extension assert CA=true.
  bool require_anchor_basic_constraints = false;

  // Optionally, require trusted leafs to be self-signed to be trusted.
  bool require_leaf_selfsigned = false;
};

class OPENSSL_EXPORT MTCAnchor {
 public:
  // Create an MTCAnchor for a trusted log with |log_id| containing the DER
  // encoding of the relative OID of the log's ID. The |trusted_subtrees| must
  // be sorted by their subtree ranges.
  MTCAnchor(Span<const uint8_t> log_id,
            Span<const TrustedSubtree> trusted_subtrees);

  // Returns whether this MTCAnchor represents a valid anchor. This function
  // exists because the c'tor inputs could be invalid.
  bool IsValid() const;

  Span<const uint8_t> log_id() const { return log_id_; }
  // TODO(nharper): Move this function to TrustAnchor.
  der::Input NormalizedSubject() const;
  // TODO(nharper): Remove this function in favor of TrustAnchor's version.
  CertificateTrust CertTrust() const;
  // TODO(nharper): Move this function to TrustAnchor.
  std::shared_ptr<const ParsedCertificate> AsCert() const;
  std::optional<TreeHashConstSpan> SubtreeHash(Subtree target_range) const;

 private:
  void CreateSyntheticCert(Span<const uint8_t> log_id);

  std::vector<uint8_t> log_id_;
  std::shared_ptr<const ParsedCertificate> synthetic_cert_;
  std::vector<TrustedSubtree> trusted_subtrees_;
};

// A TrustAnchor contains information about how a trust anchor is trusted and
// what is trusted. It should be used in place of a (ParsedCertificate,
// CertificateTrust) tuple as some trust information, e.g. MTC anchors, is not
// representable by such a tuple.
//
// TODO(nharper): This class is the first step of a large refactor to stop
// representing TrustAnchors as ParsedCertificates. Prior to the introduction of
// Merkle Tree Certs, the information about a trust anchor was split between
// a ParsedCertificate (containing the anchor's Subject name and public key) and
// a CertificateTrust struct (informing when/how the trust anchor is trusted, as
// well as whether any additional constraints should be applied). With the
// introduction of Merkle Tree Certs, some of this information about how to use
// an MTC trust anchor fits in neither place. The eventual goal is that the
// TrustAnchor class is the single place that contains all information about a
// trust anchor, rather than that information being split across multiple
// objects. This will allow a further goal of removing the dependency of
// requiring that a trust anchor be representable as a ParsedCertificate: MTC
// trust anchors only have a ParsedCertificate accessor for compatibility
// reasons, and while draft-ietf-lamps-x509-alg-none improves the efficiency of
// storing trust anchors in X.509 certs, this refactor will allow further
// improvements for classical (non-MTC) roots.
//
// See also internal design doc:
// https://docs.google.com/document/d/1wqHAmZqtF8oJzNObFBm41lzDt2JWRhjM32A3z6ampJE/edit
class OPENSSL_EXPORT TrustAnchor {
 public:
  // Creates a default TrustAnchor with an unspecified CertificateTrust.
  TrustAnchor() = default;

  // Creates a TrustAnchor with no associated MTCAnchor.
  explicit TrustAnchor(CertificateTrust trust);
  TrustAnchor(CertificateTrust trust,
              std::shared_ptr<const MTCAnchor> mtc_anchor);

  // TODO(nharper): Temporarily add ParsedCertificate member and accessor.

  // TODO(nharper): Add accessors to get information about the trust anchor that
  // is currently found in the ParsedCertificate:
  // - `der::Input NormalizedSubject() const;`
  // - `UniquePtr<EVP_PKEY> PublicKey() const;`

  // Modifies the CertificateTrust for this TrustAnchor. Should only be called
  // by path_builder.cc.
  //
  // TODO(nharper): Remove this function as part of the larger TrustAnchor
  // refactor.
  void OverrideCertTrust(CertificateTrust new_trust);
  CertificateTrust CertTrust() const;
  std::shared_ptr<const bssl::MTCAnchor> MTCAnchor() const;

 private:
  CertificateTrust trust_;
  std::shared_ptr<const bssl::MTCAnchor> mtc_anchor_ = nullptr;
};

// Interface for finding intermediates / trust anchors, and testing the
// trustedness of certificates.
class OPENSSL_EXPORT TrustStore : public CertIssuerSource {
 public:
  TrustStore();

  TrustStore(const TrustStore &) = delete;
  TrustStore &operator=(const TrustStore &) = delete;

  // Returns the trusted of |cert|, which must be non-null.
  virtual CertificateTrust GetTrust(const ParsedCertificate *cert) = 0;

  // Returns the TrustAnchor that issued |cert|, if one exists.
  //
  // TODO(nharper): Make this a pure virtual function once all TrustStore
  // implementations have implemented this.
  virtual std::shared_ptr<const MTCAnchor> GetTrustedMTCIssuerOf(
      const ParsedCertificate *cert);

  // Disable async issuers for TrustStore, as it isn't needed.
  void AsyncGetIssuersOf(const ParsedCertificate *cert,
                         std::unique_ptr<Request> *out_req) final;
};

BSSL_NAMESPACE_END

#endif  // BSSL_PKI_TRUST_STORE_H_
