// Copyright 2026 Google LLC
//
// 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.
//

#include "cose/simple_cms_parser.h"

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "absl/algorithm/container.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "crypto/algorithms.h"
#include "crypto/default/cms/certificates.h"
#include "crypto/default/cms/cms_error_code.h"
#include "crypto/default/cms/cms_parser.h"
#include "crypto/default/cms/oids.h"
#include "crypto/default/cms/verify_signature.h"
#include "openssl/asn1.h"
#include "openssl/bytestring.h"
#include "openssl/mem.h"
#include "openssl/nid.h"
#include "openssl/obj.h"
#include "openssl/stack.h"
#include "openssl/x509.h"
#include "tsp/constants.h"
#include "tsp/parsed_timestamp_token.h"

namespace credentio {

namespace {

absl::StatusOr<std::string> GetDer(X509* x509) {
  uint8_t* der_ptr = nullptr;
  int der_len = i2d_X509(x509, &der_ptr);
  bssl::UniquePtr<uint8_t> der(der_ptr);

  if (der_len <= 0) {
    return absl::InvalidArgumentError(
        "cannot convert certificate within timestamp token to DER");
  }
  return std::string(reinterpret_cast<char*>(der_ptr), der_len);
}

}  // namespace

SimpleParsedTimestampToken::SimpleParsedTimestampToken(absl::string_view data)
    : data_(data) {}

absl::StatusOr<std::unique_ptr<SimpleParsedTimestampToken>>
SimpleParsedTimestampToken::Create(absl::string_view timestamp_token) {
  auto token =
      absl::WrapUnique(new SimpleParsedTimestampToken(timestamp_token));
  std::string error_message;
  credentio_cms::ErrorCode err = credentio_cms::ParseCms(
      token->data_.data(), token->data_.size(), &token->cms_, &error_message);

  if (err != credentio_cms::ErrorCode::OK) {
    return absl::InvalidArgumentError(
        absl::StrCat("could not parse TimeStampToken cms: ", error_message));
  }

  if (!credentio_cms::CompareOid(token->cms_.content_type.cbs(),
                                 credentio_cms::kCtTstInfoOid,
                                 sizeof(credentio_cms::kCtTstInfoOid))) {
    return absl::InvalidArgumentError(
        "TimeStampToken eContentType is not id-ct-TSTInfo");
  }
  return token;
}

absl::StatusOr<const credentio_cms::SignerInfo*>
SimpleParsedTimestampToken::GetSingleSignerInfo() const {
  const std::vector<credentio_cms::SignerInfo>& signer_infos = cms_.signers;
  if (signer_infos.size() != 1) {
    return absl::InvalidArgumentError(
        absl::StrFormat("wrong number of signer infos: timestamp has %d "
                        "signers; exactly 1 is required",
                        signer_infos.size()));
  }
  return &signer_infos[0];
}

absl::StatusOr<X509*> SimpleParsedTimestampToken::GetSignerCert(
    const STACK_OF(X509) * certs,
    const credentio_cms::SignerInfo& signer_info) const {
  std::vector<X509*> tsa_certs =
      credentio_cms::GetSignerCertificates(certs, signer_info);
  if (tsa_certs.empty() || tsa_certs[0] == nullptr) {
    return absl::UnauthenticatedError(
        "timestamp does not contain TSA certificate");
  }
  return tsa_certs[0];
}

absl::Status SimpleParsedTimestampToken::VerifySignature() const {
  ABSL_ASSIGN_OR_RETURN(auto signer_info, GetSingleSignerInfo());

  bssl::UniquePtr<STACK_OF(X509)> certs(
      credentio_cms::GetAllCertificates(cms_));
  if (!certs) {
    return absl::UnauthenticatedError("failed to parse certificates");
  }

  ABSL_ASSIGN_OR_RETURN(auto tsa_cert,
                        GetSignerCert(certs.get(), *signer_info));

  return credentio_cms::VerifySignature(cms_, *signer_info, cms_.content,
                                        *tsa_cert)
      .status();
}

absl::StatusOr<HashAlgorithm>
SimpleParsedTimestampToken::GetMessageImprintHashAlgorithm() const {
  ABSL_ASSIGN_OR_RETURN(auto signer_info, GetSingleSignerInfo());
  return NidToHashAlgorithm(
      OBJ_cbs2nid(signer_info->digest_algorithm.algorithm_oid.cbs_ptr()));
}

absl::StatusOr<std::vector<std::string>>
SimpleParsedTimestampToken::GetCertificateChain() const {
  ABSL_ASSIGN_OR_RETURN(auto signer_info, GetSingleSignerInfo());

  bssl::UniquePtr<STACK_OF(X509)> certs(
      credentio_cms::GetAllCertificates(cms_));
  if (!certs) {
    return absl::UnauthenticatedError("failed to parse certificates");
  }

  ABSL_ASSIGN_OR_RETURN(auto tsa_cert,
                        GetSignerCert(certs.get(), *signer_info));

  std::vector<std::string> chain;
  chain.reserve(sk_X509_num(certs.get()) + 1);

  ABSL_ASSIGN_OR_RETURN(auto tsa_der, GetDer(tsa_cert));
  chain.push_back(std::move(tsa_der));

  for (size_t i = 0; i < sk_X509_num(certs.get()); ++i) {
    X509* x509 = sk_X509_value(certs.get(), i);
    if (X509_cmp(x509, tsa_cert) != 0) {
      ABSL_ASSIGN_OR_RETURN(auto der, GetDer(x509));
      chain.push_back(std::move(der));
    }
  }
  return chain;
}

absl::StatusOr<absl::string_view>
SimpleParsedTimestampToken::GetSigningCertificateV2Bytes() const {
  ABSL_ASSIGN_OR_RETURN(auto signer_info, GetSingleSignerInfo());

  const auto& attributes = signer_info->signed_attributes;
  auto v2_attribute = absl::c_find_if(
      attributes, [](const credentio_cms::Attribute& attribute) -> bool {
        const CBS* cbs = &attribute.type.cbs();
        bssl::UniquePtr<ASN1_OBJECT> oid(
            ASN1_OBJECT_create(NID_undef, CBS_data(cbs), CBS_len(cbs),
                               /*sn=*/nullptr, /*ln=*/nullptr));
        if (!oid) {
          return false;
        }
        return OBJ_cmp(IdAaSigningCertificateV2(), oid.get()) == 0;
      });

  if (v2_attribute == attributes.end()) {
    return absl::InvalidArgumentError(
        "invalid signed attributes; TSA did not set the "
        "\"SigningCertificateV2\" signed attribute");
  }

  if (v2_attribute->values.size() != 1) {
    return absl::InvalidArgumentError(
        absl::StrFormat("SigningCertificateV2 signed attribute contains the "
                        "wrong number of entries; got %d entries, expect 1",
                        v2_attribute->values.size()));
  }

  CBS signing_certificate_cbs = v2_attribute->values[0].cbs();
  const char* data =
      reinterpret_cast<const char*>(CBS_data(&signing_certificate_cbs));
  size_t len = CBS_len(&signing_certificate_cbs);
  return absl::string_view(data, len);
}

absl::StatusOr<absl::string_view> SimpleParsedTimestampToken::GetTstInfoBytes()
    const {
  if (cms_.content.size() != 1) {
    return absl::InvalidArgumentError(
        absl::StrFormat("TSTInfo content contains unexpected number of chunks; "
                        "got %d chunks, expect 1",
                        cms_.content.size()));
  }
  const CBS& cbs = cms_.content[0].cbs();
  const char* data = reinterpret_cast<const char*>(CBS_data(&cbs));
  size_t len = CBS_len(&cbs);
  return absl::string_view(data, len);
}

absl::StatusOr<std::unique_ptr<ParsedTimestampToken>>
SimpleCmsParser::ParseTimestampToken(absl::string_view timestamp_token) const {
  return SimpleParsedTimestampToken::Create(timestamp_token);
}

}  // namespace credentio
