current commit
261104.8 · crypto: add X509Certificate inspection getters
#ifndef SRC_CRYPTO_CRYPTO_X509_H_
#define SRC_CRYPTO_CRYPTO_X509_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "base_object.h"
#include "crypto/crypto_util.h"
#include "env.h"
#include "memory_tracker.h"
#include "ncrypto.h"
#include "node_worker.h"
#include "v8.h"

#include <memory>
#include <optional>
#include <vector>

namespace node {
namespace crypto {

// ManagedX509 owns one isolate-local X509. Adopt makes the ownership transfer
// explicit at each call site.
class ManagedX509 final : public MemoryRetainer {
 public:
  static std::shared_ptr<ManagedX509> Adopt(ncrypto::X509Pointer cert);

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

  inline operator bool() const { return !!cert_; }
  inline X509* get() { return cert_.get(); }
  inline ncrypto::X509View view() const { return cert_; }
  inline operator ncrypto::X509View() const { return cert_; }

  void MemoryInfo(MemoryTracker* tracker) const override;
  SET_MEMORY_INFO_NAME(ManagedX509)
  SET_SELF_SIZE(ManagedX509)

 private:
  explicit ManagedX509(ncrypto::X509Pointer cert);

  ncrypto::X509Pointer cert_;
};

// An immutable certificate-encoding snapshot. Certificate zero is the leaf and
// all remaining certificates follow in the supplied order. Sharing this
// snapshot between isolates is safe; the isolate-local X509 objects are always
// reparsed from it.
class X509CertificateSnapshot final : public MemoryRetainer {
 public:
  using DER = std::vector<unsigned char>;

  static std::shared_ptr<const X509CertificateSnapshot> Create(
      ncrypto::X509View leaf,
      const STACK_OF(X509) * issuer_chain = nullptr,
      OPENSSL_SIZE_T issuers_start = 0);
  static std::shared_ptr<const X509CertificateSnapshot> Create(
      std::vector<DER> certificates);

  ncrypto::X509Pointer Parse(size_t index) const;

  inline size_t size() const { return certificates_.size(); }
  inline const DER& at(size_t index) const { return certificates_.at(index); }
  size_t size_bytes() const;

  void MemoryInfo(MemoryTracker* tracker) const override;
  SET_MEMORY_INFO_NAME(X509CertificateSnapshot)
  SET_SELF_SIZE(X509CertificateSnapshot)

 private:
  explicit X509CertificateSnapshot(std::vector<DER> certificates);

  const std::vector<DER> certificates_;
};

class X509Certificate final : public BaseObject {
 public:
  enum class GetPeerCertificateFlag {
    NONE,
    SERVER
  };

  static void Initialize(Environment* env, v8::Local<v8::Object> target);
  static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
  static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
      Environment* env);
  static bool HasInstance(Environment* env, v8::Local<v8::Value> value);

  static void CreateX509CertificateClass(
      const v8::FunctionCallbackInfo<v8::Value>& args);
  static void IsX509Certificate(
      const v8::FunctionCallbackInfo<v8::Value>& args);
  static void NewFromHandle(const v8::FunctionCallbackInfo<v8::Value>& args);
  static void ParseSnapshot(const v8::FunctionCallbackInfo<v8::Value>& args);
  static void GetSnapshot(const v8::FunctionCallbackInfo<v8::Value>& args);

  static v8::MaybeLocal<v8::Object> New(
      Environment* env,
      ncrypto::X509Pointer cert,
      const STACK_OF(X509) * issuer_chain = nullptr,
      OPENSSL_SIZE_T issuers_start = 0);

  static v8::MaybeLocal<v8::Object> New(
      Environment* env,
      std::shared_ptr<ManagedX509> cert,
      std::shared_ptr<const X509CertificateSnapshot> snapshot,
      size_t snapshot_index = 0);

  static v8::MaybeLocal<v8::Object> New(
      Environment* env,
      std::shared_ptr<const X509CertificateSnapshot> snapshot,
      size_t snapshot_index = 0);

  static v8::MaybeLocal<v8::Object> GetCert(Environment* env,
                                            const ncrypto::SSLPointer& ssl);

  static v8::MaybeLocal<v8::Object> GetPeerCert(Environment* env,
                                                const ncrypto::SSLPointer& ssl,
                                                GetPeerCertificateFlag flag);

  static v8::Local<v8::Object> Wrap(Environment* env,
                                    v8::Local<v8::Object> object,
                                    ncrypto::X509Pointer cert);

  inline BaseObjectPtr<X509Certificate> getIssuerCert() const {
    return issuer_cert_;
  }

  inline ncrypto::X509View view() const { return *cert_; }
  inline X509* get() { return cert_->get(); }
  inline const X509CertificateSnapshot::DER& snapshot_der() const {
    return snapshot_->at(snapshot_index_);
  }

  v8::MaybeLocal<v8::Value> toObject(Environment* env);
  static v8::MaybeLocal<v8::Value> toObject(Environment* env,
                                            const ncrypto::X509View& cert);

  void MemoryInfo(MemoryTracker* tracker) const override;
  SET_MEMORY_INFO_NAME(X509Certificate)
  SET_SELF_SIZE(X509Certificate)

  class X509CertificateTransferData : public worker::TransferData {
   public:
    explicit X509CertificateTransferData(
        std::shared_ptr<const X509CertificateSnapshot> snapshot,
        size_t snapshot_index)
        : snapshot_(std::move(snapshot)), snapshot_index_(snapshot_index) {}

    BaseObjectPtr<BaseObject> Deserialize(
        Environment* env,
        v8::Local<v8::Context> context,
        std::unique_ptr<worker::TransferData> self) override;

    void MemoryInfo(MemoryTracker* tracker) const override;
    SET_MEMORY_INFO_NAME(X509CertificateTransferData)
    SET_SELF_SIZE(X509CertificateTransferData)

   private:
    std::shared_ptr<const X509CertificateSnapshot> snapshot_;
    size_t snapshot_index_;
  };

  BaseObject::TransferMode GetTransferMode() const override;
  std::unique_ptr<worker::TransferData> CloneForMessaging() const override;

 private:
  X509Certificate(Environment* env,
                  v8::Local<v8::Object> object,
                  std::shared_ptr<ManagedX509> cert,
                  std::shared_ptr<const X509CertificateSnapshot> snapshot,
                  size_t snapshot_index,
                  v8::Local<v8::Object> issuer_chain = v8::Local<v8::Object>());

  std::shared_ptr<ManagedX509> cert_;
  std::shared_ptr<const X509CertificateSnapshot> snapshot_;
  size_t snapshot_index_ = 0;
  BaseObjectPtr<X509Certificate> issuer_cert_;
};

inline X509Certificate::GetPeerCertificateFlag operator|(
    X509Certificate::GetPeerCertificateFlag lhs,
    X509Certificate::GetPeerCertificateFlag rhs) {
  return static_cast<X509Certificate::GetPeerCertificateFlag>(
      static_cast<int>(lhs) | static_cast<int>(rhs));
}

inline X509Certificate::GetPeerCertificateFlag operator&(
    X509Certificate::GetPeerCertificateFlag lhs,
    X509Certificate::GetPeerCertificateFlag rhs) {
  return static_cast<X509Certificate::GetPeerCertificateFlag>(
      static_cast<int>(lhs) & static_cast<int>(rhs));
}

}  // namespace crypto
}  // namespace node

#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif  // SRC_CRYPTO_CRYPTO_X509_H_