@@ -42,11 +42,13 @@ using ncrypto::MarkPopErrorOnReturn;
4242using ncrypto::SSLPointer;
4343using ncrypto::StackOfX509;
4444using ncrypto::X509Pointer;
45+ using ncrypto::X509View;
4546using v8::Array;
4647using v8::ArrayBufferView;
4748using v8::Boolean;
4849using v8::Context;
4950using v8::DontDelete;
51+ using v8::EscapableHandleScope;
5052using v8::Exception;
5153using v8::External;
5254using v8::FunctionCallbackInfo;
@@ -57,7 +59,9 @@ using v8::Integer;
5759using v8::Isolate;
5860using v8::JustVoid;
5961using v8::Local;
62+ using v8::LocalVector;
6063using v8::Maybe;
64+ using v8::MaybeLocal;
6165using v8::Nothing;
6266using v8::Object;
6367using v8::PropertyAttribute;
@@ -672,9 +676,6 @@ static void LoadCertsFromDir(std::vector<X509*>* certs,
672676 return ;
673677 }
674678
675- uv_fs_t stats_req;
676- auto cleanup_stats =
677- OnScopeLeave ([&stats_req]() { uv_fs_req_cleanup (&stats_req); });
678679 for (;;) {
679680 uv_dirent_t ent;
680681
@@ -691,12 +692,14 @@ static void LoadCertsFromDir(std::vector<X509*>* certs,
691692 return ;
692693 }
693694
695+ uv_fs_t stats_req;
694696 std::string file_path = std::string (cert_dir) + " /" + ent.name ;
695697 int stats_r = uv_fs_stat (nullptr , &stats_req, file_path.c_str (), nullptr );
696698 if (stats_r == 0 &&
697699 (static_cast <uv_stat_t *>(stats_req.ptr )->st_mode & S_IFREG)) {
698700 LoadCertsFromFile (certs, file_path.c_str ());
699701 }
702+ uv_fs_req_cleanup (&stats_req);
700703 }
701704}
702705
@@ -775,7 +778,7 @@ static std::vector<X509*> InitializeSystemStoreCertificates() {
775778 return system_store_certs;
776779}
777780
778- static std::vector<X509*>& GetSystemStoreRootCertificates () {
781+ static std::vector<X509*>& GetSystemStoreCACertificates () {
779782 // Use function-local static to guarantee thread safety.
780783 static std::vector<X509*> system_store_certs =
781784 InitializeSystemStoreCertificates ();
@@ -847,7 +850,7 @@ X509_STORE* NewRootCertStore() {
847850 CHECK_EQ (1 , X509_STORE_add_cert (store, cert));
848851 }
849852 if (per_process::cli_options->use_system_ca ) {
850- for (X509* cert : GetSystemStoreRootCertificates ()) {
853+ for (X509* cert : GetSystemStoreCACertificates ()) {
851854 CHECK_EQ (1 , X509_STORE_add_cert (store, cert));
852855 }
853856 }
@@ -869,7 +872,7 @@ void CleanupCachedRootCertificates() {
869872 }
870873 }
871874 if (has_cached_system_root_certs.load ()) {
872- for (X509* cert : GetSystemStoreRootCertificates ()) {
875+ for (X509* cert : GetSystemStoreCACertificates ()) {
873876 X509_free (cert);
874877 }
875878 }
@@ -881,7 +884,7 @@ void CleanupCachedRootCertificates() {
881884 }
882885}
883886
884- void GetRootCertificates (const FunctionCallbackInfo<Value>& args) {
887+ void GetBundledRootCertificates (const FunctionCallbackInfo<Value>& args) {
885888 Environment* env = Environment::GetCurrent (args);
886889 Local<Value> result[arraysize (root_certs)];
887890
@@ -898,6 +901,58 @@ void GetRootCertificates(const FunctionCallbackInfo<Value>& args) {
898901 Array::New (env->isolate (), result, arraysize (root_certs)));
899902}
900903
904+ MaybeLocal<Array> X509sToArrayOfStrings (Environment* env,
905+ const std::vector<X509*>& certs) {
906+ ClearErrorOnReturn clear_error_on_return;
907+ EscapableHandleScope scope (env->isolate ());
908+
909+ LocalVector<Value> result (env->isolate (), certs.size ());
910+ for (size_t i = 0 ; i < certs.size (); ++i) {
911+ X509View view (certs[i]);
912+ auto pem_bio = view.toPEM ();
913+ if (!pem_bio) {
914+ ThrowCryptoError (env, ERR_get_error (), " X509 to PEM conversion" );
915+ return MaybeLocal<Array>();
916+ }
917+
918+ char * pem_data = nullptr ;
919+ auto pem_size = BIO_get_mem_data (pem_bio.get (), &pem_data);
920+ if (pem_size <= 0 || !pem_data) {
921+ ThrowCryptoError (env, ERR_get_error (), " Reading PEM data" );
922+ return MaybeLocal<Array>();
923+ }
924+ // PEM is base64-encoded, so it must be one-byte.
925+ if (!String::NewFromOneByte (env->isolate (),
926+ reinterpret_cast <uint8_t *>(pem_data),
927+ v8::NewStringType::kNormal ,
928+ pem_size)
929+ .ToLocal (&result[i])) {
930+ return MaybeLocal<Array>();
931+ }
932+ }
933+ return scope.Escape (Array::New (env->isolate (), result.data (), result.size ()));
934+ }
935+
936+ void GetSystemCACertificates (const FunctionCallbackInfo<Value>& args) {
937+ Environment* env = Environment::GetCurrent (args);
938+ Local<Array> results;
939+ if (X509sToArrayOfStrings (env, GetSystemStoreCACertificates ())
940+ .ToLocal (&results)) {
941+ args.GetReturnValue ().Set (results);
942+ }
943+ }
944+
945+ void GetExtraCACertificates (const FunctionCallbackInfo<Value>& args) {
946+ Environment* env = Environment::GetCurrent (args);
947+ if (extra_root_certs_file.empty ()) {
948+ return args.GetReturnValue ().Set (Array::New (env->isolate ()));
949+ }
950+ Local<Array> results;
951+ if (X509sToArrayOfStrings (env, GetExtraCACertificates ()).ToLocal (&results)) {
952+ args.GetReturnValue ().Set (results);
953+ }
954+ }
955+
901956bool SecureContext::HasInstance (Environment* env, const Local<Value>& value) {
902957 return GetConstructorTemplate (env)->HasInstance (value);
903958}
@@ -981,8 +1036,14 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
9811036 GetConstructorTemplate (env),
9821037 SetConstructorFunctionFlag::NONE);
9831038
1039+ SetMethodNoSideEffect (context,
1040+ target,
1041+ " getBundledRootCertificates" ,
1042+ GetBundledRootCertificates);
1043+ SetMethodNoSideEffect (
1044+ context, target, " getSystemCACertificates" , GetSystemCACertificates);
9841045 SetMethodNoSideEffect (
985- context, target, " getRootCertificates " , GetRootCertificates );
1046+ context, target, " getExtraCACertificates " , GetExtraCACertificates );
9861047}
9871048
9881049void SecureContext::RegisterExternalReferences (
@@ -1022,7 +1083,9 @@ void SecureContext::RegisterExternalReferences(
10221083
10231084 registry->Register (CtxGetter);
10241085
1025- registry->Register (GetRootCertificates);
1086+ registry->Register (GetBundledRootCertificates);
1087+ registry->Register (GetSystemCACertificates);
1088+ registry->Register (GetExtraCACertificates);
10261089}
10271090
10281091SecureContext* SecureContext::Create (Environment* env) {
0 commit comments