%PDF- %PDF-
Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/crypto/ |
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/src/crypto/crypto_x509.cc |
#include "base_object-inl.h" #include "crypto_x509.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 "node_errors.h" #include "util-inl.h" #include "v8.h" #include <string> #include <vector> namespace node { using v8::ArrayBufferView; using v8::Context; using v8::EscapableHandleScope; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::MaybeLocal; using v8::Object; using v8::Uint32; using v8::Value; namespace crypto { ManagedX509::ManagedX509(X509Pointer&& cert) : cert_(std::move(cert)) {} ManagedX509::ManagedX509(const ManagedX509& that) { *this = that; } ManagedX509& ManagedX509::operator=(const ManagedX509& that) { cert_.reset(that.get()); if (cert_) X509_up_ref(cert_.get()); return *this; } void ManagedX509::MemoryInfo(MemoryTracker* tracker) const { // This is an approximation based on the der encoding size. int size = i2d_X509(cert_.get(), nullptr); tracker->TrackFieldWithSize("cert", size); } namespace { template <const EVP_MD* (*algo)()> void Fingerprint(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); X509Certificate* cert; ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder()); Local<Value> ret; if (GetFingerprintDigest(env, algo(), cert->get()).ToLocal(&ret)) args.GetReturnValue().Set(ret); } } // namespace Local<FunctionTemplate> X509Certificate::GetConstructorTemplate( Environment* env) { Local<FunctionTemplate> tmpl = env->x509_constructor_template(); if (tmpl.IsEmpty()) { Isolate* isolate = env->isolate(); tmpl = NewFunctionTemplate(isolate, nullptr); tmpl->InstanceTemplate()->SetInternalFieldCount( BaseObject::kInternalFieldCount); tmpl->SetClassName( FIXED_ONE_BYTE_STRING(env->isolate(), "X509Certificate")); SetProtoMethod(isolate, tmpl, "subject", Subject); SetProtoMethod(isolate, tmpl, "subjectAltName", SubjectAltName); SetProtoMethod(isolate, tmpl, "infoAccess", InfoAccess); SetProtoMethod(isolate, tmpl, "issuer", Issuer); SetProtoMethod(isolate, tmpl, "validTo", ValidTo); SetProtoMethod(isolate, tmpl, "validFrom", ValidFrom); SetProtoMethod(isolate, tmpl, "fingerprint", Fingerprint<EVP_sha1>); SetProtoMethod(isolate, tmpl, "fingerprint256", Fingerprint<EVP_sha256>); SetProtoMethod(isolate, tmpl, "fingerprint512", Fingerprint<EVP_sha512>); SetProtoMethod(isolate, tmpl, "keyUsage", KeyUsage); SetProtoMethod(isolate, tmpl, "serialNumber", SerialNumber); SetProtoMethod(isolate, tmpl, "pem", Pem); SetProtoMethod(isolate, tmpl, "raw", Raw); SetProtoMethod(isolate, tmpl, "publicKey", PublicKey); SetProtoMethod(isolate, tmpl, "checkCA", CheckCA); SetProtoMethod(isolate, tmpl, "checkHost", CheckHost); SetProtoMethod(isolate, tmpl, "checkEmail", CheckEmail); SetProtoMethod(isolate, tmpl, "checkIP", CheckIP); SetProtoMethod(isolate, tmpl, "checkIssued", CheckIssued); SetProtoMethod(isolate, tmpl, "checkPrivateKey", CheckPrivateKey); SetProtoMethod(isolate, tmpl, "verify", Verify); SetProtoMethod(isolate, tmpl, "toLegacy", ToLegacy); SetProtoMethod(isolate, tmpl, "getIssuerCert", GetIssuerCert); env->set_x509_constructor_template(tmpl); } return tmpl; } 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) { 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) { EscapableHandleScope scope(env->isolate()); Local<Function> ctor; if (!GetConstructorTemplate(env)->GetFunction(env->context()).ToLocal(&ctor)) return MaybeLocal<Object>(); Local<Object> obj; if (!ctor->NewInstance(env->context()).ToLocal(&obj)) return MaybeLocal<Object>(); new X509Certificate(env, obj, std::move(cert), issuer_chain); return scope.Escape(obj); } 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>(); X509Pointer ptr(X509_dup(cert)); return New(env, std::move(ptr)); } MaybeLocal<Object> X509Certificate::GetPeerCert( Environment* env, const SSLPointer& ssl, GetPeerCertificateFlag flag) { ClearErrorOnReturn clear_error_on_return; MaybeLocal<Object> maybe_cert; bool is_server = static_cast<int>(flag) & static_cast<int>(GetPeerCertificateFlag::SERVER); X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr); STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get()); if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0)) return MaybeLocal<Object>(); std::vector<Local<Value>> certs; if (!cert) { cert.reset(sk_X509_value(ssl_certs, 0)); 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.Holder()); 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); } template <MaybeLocal<Value> Property(Environment* env, X509* cert)> static void ReturnProperty(const FunctionCallbackInfo<Value>& args) { Environment* env = Environment::GetCurrent(args); X509Certificate* cert; ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder()); Local<Value> ret; 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.Holder()); // 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); 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.Holder()); if (cert->issuer_cert_) args.GetReturnValue().Set(cert->issuer_cert_->object()); } X509Certificate::X509Certificate( Environment* env, Local<Object> object, std::shared_ptr<ManagedX509> cert, STACK_OF(X509)* issuer_chain) : BaseObject(env, object), cert_(std::move(cert)) { MakeWeak(); if (issuer_chain != nullptr && sk_X509_num(issuer_chain)) { X509Pointer cert(X509_dup(sk_X509_value(issuer_chain, 0))); sk_X509_delete(issuer_chain, 0); Local<Object> obj = sk_X509_num(issuer_chain) ? X509Certificate::New(env, std::move(cert), issuer_chain) .ToLocalChecked() : X509Certificate::New(env, std::move(cert)) .ToLocalChecked(); issuer_cert_.reset(Unwrap<X509Certificate>(obj)); } } void X509Certificate::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("cert", cert_); } BaseObjectPtr<BaseObject> X509Certificate::X509CertificateTransferData::Deserialize( Environment* env, Local<Context> context, std::unique_ptr<worker::TransferData> self) { if (context != env->context()) { THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env); return {}; } Local<Value> handle; if (!X509Certificate::New(env, data_).ToLocal(&handle)) return {}; return BaseObjectPtr<BaseObject>( Unwrap<X509Certificate>(handle.As<Object>())); } BaseObject::TransferMode X509Certificate::GetTransferMode() const { return BaseObject::TransferMode::kCloneable; } std::unique_ptr<worker::TransferData> X509Certificate::CloneForMessaging() const { return std::make_unique<X509CertificateTransferData>(cert_); } void X509Certificate::Initialize(Environment* env, Local<Object> target) { SetMethod(env->context(), target, "parseX509", X509Certificate::Parse); NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT); NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NEVER_CHECK_SUBJECT); NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NO_WILDCARDS); NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS); NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS); } void X509Certificate::RegisterExternalReferences( ExternalReferenceRegistry* registry) { registry->Register(X509Certificate::Parse); registry->Register(Subject); registry->Register(SubjectAltName); registry->Register(InfoAccess); registry->Register(Issuer); registry->Register(ValidTo); registry->Register(ValidFrom); registry->Register(Fingerprint<EVP_sha1>); registry->Register(Fingerprint<EVP_sha256>); registry->Register(Fingerprint<EVP_sha512>); registry->Register(KeyUsage); registry->Register(SerialNumber); registry->Register(Pem); registry->Register(Raw); registry->Register(PublicKey); registry->Register(CheckCA); registry->Register(CheckHost); registry->Register(CheckEmail); registry->Register(CheckIP); registry->Register(CheckIssued); registry->Register(CheckPrivateKey); registry->Register(Verify); registry->Register(ToLegacy); registry->Register(GetIssuerCert); } } // namespace crypto } // namespace node