// 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 <cstring>
#include <vector>

#include "crypto/default/cms/cms_parser.h"
#include "openssl/asn1.h"
#include "openssl/base.h"
#include "openssl/bytestring.h"
#include "openssl/obj_mac.h"
#include "openssl/safestack.h"
#include "openssl/stack.h"
#include "openssl/x509.h"

namespace credentio_cms {
namespace {

std::vector<X509*> MatchByIssuerNameAndSerialNumber(
    const STACK_OF(X509) * certificates, const ByteString& issuer_name,
    const ByteString& serial_number) {
  std::vector<X509*> matches;
  if (CBS_data(issuer_name.cbs_ptr()) == nullptr ||
      CBS_data(serial_number.cbs_ptr()) == nullptr ||
      CBS_len(issuer_name.cbs_ptr()) == 0 ||
      CBS_len(serial_number.cbs_ptr()) == 0) {
    return matches;
  }
  const unsigned char* p = CBS_data(issuer_name.cbs_ptr());
  bssl::UniquePtr<X509_NAME> x509_issuer_name(
      d2i_X509_NAME(nullptr, &p, CBS_len(issuer_name.cbs_ptr())));
  p = CBS_data(serial_number.cbs_ptr());
  bssl::UniquePtr<ASN1_INTEGER> x509_serial_number(
      c2i_ASN1_INTEGER(nullptr, &p, CBS_len(serial_number.cbs_ptr())));
  if (x509_issuer_name == nullptr || x509_serial_number == nullptr) {
    return matches;
  }
  for (int i = 0; i < sk_X509_num(certificates); ++i) {
    X509* cert = sk_X509_value(certificates, i);
    if (cert == nullptr) {
      continue;
    }
    const ASN1_INTEGER* certificate_serial = X509_get0_serialNumber(cert);
    if (certificate_serial == nullptr ||
        ASN1_INTEGER_cmp(x509_serial_number.get(), certificate_serial) != 0) {
      continue;
    }
    if (X509_name_cmp(x509_issuer_name.get(), X509_get_issuer_name(cert)) ==
        0) {
      matches.push_back(cert);
    }
  }
  return matches;
}

std::vector<X509*> MatchBySubjectKeyId(
    const STACK_OF(X509) * certificates,
    const ByteString& subject_key_identifier) {
  std::vector<X509*> matches;
  for (int i = 0; i < sk_X509_num(certificates); ++i) {
    X509* cert = sk_X509_value(certificates, i);
    if (cert == nullptr) {
      continue;
    }
    int index = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1);
    if (index < 0) {
      continue;
    }
    const X509_EXTENSION* ext = X509_get_ext(cert, index);
    if (ext == nullptr) {
      continue;
    }
    const ASN1_OCTET_STRING* value = X509_EXTENSION_get_data(ext);
    // https://tools.ietf.org/html/rfc5280#section-4.2.1.2
    CBS extension;
    CBS_init(&extension, ASN1_STRING_get0_data(value),
             ASN1_STRING_length(value));
    CBS ext_ski;
    if (CBS_get_asn1(&extension, &ext_ski, CBS_ASN1_OCTETSTRING) == 1 &&
        CBS_len(&ext_ski) == CBS_len(subject_key_identifier.cbs_ptr()) &&
        memcmp(CBS_data(subject_key_identifier.cbs_ptr()), CBS_data(&ext_ski),
               CBS_len(&ext_ski)) == 0) {
      matches.push_back(cert);
    }
  }
  return matches;
}

}  // namespace

STACK_OF(X509) * GetAllCertificates(const Content& cms_content) {
  bssl::UniquePtr<STACK_OF(X509)> stack(sk_X509_new_null());
  for (const auto& certificate : cms_content.certificates) {
    // Return null if there is an error parsing any certificate instead of
    // returning partial results.
    const unsigned char* udata = CBS_data(certificate.cbs_ptr());
    if (udata == nullptr || CBS_len(certificate.cbs_ptr()) == 0) {
      return nullptr;
    }
    X509* cert =
        d2i_X509(nullptr /* unused */, &udata, CBS_len(certificate.cbs_ptr()));
    if (cert == nullptr) {
      return nullptr;
    }
    sk_X509_push(stack.get(), cert);
  }
  return stack.release();
}

std::vector<X509*> GetSignerCertificates(const STACK_OF(X509) * certificates,
                                         const SignerInfo& signer) {
  if (CBS_len(signer.subject_key_identifier.cbs_ptr()) > 0) {
    return MatchBySubjectKeyId(certificates, signer.subject_key_identifier);
  } else {
    return MatchByIssuerNameAndSerialNumber(certificates, signer.issuer_name,
                                            signer.serial_number);
  }
}

}  // namespace credentio_cms
