// 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 "crypto/default/cms/certificates.h"

#include <memory>
#include <string>
#include <vector>

#include "absl/log/check.h"
#include "absl/log/die_if_null.h"
#include "absl/strings/escaping.h"
#include "crypto/default/cms/cms_error_code.h"
#include "crypto/default/cms/cms_parser.h"
#include "crypto/default/cms/cms_test_helper.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "openssl/base.h"
#include "openssl/bio.h"
#include "openssl/bytestring.h"
#include "openssl/safestack.h"
#include "openssl/stack.h"
#include "openssl/x509.h"

using testing::ElementsAre;

namespace credentio_cms {
namespace {

std::string X509ToDer(X509* x509) {
  const int len = i2d_X509(x509, nullptr /* buffer */);
  CHECK_GT(len, 0);
  std::unique_ptr<char[]> data(new char[len]);
  unsigned char* dataptr = reinterpret_cast<unsigned char*>(data.get());
  const int len2 = i2d_X509(x509, &dataptr);
  CHECK_EQ(len, len2);
  std::string der_output;
  der_output.assign(data.get(), len);
  return der_output;
}

ByteString ByteStringFromString(const std::string& value) {
  ByteString bs;
  CBS_init(bs.cbs_ptr(), reinterpret_cast<const unsigned char*>(value.data()),
           value.length());
  return bs;
}

class CertificateTest : public testing::Test {
 protected:
  void SetUp() override {
    user1_rsa_.reset(
        ABSL_DIE_IF_NULL(PemToCertificate(GetFileContents("user1_both.pem"))));
    user1_ecc_.reset(
        ABSL_DIE_IF_NULL(PemToCertificate(GetFileContents("user1_ecc.pem"))));
    user2_rsa_.reset(
        ABSL_DIE_IF_NULL(PemToCertificate(GetFileContents("user2_both.pem"))));
    user1_rsa_der_ = X509ToDer(user1_rsa_.get());
    user1_ecc_der_ = X509ToDer(user1_ecc_.get());
    user2_rsa_der_ = X509ToDer(user2_rsa_.get());
    content_.certificates.push_back(ByteStringFromString(user1_rsa_der_));
    content_.certificates.push_back(ByteStringFromString(user1_ecc_der_));
    content_.certificates.push_back(ByteStringFromString(user2_rsa_der_));

    test_stack_ = sk_X509_new_null();
    sk_X509_push(test_stack_, user1_rsa_.get());
    sk_X509_push(test_stack_, user1_ecc_.get());
    sk_X509_push(test_stack_, user2_rsa_.get());
  }

  void TearDown() override {
    if (test_stack_ != nullptr) {
      sk_X509_free(test_stack_);
    }
  }

  STACK_OF(X509) * test_stack_ = nullptr;
  Content content_;
  bssl::UniquePtr<X509> user1_rsa_;
  bssl::UniquePtr<X509> user1_ecc_;
  bssl::UniquePtr<X509> user2_rsa_;
  std::string user1_rsa_der_;
  std::string user1_ecc_der_;
  std::string user2_rsa_der_;
};

TEST_F(CertificateTest, GetAllCertificates) {
  bssl::UniquePtr<STACK_OF(X509)> stack(GetAllCertificates(content_));
  ASSERT_EQ(3, sk_X509_num(stack.get()));
  EXPECT_EQ(0, X509_cmp(sk_X509_value(stack.get(), 0), user1_rsa_.get()));
  EXPECT_EQ(0, X509_cmp(sk_X509_value(stack.get(), 1), user1_ecc_.get()));
  EXPECT_EQ(0, X509_cmp(sk_X509_value(stack.get(), 2), user2_rsa_.get()));
}

TEST_F(CertificateTest, GetByName) {
  X509_NAME* issuer = X509_get_issuer_name(user1_rsa_.get());
  const int len = i2d_X509_NAME(issuer, nullptr /* buffer */);
  CHECK_GT(len, 0);
  std::unique_ptr<char[]> data(new char[len]);
  unsigned char* dataptr = reinterpret_cast<unsigned char*>(data.get());
  const int len2 = i2d_X509_NAME(issuer, &dataptr);
  CHECK_EQ(len, len2);
  std::string name_der;
  name_der.assign(data.get(), len);
  SignerInfo signer_info;
  signer_info.issuer_name = ByteStringFromString(name_der);
  std::string serial = "\x12\x3b";
  signer_info.serial_number = ByteStringFromString(serial);

  std::vector<X509*> matching = GetSignerCertificates(test_stack_, signer_info);
  EXPECT_THAT(matching, ElementsAre(user1_ecc_.get()));

  CHECK(absl::HexStringToBytes("123f", &serial));
  signer_info.serial_number = ByteStringFromString(serial);
  matching = GetSignerCertificates(test_stack_, signer_info);
  EXPECT_THAT(matching, ElementsAre());
}

TEST_F(CertificateTest, GetBySki) {
  SignerInfo signer_info;
  std::string ski;
  CHECK(
      absl::HexStringToBytes("9B6EAE67945D61FB736371448CE0F2ECBA43CBA0", &ski));
  signer_info.subject_key_identifier = ByteStringFromString(ski);
  std::vector<X509*> matching = GetSignerCertificates(test_stack_, signer_info);
  EXPECT_THAT(matching, ElementsAre(user1_ecc_.get()));
}

TEST_F(CertificateTest, RFCSkiExample) {
  // The RFC 4134 4.7 example uses the Subject Key Id to match the signer's
  // certificate.
  std::string cms = GetCms(GetFileContents("rfc4134-4.7.msg"));
  Content contents;
  std::string error_message;
  ASSERT_EQ(ErrorCode::OK,
            ParseCms(cms.data(), cms.length(), &contents, &error_message))
      << error_message;
  bssl::UniquePtr<STACK_OF(X509)> certs(GetAllCertificates(contents));
  ASSERT_EQ(1, sk_X509_num(certs.get()));
  ASSERT_EQ(1, contents.signers.size());

  std::vector<X509*> matching =
      GetSignerCertificates(certs.get(), contents.signers[0]);
  EXPECT_THAT(matching, ElementsAre(sk_X509_value(certs.get(), 0)));
}

TEST_F(CertificateTest, GetAllCertificatesWithEmptyCert) {
  // Zero out the 2nd certificate in the stack.
  CBS_init(content_.certificates[1].cbs_ptr(), nullptr, 0);
  bssl::UniquePtr<STACK_OF(X509)> stack(GetAllCertificates(content_));
  ASSERT_TRUE(stack == nullptr);
}

TEST_F(CertificateTest, GetAllCertificatesWithBrokenCert) {
  // A valid X509 certificate should start with a 0x30 (Constructed Sequence)
  // tag.
  uint8_t kBrokenCert[] = {0xFF};
  // Make the second certificate in the stack broken.
  CBS_init(content_.certificates[1].cbs_ptr(), kBrokenCert,
           sizeof(kBrokenCert));
  bssl::UniquePtr<STACK_OF(X509)> stack(GetAllCertificates(content_));
  ASSERT_TRUE(stack == nullptr);
}

}  // namespace
}  // namespace credentio_cms
