|
9 | 9 | #include "node.h" |
10 | 10 | #include "node_buffer.h" |
11 | 11 | #include "node_options.h" |
| 12 | +#include "node_process-inl.h" |
12 | 13 | #include "util.h" |
13 | 14 | #include "v8.h" |
14 | 15 |
|
@@ -1084,35 +1085,73 @@ template <typename It> |
1084 | 1085 | MaybeLocal<Array> X509sToArrayOfStrings(Environment* env, |
1085 | 1086 | It first, |
1086 | 1087 | It last, |
1087 | | - size_t size) { |
| 1088 | + size_t size, |
| 1089 | + bool skip_on_error = false) { |
1088 | 1090 | ClearErrorOnReturn clear_error_on_return; |
1089 | 1091 | EscapableHandleScope scope(env->isolate()); |
1090 | 1092 |
|
1091 | | - LocalVector<Value> result(env->isolate(), size); |
1092 | | - size_t i = 0; |
1093 | | - for (It cur = first; cur != last; ++cur, ++i) { |
| 1093 | + LocalVector<Value> result(env->isolate()); |
| 1094 | + result.reserve(size); |
| 1095 | + size_t skipped = 0; |
| 1096 | + for (It cur = first; cur != last; ++cur) { |
1094 | 1097 | X509View view(*cur); |
1095 | 1098 | auto pem_bio = view.toPEM(); |
1096 | 1099 | if (!pem_bio) { |
| 1100 | + if (skip_on_error) { |
| 1101 | + auto subject_bio = view.getSubject(); |
| 1102 | + char* subject_data = nullptr; |
| 1103 | + std::string subject_str = "<unknown>"; |
| 1104 | + if (subject_bio) { |
| 1105 | + long subject_size = BIO_get_mem_data(subject_bio.get(), &subject_data); |
| 1106 | + if (subject_size > 0 && subject_data) { |
| 1107 | + subject_str = std::string(subject_data, subject_size); |
| 1108 | + } |
| 1109 | + } |
| 1110 | + per_process::Debug(DebugCategory::CRYPTO, |
| 1111 | + "Skipping system certificate with subject " |
| 1112 | + "'%s' because X509 to PEM conversion failed\n", |
| 1113 | + subject_str.c_str()); |
| 1114 | + skipped++; |
| 1115 | + continue; |
| 1116 | + } |
1097 | 1117 | ThrowCryptoError(env, ERR_get_error(), "X509 to PEM conversion"); |
1098 | 1118 | return MaybeLocal<Array>(); |
1099 | 1119 | } |
1100 | 1120 |
|
1101 | 1121 | char* pem_data = nullptr; |
1102 | 1122 | auto pem_size = BIO_get_mem_data(pem_bio.get(), &pem_data); |
1103 | 1123 | if (pem_size <= 0 || !pem_data) { |
| 1124 | + if (skip_on_error) { |
| 1125 | + per_process::Debug(DebugCategory::CRYPTO, |
| 1126 | + "Skipping a system certificate " |
| 1127 | + "because reading PEM data failed\n"); |
| 1128 | + skipped++; |
| 1129 | + continue; |
| 1130 | + } |
1104 | 1131 | ThrowCryptoError(env, ERR_get_error(), "Reading PEM data"); |
1105 | 1132 | return MaybeLocal<Array>(); |
1106 | 1133 | } |
| 1134 | + |
| 1135 | + Local<Value> str; |
1107 | 1136 | // PEM is base64-encoded, so it must be one-byte. |
1108 | 1137 | if (!String::NewFromOneByte(env->isolate(), |
1109 | 1138 | reinterpret_cast<uint8_t*>(pem_data), |
1110 | 1139 | v8::NewStringType::kNormal, |
1111 | 1140 | pem_size) |
1112 | | - .ToLocal(&result[i])) { |
| 1141 | + .ToLocal(&str)) { |
1113 | 1142 | return MaybeLocal<Array>(); |
1114 | 1143 | } |
| 1144 | + result.push_back(str); |
1115 | 1145 | } |
| 1146 | + |
| 1147 | + if (skipped > 0) { |
| 1148 | + ProcessEmitWarning( |
| 1149 | + env, |
| 1150 | + "Skipped %zu system certificate(s) that could not be converted " |
| 1151 | + "to PEM format. Use NODE_DEBUG=crypto for details.", |
| 1152 | + skipped); |
| 1153 | + } |
| 1154 | + |
1116 | 1155 | return scope.Escape(Array::New(env->isolate(), result.data(), result.size())); |
1117 | 1156 | } |
1118 | 1157 |
|
@@ -1196,7 +1235,7 @@ void GetSystemCACertificates(const FunctionCallbackInfo<Value>& args) { |
1196 | 1235 | Environment* env = Environment::GetCurrent(args); |
1197 | 1236 | Local<Array> results; |
1198 | 1237 | std::vector<X509*>& certs = GetSystemStoreCACertificates(); |
1199 | | - if (X509sToArrayOfStrings(env, certs.begin(), certs.end(), certs.size()) |
| 1238 | + if (X509sToArrayOfStrings(env, certs.begin(), certs.end(), certs.size(), true) |
1200 | 1239 | .ToLocal(&results)) { |
1201 | 1240 | args.GetReturnValue().Set(results); |
1202 | 1241 | } |
|
0 commit comments