src: move some X509Certificate stuff to ncrypto
PR-URL: https://github.com/nodejs/node/pull/54241 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
624db50952
commit
5f230d2cf4
2
deps/ncrypto/engine.cc
vendored
2
deps/ncrypto/engine.cc
vendored
@ -58,7 +58,7 @@ EnginePointer EnginePointer::getEngineByName(const std::string_view name,
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::move(engine);
|
||||
return engine;
|
||||
}
|
||||
|
||||
bool EnginePointer::setAsDefault(uint32_t flags, CryptoErrorList* errors) {
|
||||
|
229
deps/ncrypto/ncrypto.cc
vendored
229
deps/ncrypto/ncrypto.cc
vendored
@ -1,12 +1,12 @@
|
||||
#include "ncrypto.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "openssl/bn.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/pkcs12.h"
|
||||
#include "openssl/x509v3.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
#include "openssl/provider.h"
|
||||
#include <openssl/provider.h>
|
||||
#endif
|
||||
|
||||
namespace ncrypto {
|
||||
@ -703,4 +703,223 @@ bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// X509Pointer
|
||||
|
||||
X509Pointer::X509Pointer(X509* x509) : cert_(x509) {}
|
||||
|
||||
X509Pointer::X509Pointer(X509Pointer&& other) noexcept
|
||||
: cert_(other.release()) {}
|
||||
|
||||
X509Pointer& X509Pointer::operator=(X509Pointer&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
this->~X509Pointer();
|
||||
return *new (this) X509Pointer(std::move(other));
|
||||
}
|
||||
|
||||
X509Pointer::~X509Pointer() { reset(); }
|
||||
|
||||
void X509Pointer::reset(X509* x509) {
|
||||
cert_.reset(x509);
|
||||
}
|
||||
|
||||
X509* X509Pointer::release() {
|
||||
return cert_.release();
|
||||
}
|
||||
|
||||
X509View X509Pointer::view() const {
|
||||
return X509View(cert_.get());
|
||||
}
|
||||
|
||||
BIOPointer X509View::toPEM() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
if (PEM_write_bio_X509(bio.get(), const_cast<X509*>(cert_)) <= 0) return {};
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::toDER() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
if (i2d_X509_bio(bio.get(), const_cast<X509*>(cert_)) <= 0) return {};
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::getSubject() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
if (X509_NAME_print_ex(bio.get(), X509_get_subject_name(cert_),
|
||||
0, kX509NameFlagsMultiline) <= 0) {
|
||||
return {};
|
||||
}
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::getSubjectAltName() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
int index = X509_get_ext_by_NID(cert_, NID_subject_alt_name, -1);
|
||||
if (index < 0 || !SafeX509SubjectAltNamePrint(bio, X509_get_ext(cert_, index))) {
|
||||
return {};
|
||||
}
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::getIssuer() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
if (X509_NAME_print_ex(bio.get(), X509_get_issuer_name(cert_), 0,
|
||||
kX509NameFlagsMultiline) <= 0) {
|
||||
return {};
|
||||
}
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::getInfoAccess() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
int index = X509_get_ext_by_NID(cert_, NID_info_access, -1);
|
||||
if (index < 0) return {};
|
||||
if (!SafeX509InfoAccessPrint(bio, X509_get_ext(cert_, index))) {
|
||||
return {};
|
||||
}
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::getValidFrom() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
ASN1_TIME_print(bio.get(), X509_get_notBefore(cert_));
|
||||
return bio;
|
||||
}
|
||||
|
||||
BIOPointer X509View::getValidTo() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) return {};
|
||||
ASN1_TIME_print(bio.get(), X509_get_notAfter(cert_));
|
||||
return bio;
|
||||
}
|
||||
|
||||
DataPointer X509View::getSerialNumber() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
if (ASN1_INTEGER* serial_number = X509_get_serialNumber(const_cast<X509*>(cert_))) {
|
||||
if (auto bn = BignumPointer(ASN1_INTEGER_to_BN(serial_number, nullptr))) {
|
||||
return bn.toHex();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Result<EVPKeyPointer, int> X509View::getPublicKey() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return Result<EVPKeyPointer, int>(EVPKeyPointer {});
|
||||
auto pkey = EVPKeyPointer(X509_get_pubkey(const_cast<X509*>(cert_)));
|
||||
if (!pkey) return Result<EVPKeyPointer, int>(ERR_get_error());
|
||||
return pkey;
|
||||
}
|
||||
|
||||
StackOfASN1 X509View::getKeyUsage() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return {};
|
||||
return StackOfASN1(static_cast<STACK_OF(ASN1_OBJECT)*>(
|
||||
X509_get_ext_d2i(cert_, NID_ext_key_usage, nullptr, nullptr)));
|
||||
}
|
||||
|
||||
bool X509View::isCA() const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return false;
|
||||
return X509_check_ca(const_cast<X509*>(cert_)) == 1;
|
||||
}
|
||||
|
||||
bool X509View::isIssuedBy(const X509View& issuer) const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr || issuer.cert_ == nullptr) return false;
|
||||
return X509_check_issued(const_cast<X509*>(issuer.cert_),
|
||||
const_cast<X509*>(cert_)) == X509_V_OK;
|
||||
}
|
||||
|
||||
bool X509View::checkPrivateKey(const EVPKeyPointer& pkey) const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr || pkey == nullptr) return false;
|
||||
return X509_check_private_key(const_cast<X509*>(cert_), pkey.get()) == 1;
|
||||
}
|
||||
|
||||
bool X509View::checkPublicKey(const EVPKeyPointer& pkey) const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr || pkey == nullptr) return false;
|
||||
return X509_verify(const_cast<X509*>(cert_), pkey.get()) == 1;
|
||||
}
|
||||
|
||||
X509View::CheckMatch X509View::checkHost(const std::string_view host, int flags,
|
||||
DataPointer* peerName) const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return CheckMatch::NO_MATCH;
|
||||
char* peername;
|
||||
switch (X509_check_host(const_cast<X509*>(cert_), host.data(), host.size(), flags, &peername)) {
|
||||
case 0: return CheckMatch::NO_MATCH;
|
||||
case 1: {
|
||||
if (peername != nullptr) {
|
||||
DataPointer name(peername, strlen(peername));
|
||||
if (peerName != nullptr) *peerName = std::move(name);
|
||||
}
|
||||
return CheckMatch::MATCH;
|
||||
}
|
||||
case -2: return CheckMatch::INVALID_NAME;
|
||||
default: return CheckMatch::OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
X509View::CheckMatch X509View::checkEmail(const std::string_view email, int flags) const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return CheckMatch::NO_MATCH;
|
||||
switch (X509_check_email(const_cast<X509*>(cert_), email.data(), email.size(), flags)) {
|
||||
case 0: return CheckMatch::NO_MATCH;
|
||||
case 1: return CheckMatch::MATCH;
|
||||
case -2: return CheckMatch::INVALID_NAME;
|
||||
default: return CheckMatch::OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
X509View::CheckMatch X509View::checkIp(const std::string_view ip, int flags) const {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
if (cert_ == nullptr) return CheckMatch::NO_MATCH;
|
||||
switch (X509_check_ip_asc(const_cast<X509*>(cert_), ip.data(), flags)) {
|
||||
case 0: return CheckMatch::NO_MATCH;
|
||||
case 1: return CheckMatch::MATCH;
|
||||
case -2: return CheckMatch::INVALID_NAME;
|
||||
default: return CheckMatch::OPERATION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
Result<X509Pointer, int> X509Pointer::Parse(Buffer<const unsigned char> buffer) {
|
||||
ClearErrorOnReturn clearErrorOnReturn;
|
||||
BIOPointer bio(BIO_new_mem_buf(buffer.data, buffer.len));
|
||||
if (!bio) return Result<X509Pointer, int>(ERR_get_error());
|
||||
|
||||
X509Pointer pem(PEM_read_bio_X509_AUX(bio.get(), nullptr, NoPasswordCallback, nullptr));
|
||||
if (pem) return Result<X509Pointer, int>(std::move(pem));
|
||||
BIO_reset(bio.get());
|
||||
|
||||
X509Pointer der(d2i_X509_bio(bio.get(), nullptr));
|
||||
if (der) return Result<X509Pointer, int>(std::move(der));
|
||||
|
||||
return Result<X509Pointer, int>(ERR_get_error());
|
||||
}
|
||||
} // namespace ncrypto
|
||||
|
93
deps/ncrypto/ncrypto.h
vendored
93
deps/ncrypto/ncrypto.h
vendored
@ -6,7 +6,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include "openssl/bn.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/dsa.h>
|
||||
@ -91,6 +91,13 @@ namespace ncrypto {
|
||||
#endif
|
||||
}
|
||||
|
||||
static constexpr int kX509NameFlagsMultiline =
|
||||
ASN1_STRFLGS_ESC_2253 |
|
||||
ASN1_STRFLGS_ESC_CTRL |
|
||||
ASN1_STRFLGS_UTF8_CONVERT |
|
||||
XN_FLAG_SEP_MULTILINE |
|
||||
XN_FLAG_FN_SN;
|
||||
|
||||
// ============================================================================
|
||||
// Error handling utilities
|
||||
|
||||
@ -164,6 +171,14 @@ private:
|
||||
CryptoErrorList* errors_;
|
||||
};
|
||||
|
||||
template <typename T, typename E>
|
||||
struct Result final {
|
||||
T value;
|
||||
std::optional<E> error;
|
||||
Result(T&& value) : value(std::move(value)) {}
|
||||
Result(E&& error) : error(std::move(error)) {}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Various smart pointer aliases for OpenSSL types.
|
||||
|
||||
@ -197,7 +212,13 @@ using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
||||
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
|
||||
using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
|
||||
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
|
||||
using X509Pointer = DeleteFnPtr<X509, X509_free>;
|
||||
|
||||
struct StackOfXASN1Deleter {
|
||||
void operator()(STACK_OF(ASN1_OBJECT)* p) const {
|
||||
sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free);
|
||||
}
|
||||
};
|
||||
using StackOfASN1 = std::unique_ptr<STACK_OF(ASN1_OBJECT), StackOfXASN1Deleter>;
|
||||
|
||||
// An unowned, unmanaged pointer to a buffer of data.
|
||||
template <typename T>
|
||||
@ -290,6 +311,74 @@ class BignumPointer final {
|
||||
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
|
||||
};
|
||||
|
||||
class X509View final {
|
||||
public:
|
||||
X509View() = default;
|
||||
inline explicit X509View(const X509* cert) : cert_(cert) {}
|
||||
X509View(const X509View& other) = default;
|
||||
X509View& operator=(const X509View& other) = default;
|
||||
NCRYPTO_DISALLOW_MOVE(X509View)
|
||||
|
||||
inline bool operator==(std::nullptr_t) noexcept { return cert_ == nullptr; }
|
||||
inline operator bool() const { return cert_ != nullptr; }
|
||||
|
||||
BIOPointer toPEM() const;
|
||||
BIOPointer toDER() const;
|
||||
|
||||
BIOPointer getSubject() const;
|
||||
BIOPointer getSubjectAltName() const;
|
||||
BIOPointer getIssuer() const;
|
||||
BIOPointer getInfoAccess() const;
|
||||
BIOPointer getValidFrom() const;
|
||||
BIOPointer getValidTo() const;
|
||||
DataPointer getSerialNumber() const;
|
||||
Result<EVPKeyPointer, int> getPublicKey() const;
|
||||
StackOfASN1 getKeyUsage() const;
|
||||
|
||||
bool isCA() const;
|
||||
bool isIssuedBy(const X509View& other) const;
|
||||
bool checkPrivateKey(const EVPKeyPointer& pkey) const;
|
||||
bool checkPublicKey(const EVPKeyPointer& pkey) const;
|
||||
|
||||
enum class CheckMatch {
|
||||
NO_MATCH,
|
||||
MATCH,
|
||||
INVALID_NAME,
|
||||
OPERATION_FAILED,
|
||||
};
|
||||
CheckMatch checkHost(const std::string_view host, int flags,
|
||||
DataPointer* peerName = nullptr) const;
|
||||
CheckMatch checkEmail(const std::string_view email, int flags) const;
|
||||
CheckMatch checkIp(const std::string_view ip, int flags) const;
|
||||
|
||||
private:
|
||||
const X509* cert_ = nullptr;
|
||||
};
|
||||
|
||||
class X509Pointer final {
|
||||
public:
|
||||
static Result<X509Pointer, int> Parse(Buffer<const unsigned char> buffer);
|
||||
|
||||
X509Pointer() = default;
|
||||
explicit X509Pointer(X509* cert);
|
||||
X509Pointer(X509Pointer&& other) noexcept;
|
||||
X509Pointer& operator=(X509Pointer&& other) noexcept;
|
||||
NCRYPTO_DISALLOW_COPY(X509Pointer)
|
||||
~X509Pointer();
|
||||
|
||||
inline bool operator==(std::nullptr_t) noexcept { return cert_ == nullptr; }
|
||||
inline operator bool() const { return cert_ != nullptr; }
|
||||
inline X509* get() const { return cert_.get(); }
|
||||
void reset(X509* cert = nullptr);
|
||||
X509* release();
|
||||
|
||||
X509View view() const;
|
||||
operator X509View() const { return view(); }
|
||||
|
||||
private:
|
||||
DeleteFnPtr<X509, X509_free> cert_;
|
||||
};
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
class EnginePointer final {
|
||||
public:
|
||||
|
@ -3,10 +3,11 @@
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "node_crypto.h"
|
||||
#include "v8.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include "ncrypto.h"
|
||||
#include "node_crypto.h"
|
||||
#include "v8.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -26,12 +27,7 @@ struct StackOfX509Deleter {
|
||||
};
|
||||
using StackOfX509 = std::unique_ptr<STACK_OF(X509), StackOfX509Deleter>;
|
||||
|
||||
struct StackOfXASN1Deleter {
|
||||
void operator()(STACK_OF(ASN1_OBJECT)* p) const {
|
||||
sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free);
|
||||
}
|
||||
};
|
||||
using StackOfASN1 = std::unique_ptr<STACK_OF(ASN1_OBJECT), StackOfXASN1Deleter>;
|
||||
using StackOfASN1 = ncrypto::StackOfASN1;
|
||||
|
||||
X509Pointer SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert);
|
||||
|
||||
|
@ -82,6 +82,7 @@ class ManagedEVPPKey : public MemoryRetainer {
|
||||
|
||||
operator bool() const;
|
||||
EVP_PKEY* get() const;
|
||||
inline const EVPKeyPointer& pkey() const { return pkey_; }
|
||||
Mutex* mutex() const;
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
|
@ -1,11 +1,12 @@
|
||||
#include "base_object-inl.h"
|
||||
#include "crypto_x509.h"
|
||||
#include "base_object-inl.h"
|
||||
#include "crypto_bio.h"
|
||||
#include "crypto_common.h"
|
||||
#include "crypto_context.h"
|
||||
#include "crypto_keys.h"
|
||||
#include "crypto_bio.h"
|
||||
#include "env-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "ncrypto.h"
|
||||
#include "node_errors.h"
|
||||
#include "util-inl.h"
|
||||
#include "v8.h"
|
||||
@ -15,6 +16,8 @@
|
||||
|
||||
namespace node {
|
||||
|
||||
using v8::Array;
|
||||
using v8::ArrayBuffer;
|
||||
using v8::ArrayBufferView;
|
||||
using v8::Context;
|
||||
using v8::EscapableHandleScope;
|
||||
@ -24,7 +27,9 @@ using v8::FunctionTemplate;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
using v8::MaybeLocal;
|
||||
using v8::NewStringType;
|
||||
using v8::Object;
|
||||
using v8::String;
|
||||
using v8::Uint32;
|
||||
using v8::Value;
|
||||
|
||||
@ -58,8 +63,330 @@ void Fingerprint(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (GetFingerprintDigest(env, algo(), cert->get()).ToLocal(&ret))
|
||||
if (GetFingerprintDigest(env, algo(), cert->get()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
MaybeLocal<Value> ToV8Value(Local<Context> context, BIOPointer&& bio) {
|
||||
if (!bio) return {};
|
||||
BUF_MEM* mem;
|
||||
BIO_get_mem_ptr(bio.get(), &mem);
|
||||
Local<Value> ret;
|
||||
if (!String::NewFromUtf8(context->GetIsolate(),
|
||||
mem->data,
|
||||
NewStringType::kNormal,
|
||||
mem->length)
|
||||
.ToLocal(&ret))
|
||||
return {};
|
||||
return ret;
|
||||
}
|
||||
|
||||
MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer&& bio) {
|
||||
if (!bio) return {};
|
||||
BUF_MEM* mem;
|
||||
BIO_get_mem_ptr(bio.get(), &mem);
|
||||
auto backing = ArrayBuffer::NewBackingStore(
|
||||
mem->data,
|
||||
mem->length,
|
||||
[](void*, size_t, void* data) {
|
||||
BIOPointer free_me(static_cast<BIO*>(data));
|
||||
},
|
||||
bio.release());
|
||||
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
|
||||
Local<Value> ret;
|
||||
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {};
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Pem(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().toPEM()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void Der(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToBuffer(env, cert->view().toDER()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void Subject(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().getSubject()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void SubjectAltName(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().getSubjectAltName())
|
||||
.ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void Issuer(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().getIssuer()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void InfoAccess(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().getInfoAccess()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void ValidFrom(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().getValidFrom()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void ValidTo(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
Local<Value> ret;
|
||||
if (ToV8Value(env->context(), cert->view().getValidTo()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void SerialNumber(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
if (auto serial = cert->view().getSerialNumber()) {
|
||||
args.GetReturnValue().Set(OneByteString(
|
||||
env->isolate(), static_cast<unsigned char*>(serial.get())));
|
||||
}
|
||||
}
|
||||
|
||||
void PublicKey(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
// TODO(tniessen): consider checking X509_get_pubkey() when the
|
||||
// X509Certificate object is being created.
|
||||
auto result = cert->view().getPublicKey();
|
||||
if (!result.value) {
|
||||
ThrowCryptoError(env, result.error.value_or(0));
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<KeyObjectData> key_data = KeyObjectData::CreateAsymmetric(
|
||||
kKeyTypePublic, ManagedEVPPKey(std::move(result.value)));
|
||||
|
||||
Local<Value> ret;
|
||||
if (KeyObjectHandle::Create(env, std::move(key_data)).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyUsage(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
auto eku = cert->view().getKeyUsage();
|
||||
if (!eku) return;
|
||||
|
||||
const int count = sk_ASN1_OBJECT_num(eku.get());
|
||||
MaybeStackBuffer<Local<Value>, 16> ext_key_usage(count);
|
||||
char buf[256];
|
||||
|
||||
int j = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (OBJ_obj2txt(buf, sizeof(buf), sk_ASN1_OBJECT_value(eku.get(), i), 1) >=
|
||||
0) {
|
||||
ext_key_usage[j++] = OneByteString(env->isolate(), buf);
|
||||
}
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
Array::New(env->isolate(), ext_key_usage.out(), count));
|
||||
}
|
||||
|
||||
void CheckCA(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
args.GetReturnValue().Set(cert->view().isCA());
|
||||
}
|
||||
|
||||
void CheckIssued(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
CHECK(args[0]->IsObject());
|
||||
CHECK(X509Certificate::HasInstance(env, args[0].As<Object>()));
|
||||
X509Certificate* issuer;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&issuer, args[0]);
|
||||
args.GetReturnValue().Set(cert->view().isIssuedBy(issuer->view()));
|
||||
}
|
||||
|
||||
void CheckPrivateKey(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
CHECK(args[0]->IsObject());
|
||||
KeyObjectHandle* key;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&key, args[0]);
|
||||
CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate);
|
||||
args.GetReturnValue().Set(
|
||||
cert->view().checkPrivateKey(key->Data()->GetAsymmetricKey().pkey()));
|
||||
}
|
||||
|
||||
void CheckPublicKey(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsObject());
|
||||
KeyObjectHandle* key;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&key, args[0]);
|
||||
CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePublic);
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
cert->view().checkPublicKey(key->Data()->GetAsymmetricKey().pkey()));
|
||||
}
|
||||
|
||||
void CheckHost(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsString()); // name
|
||||
CHECK(args[1]->IsUint32()); // flags
|
||||
|
||||
Utf8Value name(env->isolate(), args[0]);
|
||||
uint32_t flags = args[1].As<Uint32>()->Value();
|
||||
ncrypto::DataPointer peername;
|
||||
|
||||
switch (cert->view().checkHost(name.ToStringView(), flags, &peername)) {
|
||||
case ncrypto::X509View::CheckMatch::MATCH: { // Match!
|
||||
Local<Value> ret = args[0];
|
||||
if (peername) {
|
||||
ret = OneByteString(env->isolate(),
|
||||
static_cast<const char*>(peername.get()),
|
||||
peername.size());
|
||||
}
|
||||
return args.GetReturnValue().Set(ret);
|
||||
}
|
||||
case ncrypto::X509View::CheckMatch::NO_MATCH: // No Match!
|
||||
return; // No return value is set
|
||||
case ncrypto::X509View::CheckMatch::INVALID_NAME: // Error!
|
||||
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid name");
|
||||
default: // Error!
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckEmail(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsString()); // name
|
||||
CHECK(args[1]->IsUint32()); // flags
|
||||
|
||||
Utf8Value name(env->isolate(), args[0]);
|
||||
uint32_t flags = args[1].As<Uint32>()->Value();
|
||||
|
||||
switch (cert->view().checkEmail(name.ToStringView(), flags)) {
|
||||
case ncrypto::X509View::CheckMatch::MATCH: // Match!
|
||||
return args.GetReturnValue().Set(args[0]);
|
||||
case ncrypto::X509View::CheckMatch::NO_MATCH: // No Match!
|
||||
return; // No return value is set
|
||||
case ncrypto::X509View::CheckMatch::INVALID_NAME: // Error!
|
||||
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid name");
|
||||
default: // Error!
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckIP(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsString()); // IP
|
||||
CHECK(args[1]->IsUint32()); // flags
|
||||
|
||||
Utf8Value name(env->isolate(), args[0]);
|
||||
uint32_t flags = args[1].As<Uint32>()->Value();
|
||||
|
||||
switch (cert->view().checkIp(name.ToStringView(), flags)) {
|
||||
case ncrypto::X509View::CheckMatch::MATCH: // Match!
|
||||
return args.GetReturnValue().Set(args[0]);
|
||||
case ncrypto::X509View::CheckMatch::NO_MATCH: // No Match!
|
||||
return; // No return value is set
|
||||
case ncrypto::X509View::CheckMatch::INVALID_NAME: // Error!
|
||||
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP");
|
||||
default: // Error!
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
|
||||
}
|
||||
}
|
||||
|
||||
void GetIssuerCert(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
auto issuer = cert->getIssuerCert();
|
||||
if (issuer) args.GetReturnValue().Set(issuer->object());
|
||||
}
|
||||
|
||||
void Parse(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
CHECK(args[0]->IsArrayBufferView());
|
||||
ArrayBufferViewContents<unsigned char> buf(args[0].As<ArrayBufferView>());
|
||||
Local<Object> cert;
|
||||
|
||||
auto result = X509Pointer::Parse(ncrypto::Buffer<const unsigned char>{
|
||||
.data = buf.data(),
|
||||
.len = buf.length(),
|
||||
});
|
||||
|
||||
if (!result.value) return ThrowCryptoError(env, result.error.value_or(0));
|
||||
|
||||
if (X509Certificate::New(env, std::move(result.value)).ToLocal(&cert)) {
|
||||
args.GetReturnValue().Set(cert);
|
||||
}
|
||||
}
|
||||
|
||||
void ToLegacy(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
Local<Value> ret;
|
||||
if (X509ToObject(env, cert->get()).ToLocal(&ret)) {
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -85,7 +412,7 @@ Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
|
||||
SetProtoMethod(isolate, tmpl, "keyUsage", KeyUsage);
|
||||
SetProtoMethod(isolate, tmpl, "serialNumber", SerialNumber);
|
||||
SetProtoMethod(isolate, tmpl, "pem", Pem);
|
||||
SetProtoMethod(isolate, tmpl, "raw", Raw);
|
||||
SetProtoMethod(isolate, tmpl, "raw", Der);
|
||||
SetProtoMethod(isolate, tmpl, "publicKey", PublicKey);
|
||||
SetProtoMethod(isolate, tmpl, "checkCA", CheckCA);
|
||||
SetProtoMethod(isolate, tmpl, "checkHost", CheckHost);
|
||||
@ -93,7 +420,7 @@ Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
|
||||
SetProtoMethod(isolate, tmpl, "checkIP", CheckIP);
|
||||
SetProtoMethod(isolate, tmpl, "checkIssued", CheckIssued);
|
||||
SetProtoMethod(isolate, tmpl, "checkPrivateKey", CheckPrivateKey);
|
||||
SetProtoMethod(isolate, tmpl, "verify", Verify);
|
||||
SetProtoMethod(isolate, tmpl, "verify", CheckPublicKey);
|
||||
SetProtoMethod(isolate, tmpl, "toLegacy", ToLegacy);
|
||||
SetProtoMethod(isolate, tmpl, "getIssuerCert", GetIssuerCert);
|
||||
env->set_x509_constructor_template(tmpl);
|
||||
@ -105,18 +432,16 @@ bool X509Certificate::HasInstance(Environment* env, Local<Object> object) {
|
||||
return GetConstructorTemplate(env)->HasInstance(object);
|
||||
}
|
||||
|
||||
MaybeLocal<Object> X509Certificate::New(
|
||||
Environment* env,
|
||||
X509Pointer cert,
|
||||
STACK_OF(X509)* issuer_chain) {
|
||||
MaybeLocal<Object> X509Certificate::New(Environment* env,
|
||||
X509Pointer cert,
|
||||
STACK_OF(X509) * issuer_chain) {
|
||||
std::shared_ptr<ManagedX509> mcert(new ManagedX509(std::move(cert)));
|
||||
return New(env, std::move(mcert), issuer_chain);
|
||||
}
|
||||
|
||||
MaybeLocal<Object> X509Certificate::New(
|
||||
Environment* env,
|
||||
std::shared_ptr<ManagedX509> cert,
|
||||
STACK_OF(X509)* issuer_chain) {
|
||||
MaybeLocal<Object> X509Certificate::New(Environment* env,
|
||||
std::shared_ptr<ManagedX509> cert,
|
||||
STACK_OF(X509) * issuer_chain) {
|
||||
EscapableHandleScope scope(env->isolate());
|
||||
Local<Function> ctor;
|
||||
if (!GetConstructorTemplate(env)->GetFunction(env->context()).ToLocal(&ctor))
|
||||
@ -130,22 +455,19 @@ MaybeLocal<Object> X509Certificate::New(
|
||||
return scope.Escape(obj);
|
||||
}
|
||||
|
||||
MaybeLocal<Object> X509Certificate::GetCert(
|
||||
Environment* env,
|
||||
const SSLPointer& ssl) {
|
||||
MaybeLocal<Object> X509Certificate::GetCert(Environment* env,
|
||||
const SSLPointer& ssl) {
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
X509* cert = SSL_get_certificate(ssl.get());
|
||||
if (cert == nullptr)
|
||||
return MaybeLocal<Object>();
|
||||
if (cert == nullptr) return MaybeLocal<Object>();
|
||||
|
||||
X509Pointer ptr(X509_dup(cert));
|
||||
return New(env, std::move(ptr));
|
||||
}
|
||||
|
||||
MaybeLocal<Object> X509Certificate::GetPeerCert(
|
||||
Environment* env,
|
||||
const SSLPointer& ssl,
|
||||
GetPeerCertificateFlag flag) {
|
||||
MaybeLocal<Object> X509Certificate::GetPeerCert(Environment* env,
|
||||
const SSLPointer& ssl,
|
||||
GetPeerCertificateFlag flag) {
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
MaybeLocal<Object> maybe_cert;
|
||||
|
||||
@ -164,80 +486,8 @@ MaybeLocal<Object> X509Certificate::GetPeerCert(
|
||||
sk_X509_delete(ssl_certs, 0);
|
||||
}
|
||||
|
||||
return sk_X509_num(ssl_certs)
|
||||
? New(env, std::move(cert), ssl_certs)
|
||||
: New(env, std::move(cert));
|
||||
}
|
||||
|
||||
void X509Certificate::Parse(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
CHECK(args[0]->IsArrayBufferView());
|
||||
ArrayBufferViewContents<unsigned char> buf(args[0].As<ArrayBufferView>());
|
||||
const unsigned char* data = buf.data();
|
||||
unsigned data_len = buf.length();
|
||||
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
BIOPointer bio(LoadBIO(env, args[0]));
|
||||
if (!bio)
|
||||
return ThrowCryptoError(env, ERR_get_error());
|
||||
|
||||
Local<Object> cert;
|
||||
|
||||
X509Pointer pem(PEM_read_bio_X509_AUX(
|
||||
bio.get(), nullptr, NoPasswordCallback, nullptr));
|
||||
if (!pem) {
|
||||
// Try as DER, but return the original PEM failure if it isn't DER.
|
||||
MarkPopErrorOnReturn mark_here;
|
||||
|
||||
X509Pointer der(d2i_X509(nullptr, &data, data_len));
|
||||
if (!der)
|
||||
return ThrowCryptoError(env, ERR_get_error());
|
||||
|
||||
if (!X509Certificate::New(env, std::move(der)).ToLocal(&cert))
|
||||
return;
|
||||
} else if (!X509Certificate::New(env, std::move(pem)).ToLocal(&cert)) {
|
||||
return;
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(cert);
|
||||
}
|
||||
|
||||
template <MaybeLocal<Value> Property(
|
||||
Environment* env, X509* cert, const BIOPointer& bio)>
|
||||
static void ReturnPropertyThroughBIO(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
CHECK(bio);
|
||||
Local<Value> ret;
|
||||
if (Property(env, cert->get(), bio).ToLocal(&ret))
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
|
||||
void X509Certificate::Subject(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnPropertyThroughBIO<GetSubject>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::Issuer(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnPropertyThroughBIO<GetIssuerString>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::SubjectAltName(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnPropertyThroughBIO<GetSubjectAltNameString>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::InfoAccess(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnPropertyThroughBIO<GetInfoAccessString>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::ValidFrom(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnPropertyThroughBIO<GetValidFrom>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::ValidTo(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnPropertyThroughBIO<GetValidTo>(args);
|
||||
return sk_X509_num(ssl_certs) ? New(env, std::move(cert), ssl_certs)
|
||||
: New(env, std::move(cert));
|
||||
}
|
||||
|
||||
template <MaybeLocal<Value> Property(Environment* env, X509* cert)>
|
||||
@ -249,207 +499,6 @@ static void ReturnProperty(const FunctionCallbackInfo<Value>& args) {
|
||||
if (Property(env, cert->get()).ToLocal(&ret)) args.GetReturnValue().Set(ret);
|
||||
}
|
||||
|
||||
void X509Certificate::KeyUsage(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnProperty<GetKeyUsage>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::SerialNumber(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnProperty<GetSerialNumber>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::Raw(const FunctionCallbackInfo<Value>& args) {
|
||||
ReturnProperty<GetRawDERCertificate>(args);
|
||||
}
|
||||
|
||||
void X509Certificate::PublicKey(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
// TODO(tniessen): consider checking X509_get_pubkey() when the
|
||||
// X509Certificate object is being created.
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
EVPKeyPointer pkey(X509_get_pubkey(cert->get()));
|
||||
if (!pkey) return ThrowCryptoError(env, ERR_get_error());
|
||||
ManagedEVPPKey epkey(std::move(pkey));
|
||||
std::shared_ptr<KeyObjectData> key_data =
|
||||
KeyObjectData::CreateAsymmetric(kKeyTypePublic, epkey);
|
||||
|
||||
Local<Value> ret;
|
||||
if (KeyObjectHandle::Create(env, key_data).ToLocal(&ret))
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
|
||||
void X509Certificate::Pem(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
BIOPointer bio(BIO_new(BIO_s_mem()));
|
||||
CHECK(bio);
|
||||
if (PEM_write_bio_X509(bio.get(), cert->get()))
|
||||
args.GetReturnValue().Set(ToV8Value(env, bio));
|
||||
}
|
||||
|
||||
void X509Certificate::CheckCA(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
args.GetReturnValue().Set(X509_check_ca(cert->get()) == 1);
|
||||
}
|
||||
|
||||
void X509Certificate::CheckHost(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsString()); // name
|
||||
CHECK(args[1]->IsUint32()); // flags
|
||||
|
||||
Utf8Value name(env->isolate(), args[0]);
|
||||
uint32_t flags = args[1].As<Uint32>()->Value();
|
||||
char* peername;
|
||||
|
||||
switch (X509_check_host(
|
||||
cert->get(),
|
||||
*name,
|
||||
name.length(),
|
||||
flags,
|
||||
&peername)) {
|
||||
case 1: { // Match!
|
||||
Local<Value> ret = args[0];
|
||||
if (peername != nullptr) {
|
||||
ret = OneByteString(env->isolate(), peername);
|
||||
OPENSSL_free(peername);
|
||||
}
|
||||
return args.GetReturnValue().Set(ret);
|
||||
}
|
||||
case 0: // No Match!
|
||||
return; // No return value is set
|
||||
case -2: // Error!
|
||||
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid name");
|
||||
default: // Error!
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
|
||||
}
|
||||
}
|
||||
|
||||
void X509Certificate::CheckEmail(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsString()); // name
|
||||
CHECK(args[1]->IsUint32()); // flags
|
||||
|
||||
Utf8Value name(env->isolate(), args[0]);
|
||||
uint32_t flags = args[1].As<Uint32>()->Value();
|
||||
|
||||
switch (X509_check_email(
|
||||
cert->get(),
|
||||
*name,
|
||||
name.length(),
|
||||
flags)) {
|
||||
case 1: // Match!
|
||||
return args.GetReturnValue().Set(args[0]);
|
||||
case 0: // No Match!
|
||||
return; // No return value is set
|
||||
case -2: // Error!
|
||||
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid name");
|
||||
default: // Error!
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
|
||||
}
|
||||
}
|
||||
|
||||
void X509Certificate::CheckIP(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsString()); // IP
|
||||
CHECK(args[1]->IsUint32()); // flags
|
||||
|
||||
Utf8Value name(env->isolate(), args[0]);
|
||||
uint32_t flags = args[1].As<Uint32>()->Value();
|
||||
|
||||
switch (X509_check_ip_asc(cert->get(), *name, flags)) {
|
||||
case 1: // Match!
|
||||
return args.GetReturnValue().Set(args[0]);
|
||||
case 0: // No Match!
|
||||
return; // No return value is set
|
||||
case -2: // Error!
|
||||
return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP");
|
||||
default: // Error!
|
||||
return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
|
||||
}
|
||||
}
|
||||
|
||||
void X509Certificate::CheckIssued(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsObject());
|
||||
CHECK(X509Certificate::HasInstance(env, args[0].As<Object>()));
|
||||
|
||||
X509Certificate* issuer;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&issuer, args[0]);
|
||||
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
X509_check_issued(issuer->get(), cert->get()) == X509_V_OK);
|
||||
}
|
||||
|
||||
void X509Certificate::CheckPrivateKey(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsObject());
|
||||
KeyObjectHandle* key;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&key, args[0]);
|
||||
CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate);
|
||||
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
X509_check_private_key(
|
||||
cert->get(),
|
||||
key->Data()->GetAsymmetricKey().get()) == 1);
|
||||
}
|
||||
|
||||
void X509Certificate::Verify(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
|
||||
CHECK(args[0]->IsObject());
|
||||
KeyObjectHandle* key;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&key, args[0]);
|
||||
CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePublic);
|
||||
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
X509_verify(
|
||||
cert->get(),
|
||||
key->Data()->GetAsymmetricKey().get()) > 0);
|
||||
}
|
||||
|
||||
void X509Certificate::ToLegacy(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
ClearErrorOnReturn clear_error_on_return;
|
||||
Local<Value> ret;
|
||||
if (X509ToObject(env, cert->get()).ToLocal(&ret))
|
||||
args.GetReturnValue().Set(ret);
|
||||
}
|
||||
|
||||
void X509Certificate::GetIssuerCert(const FunctionCallbackInfo<Value>& args) {
|
||||
X509Certificate* cert;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&cert, args.This());
|
||||
if (cert->issuer_cert_)
|
||||
args.GetReturnValue().Set(cert->issuer_cert_->object());
|
||||
}
|
||||
|
||||
X509Certificate::X509Certificate(
|
||||
Environment* env,
|
||||
Local<Object> object,
|
||||
@ -504,7 +553,7 @@ std::unique_ptr<worker::TransferData> X509Certificate::CloneForMessaging()
|
||||
|
||||
|
||||
void X509Certificate::Initialize(Environment* env, Local<Object> target) {
|
||||
SetMethod(env->context(), target, "parseX509", X509Certificate::Parse);
|
||||
SetMethod(env->context(), target, "parseX509", Parse);
|
||||
|
||||
NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT);
|
||||
NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NEVER_CHECK_SUBJECT);
|
||||
@ -516,7 +565,7 @@ void X509Certificate::Initialize(Environment* env, Local<Object> target) {
|
||||
|
||||
void X509Certificate::RegisterExternalReferences(
|
||||
ExternalReferenceRegistry* registry) {
|
||||
registry->Register(X509Certificate::Parse);
|
||||
registry->Register(Parse);
|
||||
registry->Register(Subject);
|
||||
registry->Register(SubjectAltName);
|
||||
registry->Register(InfoAccess);
|
||||
@ -529,7 +578,7 @@ void X509Certificate::RegisterExternalReferences(
|
||||
registry->Register(KeyUsage);
|
||||
registry->Register(SerialNumber);
|
||||
registry->Register(Pem);
|
||||
registry->Register(Raw);
|
||||
registry->Register(Der);
|
||||
registry->Register(PublicKey);
|
||||
registry->Register(CheckCA);
|
||||
registry->Register(CheckHost);
|
||||
@ -537,7 +586,7 @@ void X509Certificate::RegisterExternalReferences(
|
||||
registry->Register(CheckIP);
|
||||
registry->Register(CheckIssued);
|
||||
registry->Register(CheckPrivateKey);
|
||||
registry->Register(Verify);
|
||||
registry->Register(CheckPublicKey);
|
||||
registry->Register(ToLegacy);
|
||||
registry->Register(GetIssuerCert);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "crypto/crypto_util.h"
|
||||
#include "env.h"
|
||||
#include "memory_tracker.h"
|
||||
#include "ncrypto.h"
|
||||
#include "node_worker.h"
|
||||
#include "v8.h"
|
||||
|
||||
@ -17,7 +18,7 @@ namespace crypto {
|
||||
// X509 objects that allows an X509Certificate instance to
|
||||
// be cloned at the JS level while pointing at the same
|
||||
// underlying X509 instance.
|
||||
class ManagedX509 : public MemoryRetainer {
|
||||
class ManagedX509 final : public MemoryRetainer {
|
||||
public:
|
||||
ManagedX509() = default;
|
||||
explicit ManagedX509(X509Pointer&& cert);
|
||||
@ -26,6 +27,8 @@ class ManagedX509 : public MemoryRetainer {
|
||||
|
||||
operator bool() const { return !!cert_; }
|
||||
X509* get() const { return cert_.get(); }
|
||||
ncrypto::X509View view() const { return cert_; }
|
||||
operator ncrypto::X509View() const { return cert_; }
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
SET_MEMORY_INFO_NAME(ManagedX509)
|
||||
@ -35,7 +38,7 @@ class ManagedX509 : public MemoryRetainer {
|
||||
X509Pointer cert_;
|
||||
};
|
||||
|
||||
class X509Certificate : public BaseObject {
|
||||
class X509Certificate final : public BaseObject {
|
||||
public:
|
||||
enum class GetPeerCertificateFlag {
|
||||
NONE,
|
||||
@ -72,28 +75,11 @@ class X509Certificate : public BaseObject {
|
||||
v8::Local<v8::Object> object,
|
||||
X509Pointer cert);
|
||||
|
||||
static void Parse(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Subject(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SubjectAltName(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Issuer(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void InfoAccess(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void ValidFrom(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void ValidTo(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void KeyUsage(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SerialNumber(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Raw(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void PublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Pem(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CheckCA(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CheckHost(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CheckEmail(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CheckIP(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CheckIssued(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void CheckPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void Verify(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void ToLegacy(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void GetIssuerCert(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
inline BaseObjectPtr<X509Certificate> getIssuerCert() const {
|
||||
return issuer_cert_;
|
||||
}
|
||||
|
||||
inline ncrypto::X509View view() const { return *cert_; }
|
||||
X509* get() { return cert_->get(); }
|
||||
|
||||
void MemoryInfo(MemoryTracker* tracker) const override;
|
||||
|
Loading…
x
Reference in New Issue
Block a user