1 #include "base_object-inl.h"
2 #include "crypto_x509.h"
3 #include "crypto_common.h"
4 #include "crypto_context.h"
5 #include "crypto_keys.h"
6 #include "crypto_bio.h"
7 #include "env-inl.h"
8 #include "memory_tracker-inl.h"
9 #include "node_errors.h"
10 #include "util-inl.h"
11 #include "v8.h"
12
13 #include <string>
14 #include <vector>
15
16 namespace node {
17
18 using v8::ArrayBufferView;
19 using v8::Context;
20 using v8::EscapableHandleScope;
21 using v8::Function;
22 using v8::FunctionCallbackInfo;
23 using v8::FunctionTemplate;
24 using v8::Isolate;
25 using v8::Local;
26 using v8::MaybeLocal;
27 using v8::Object;
28 using v8::Uint32;
29 using v8::Value;
30
31 namespace crypto {
32
ManagedX509(X509Pointer && cert)33 ManagedX509::ManagedX509(X509Pointer&& cert) : cert_(std::move(cert)) {}
34
ManagedX509(const ManagedX509 & that)35 ManagedX509::ManagedX509(const ManagedX509& that) {
36 *this = that;
37 }
38
operator =(const ManagedX509 & that)39 ManagedX509& ManagedX509::operator=(const ManagedX509& that) {
40 cert_.reset(that.get());
41
42 if (cert_)
43 X509_up_ref(cert_.get());
44
45 return *this;
46 }
47
MemoryInfo(MemoryTracker * tracker) const48 void ManagedX509::MemoryInfo(MemoryTracker* tracker) const {
49 // This is an approximation based on the der encoding size.
50 int size = i2d_X509(cert_.get(), nullptr);
51 tracker->TrackFieldWithSize("cert", size);
52 }
53
54 namespace {
55 template <const EVP_MD* (*algo)()>
Fingerprint(const FunctionCallbackInfo<Value> & args)56 void Fingerprint(const FunctionCallbackInfo<Value>& args) {
57 Environment* env = Environment::GetCurrent(args);
58 X509Certificate* cert;
59 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
60 Local<Value> ret;
61 if (GetFingerprintDigest(env, algo(), cert->get()).ToLocal(&ret))
62 args.GetReturnValue().Set(ret);
63 }
64 } // namespace
65
GetConstructorTemplate(Environment * env)66 Local<FunctionTemplate> X509Certificate::GetConstructorTemplate(
67 Environment* env) {
68 Local<FunctionTemplate> tmpl = env->x509_constructor_template();
69 if (tmpl.IsEmpty()) {
70 Isolate* isolate = env->isolate();
71 tmpl = NewFunctionTemplate(isolate, nullptr);
72 tmpl->InstanceTemplate()->SetInternalFieldCount(
73 BaseObject::kInternalFieldCount);
74 tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
75 tmpl->SetClassName(
76 FIXED_ONE_BYTE_STRING(env->isolate(), "X509Certificate"));
77 SetProtoMethod(isolate, tmpl, "subject", Subject);
78 SetProtoMethod(isolate, tmpl, "subjectAltName", SubjectAltName);
79 SetProtoMethod(isolate, tmpl, "infoAccess", InfoAccess);
80 SetProtoMethod(isolate, tmpl, "issuer", Issuer);
81 SetProtoMethod(isolate, tmpl, "validTo", ValidTo);
82 SetProtoMethod(isolate, tmpl, "validFrom", ValidFrom);
83 SetProtoMethod(isolate, tmpl, "fingerprint", Fingerprint<EVP_sha1>);
84 SetProtoMethod(isolate, tmpl, "fingerprint256", Fingerprint<EVP_sha256>);
85 SetProtoMethod(isolate, tmpl, "fingerprint512", Fingerprint<EVP_sha512>);
86 SetProtoMethod(isolate, tmpl, "keyUsage", KeyUsage);
87 SetProtoMethod(isolate, tmpl, "serialNumber", SerialNumber);
88 SetProtoMethod(isolate, tmpl, "pem", Pem);
89 SetProtoMethod(isolate, tmpl, "raw", Raw);
90 SetProtoMethod(isolate, tmpl, "publicKey", PublicKey);
91 SetProtoMethod(isolate, tmpl, "checkCA", CheckCA);
92 SetProtoMethod(isolate, tmpl, "checkHost", CheckHost);
93 SetProtoMethod(isolate, tmpl, "checkEmail", CheckEmail);
94 SetProtoMethod(isolate, tmpl, "checkIP", CheckIP);
95 SetProtoMethod(isolate, tmpl, "checkIssued", CheckIssued);
96 SetProtoMethod(isolate, tmpl, "checkPrivateKey", CheckPrivateKey);
97 SetProtoMethod(isolate, tmpl, "verify", Verify);
98 SetProtoMethod(isolate, tmpl, "toLegacy", ToLegacy);
99 SetProtoMethod(isolate, tmpl, "getIssuerCert", GetIssuerCert);
100 env->set_x509_constructor_template(tmpl);
101 }
102 return tmpl;
103 }
104
HasInstance(Environment * env,Local<Object> object)105 bool X509Certificate::HasInstance(Environment* env, Local<Object> object) {
106 return GetConstructorTemplate(env)->HasInstance(object);
107 }
108
New(Environment * env,X509Pointer cert,STACK_OF (X509)* issuer_chain)109 MaybeLocal<Object> X509Certificate::New(
110 Environment* env,
111 X509Pointer cert,
112 STACK_OF(X509)* issuer_chain) {
113 std::shared_ptr<ManagedX509> mcert(new ManagedX509(std::move(cert)));
114 return New(env, std::move(mcert), issuer_chain);
115 }
116
New(Environment * env,std::shared_ptr<ManagedX509> cert,STACK_OF (X509)* issuer_chain)117 MaybeLocal<Object> X509Certificate::New(
118 Environment* env,
119 std::shared_ptr<ManagedX509> cert,
120 STACK_OF(X509)* issuer_chain) {
121 EscapableHandleScope scope(env->isolate());
122 Local<Function> ctor;
123 if (!GetConstructorTemplate(env)->GetFunction(env->context()).ToLocal(&ctor))
124 return MaybeLocal<Object>();
125
126 Local<Object> obj;
127 if (!ctor->NewInstance(env->context()).ToLocal(&obj))
128 return MaybeLocal<Object>();
129
130 new X509Certificate(env, obj, std::move(cert), issuer_chain);
131 return scope.Escape(obj);
132 }
133
GetCert(Environment * env,const SSLPointer & ssl)134 MaybeLocal<Object> X509Certificate::GetCert(
135 Environment* env,
136 const SSLPointer& ssl) {
137 ClearErrorOnReturn clear_error_on_return;
138 X509* cert = SSL_get_certificate(ssl.get());
139 if (cert == nullptr)
140 return MaybeLocal<Object>();
141
142 X509Pointer ptr(X509_dup(cert));
143 return New(env, std::move(ptr));
144 }
145
GetPeerCert(Environment * env,const SSLPointer & ssl,GetPeerCertificateFlag flag)146 MaybeLocal<Object> X509Certificate::GetPeerCert(
147 Environment* env,
148 const SSLPointer& ssl,
149 GetPeerCertificateFlag flag) {
150 ClearErrorOnReturn clear_error_on_return;
151 MaybeLocal<Object> maybe_cert;
152
153 bool is_server =
154 static_cast<int>(flag) & static_cast<int>(GetPeerCertificateFlag::SERVER);
155
156 X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr);
157 STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get());
158 if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
159 return MaybeLocal<Object>();
160
161 std::vector<Local<Value>> certs;
162
163 if (!cert) {
164 cert.reset(sk_X509_value(ssl_certs, 0));
165 sk_X509_delete(ssl_certs, 0);
166 }
167
168 return sk_X509_num(ssl_certs)
169 ? New(env, std::move(cert), ssl_certs)
170 : New(env, std::move(cert));
171 }
172
Parse(const FunctionCallbackInfo<Value> & args)173 void X509Certificate::Parse(const FunctionCallbackInfo<Value>& args) {
174 Environment* env = Environment::GetCurrent(args);
175
176 CHECK(args[0]->IsArrayBufferView());
177 ArrayBufferViewContents<unsigned char> buf(args[0].As<ArrayBufferView>());
178 const unsigned char* data = buf.data();
179 unsigned data_len = buf.length();
180
181 ClearErrorOnReturn clear_error_on_return;
182 BIOPointer bio(LoadBIO(env, args[0]));
183 if (!bio)
184 return ThrowCryptoError(env, ERR_get_error());
185
186 Local<Object> cert;
187
188 X509Pointer pem(PEM_read_bio_X509_AUX(
189 bio.get(), nullptr, NoPasswordCallback, nullptr));
190 if (!pem) {
191 // Try as DER, but return the original PEM failure if it isn't DER.
192 MarkPopErrorOnReturn mark_here;
193
194 X509Pointer der(d2i_X509(nullptr, &data, data_len));
195 if (!der)
196 return ThrowCryptoError(env, ERR_get_error());
197
198 if (!X509Certificate::New(env, std::move(der)).ToLocal(&cert))
199 return;
200 } else if (!X509Certificate::New(env, std::move(pem)).ToLocal(&cert)) {
201 return;
202 }
203
204 args.GetReturnValue().Set(cert);
205 }
206
207 template <MaybeLocal<Value> Property(
208 Environment* env, X509* cert, const BIOPointer& bio)>
ReturnPropertyThroughBIO(const FunctionCallbackInfo<Value> & args)209 static void ReturnPropertyThroughBIO(const FunctionCallbackInfo<Value>& args) {
210 Environment* env = Environment::GetCurrent(args);
211 X509Certificate* cert;
212 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
213 BIOPointer bio(BIO_new(BIO_s_mem()));
214 CHECK(bio);
215 Local<Value> ret;
216 if (Property(env, cert->get(), bio).ToLocal(&ret))
217 args.GetReturnValue().Set(ret);
218 }
219
Subject(const FunctionCallbackInfo<Value> & args)220 void X509Certificate::Subject(const FunctionCallbackInfo<Value>& args) {
221 ReturnPropertyThroughBIO<GetSubject>(args);
222 }
223
Issuer(const FunctionCallbackInfo<Value> & args)224 void X509Certificate::Issuer(const FunctionCallbackInfo<Value>& args) {
225 ReturnPropertyThroughBIO<GetIssuerString>(args);
226 }
227
SubjectAltName(const FunctionCallbackInfo<Value> & args)228 void X509Certificate::SubjectAltName(const FunctionCallbackInfo<Value>& args) {
229 ReturnPropertyThroughBIO<GetSubjectAltNameString>(args);
230 }
231
InfoAccess(const FunctionCallbackInfo<Value> & args)232 void X509Certificate::InfoAccess(const FunctionCallbackInfo<Value>& args) {
233 ReturnPropertyThroughBIO<GetInfoAccessString>(args);
234 }
235
ValidFrom(const FunctionCallbackInfo<Value> & args)236 void X509Certificate::ValidFrom(const FunctionCallbackInfo<Value>& args) {
237 ReturnPropertyThroughBIO<GetValidFrom>(args);
238 }
239
ValidTo(const FunctionCallbackInfo<Value> & args)240 void X509Certificate::ValidTo(const FunctionCallbackInfo<Value>& args) {
241 ReturnPropertyThroughBIO<GetValidTo>(args);
242 }
243
244 template <MaybeLocal<Value> Property(Environment* env, X509* cert)>
ReturnProperty(const FunctionCallbackInfo<Value> & args)245 static void ReturnProperty(const FunctionCallbackInfo<Value>& args) {
246 Environment* env = Environment::GetCurrent(args);
247 X509Certificate* cert;
248 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
249 Local<Value> ret;
250 if (Property(env, cert->get()).ToLocal(&ret)) args.GetReturnValue().Set(ret);
251 }
252
KeyUsage(const FunctionCallbackInfo<Value> & args)253 void X509Certificate::KeyUsage(const FunctionCallbackInfo<Value>& args) {
254 ReturnProperty<GetKeyUsage>(args);
255 }
256
SerialNumber(const FunctionCallbackInfo<Value> & args)257 void X509Certificate::SerialNumber(const FunctionCallbackInfo<Value>& args) {
258 ReturnProperty<GetSerialNumber>(args);
259 }
260
Raw(const FunctionCallbackInfo<Value> & args)261 void X509Certificate::Raw(const FunctionCallbackInfo<Value>& args) {
262 ReturnProperty<GetRawDERCertificate>(args);
263 }
264
PublicKey(const FunctionCallbackInfo<Value> & args)265 void X509Certificate::PublicKey(const FunctionCallbackInfo<Value>& args) {
266 Environment* env = Environment::GetCurrent(args);
267 X509Certificate* cert;
268 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
269
270 // TODO(tniessen): consider checking X509_get_pubkey() when the
271 // X509Certificate object is being created.
272 ClearErrorOnReturn clear_error_on_return;
273 EVPKeyPointer pkey(X509_get_pubkey(cert->get()));
274 if (!pkey) return ThrowCryptoError(env, ERR_get_error());
275 ManagedEVPPKey epkey(std::move(pkey));
276 std::shared_ptr<KeyObjectData> key_data =
277 KeyObjectData::CreateAsymmetric(kKeyTypePublic, epkey);
278
279 Local<Value> ret;
280 if (KeyObjectHandle::Create(env, key_data).ToLocal(&ret))
281 args.GetReturnValue().Set(ret);
282 }
283
Pem(const FunctionCallbackInfo<Value> & args)284 void X509Certificate::Pem(const FunctionCallbackInfo<Value>& args) {
285 Environment* env = Environment::GetCurrent(args);
286 X509Certificate* cert;
287 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
288 BIOPointer bio(BIO_new(BIO_s_mem()));
289 CHECK(bio);
290 if (PEM_write_bio_X509(bio.get(), cert->get()))
291 args.GetReturnValue().Set(ToV8Value(env, bio));
292 }
293
CheckCA(const FunctionCallbackInfo<Value> & args)294 void X509Certificate::CheckCA(const FunctionCallbackInfo<Value>& args) {
295 X509Certificate* cert;
296 ClearErrorOnReturn clear_error_on_return;
297 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
298 args.GetReturnValue().Set(X509_check_ca(cert->get()) == 1);
299 }
300
CheckHost(const FunctionCallbackInfo<Value> & args)301 void X509Certificate::CheckHost(const FunctionCallbackInfo<Value>& args) {
302 Environment* env = Environment::GetCurrent(args);
303 X509Certificate* cert;
304 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
305
306 CHECK(args[0]->IsString()); // name
307 CHECK(args[1]->IsUint32()); // flags
308
309 Utf8Value name(env->isolate(), args[0]);
310 uint32_t flags = args[1].As<Uint32>()->Value();
311 char* peername;
312
313 switch (X509_check_host(
314 cert->get(),
315 *name,
316 name.length(),
317 flags,
318 &peername)) {
319 case 1: { // Match!
320 Local<Value> ret = args[0];
321 if (peername != nullptr) {
322 ret = OneByteString(env->isolate(), peername);
323 OPENSSL_free(peername);
324 }
325 return args.GetReturnValue().Set(ret);
326 }
327 case 0: // No Match!
328 return; // No return value is set
329 case -2: // Error!
330 return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid name");
331 default: // Error!
332 return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
333 }
334 }
335
CheckEmail(const FunctionCallbackInfo<Value> & args)336 void X509Certificate::CheckEmail(const FunctionCallbackInfo<Value>& args) {
337 Environment* env = Environment::GetCurrent(args);
338 X509Certificate* cert;
339 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
340
341 CHECK(args[0]->IsString()); // name
342 CHECK(args[1]->IsUint32()); // flags
343
344 Utf8Value name(env->isolate(), args[0]);
345 uint32_t flags = args[1].As<Uint32>()->Value();
346
347 switch (X509_check_email(
348 cert->get(),
349 *name,
350 name.length(),
351 flags)) {
352 case 1: // Match!
353 return args.GetReturnValue().Set(args[0]);
354 case 0: // No Match!
355 return; // No return value is set
356 case -2: // Error!
357 return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid name");
358 default: // Error!
359 return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
360 }
361 }
362
CheckIP(const FunctionCallbackInfo<Value> & args)363 void X509Certificate::CheckIP(const FunctionCallbackInfo<Value>& args) {
364 Environment* env = Environment::GetCurrent(args);
365 X509Certificate* cert;
366 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
367
368 CHECK(args[0]->IsString()); // IP
369 CHECK(args[1]->IsUint32()); // flags
370
371 Utf8Value name(env->isolate(), args[0]);
372 uint32_t flags = args[1].As<Uint32>()->Value();
373
374 switch (X509_check_ip_asc(cert->get(), *name, flags)) {
375 case 1: // Match!
376 return args.GetReturnValue().Set(args[0]);
377 case 0: // No Match!
378 return; // No return value is set
379 case -2: // Error!
380 return THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP");
381 default: // Error!
382 return THROW_ERR_CRYPTO_OPERATION_FAILED(env);
383 }
384 }
385
CheckIssued(const FunctionCallbackInfo<Value> & args)386 void X509Certificate::CheckIssued(const FunctionCallbackInfo<Value>& args) {
387 Environment* env = Environment::GetCurrent(args);
388 X509Certificate* cert;
389 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
390
391 CHECK(args[0]->IsObject());
392 CHECK(X509Certificate::HasInstance(env, args[0].As<Object>()));
393
394 X509Certificate* issuer;
395 ASSIGN_OR_RETURN_UNWRAP(&issuer, args[0]);
396
397 ClearErrorOnReturn clear_error_on_return;
398
399 args.GetReturnValue().Set(
400 X509_check_issued(issuer->get(), cert->get()) == X509_V_OK);
401 }
402
CheckPrivateKey(const FunctionCallbackInfo<Value> & args)403 void X509Certificate::CheckPrivateKey(const FunctionCallbackInfo<Value>& args) {
404 X509Certificate* cert;
405 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
406
407 CHECK(args[0]->IsObject());
408 KeyObjectHandle* key;
409 ASSIGN_OR_RETURN_UNWRAP(&key, args[0]);
410 CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePrivate);
411
412 ClearErrorOnReturn clear_error_on_return;
413
414 args.GetReturnValue().Set(
415 X509_check_private_key(
416 cert->get(),
417 key->Data()->GetAsymmetricKey().get()) == 1);
418 }
419
Verify(const FunctionCallbackInfo<Value> & args)420 void X509Certificate::Verify(const FunctionCallbackInfo<Value>& args) {
421 X509Certificate* cert;
422 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
423
424 CHECK(args[0]->IsObject());
425 KeyObjectHandle* key;
426 ASSIGN_OR_RETURN_UNWRAP(&key, args[0]);
427 CHECK_EQ(key->Data()->GetKeyType(), kKeyTypePublic);
428
429 ClearErrorOnReturn clear_error_on_return;
430
431 args.GetReturnValue().Set(
432 X509_verify(
433 cert->get(),
434 key->Data()->GetAsymmetricKey().get()) > 0);
435 }
436
ToLegacy(const FunctionCallbackInfo<Value> & args)437 void X509Certificate::ToLegacy(const FunctionCallbackInfo<Value>& args) {
438 Environment* env = Environment::GetCurrent(args);
439 X509Certificate* cert;
440 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
441 ClearErrorOnReturn clear_error_on_return;
442 Local<Value> ret;
443 if (X509ToObject(env, cert->get()).ToLocal(&ret))
444 args.GetReturnValue().Set(ret);
445 }
446
GetIssuerCert(const FunctionCallbackInfo<Value> & args)447 void X509Certificate::GetIssuerCert(const FunctionCallbackInfo<Value>& args) {
448 X509Certificate* cert;
449 ASSIGN_OR_RETURN_UNWRAP(&cert, args.Holder());
450 if (cert->issuer_cert_)
451 args.GetReturnValue().Set(cert->issuer_cert_->object());
452 }
453
X509Certificate(Environment * env,Local<Object> object,std::shared_ptr<ManagedX509> cert,STACK_OF (X509)* issuer_chain)454 X509Certificate::X509Certificate(
455 Environment* env,
456 Local<Object> object,
457 std::shared_ptr<ManagedX509> cert,
458 STACK_OF(X509)* issuer_chain)
459 : BaseObject(env, object),
460 cert_(std::move(cert)) {
461 MakeWeak();
462
463 if (issuer_chain != nullptr && sk_X509_num(issuer_chain)) {
464 X509Pointer cert(X509_dup(sk_X509_value(issuer_chain, 0)));
465 sk_X509_delete(issuer_chain, 0);
466 Local<Object> obj = sk_X509_num(issuer_chain)
467 ? X509Certificate::New(env, std::move(cert), issuer_chain)
468 .ToLocalChecked()
469 : X509Certificate::New(env, std::move(cert))
470 .ToLocalChecked();
471 issuer_cert_.reset(Unwrap<X509Certificate>(obj));
472 }
473 }
474
MemoryInfo(MemoryTracker * tracker) const475 void X509Certificate::MemoryInfo(MemoryTracker* tracker) const {
476 tracker->TrackField("cert", cert_);
477 }
478
479 BaseObjectPtr<BaseObject>
Deserialize(Environment * env,Local<Context> context,std::unique_ptr<worker::TransferData> self)480 X509Certificate::X509CertificateTransferData::Deserialize(
481 Environment* env,
482 Local<Context> context,
483 std::unique_ptr<worker::TransferData> self) {
484 if (context != env->context()) {
485 THROW_ERR_MESSAGE_TARGET_CONTEXT_UNAVAILABLE(env);
486 return {};
487 }
488
489 Local<Value> handle;
490 if (!X509Certificate::New(env, data_).ToLocal(&handle))
491 return {};
492
493 return BaseObjectPtr<BaseObject>(
494 Unwrap<X509Certificate>(handle.As<Object>()));
495 }
496
497
GetTransferMode() const498 BaseObject::TransferMode X509Certificate::GetTransferMode() const {
499 return BaseObject::TransferMode::kCloneable;
500 }
501
CloneForMessaging() const502 std::unique_ptr<worker::TransferData> X509Certificate::CloneForMessaging()
503 const {
504 return std::make_unique<X509CertificateTransferData>(cert_);
505 }
506
507
Initialize(Environment * env,Local<Object> target)508 void X509Certificate::Initialize(Environment* env, Local<Object> target) {
509 SetMethod(env->context(), target, "parseX509", X509Certificate::Parse);
510
511 NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT);
512 NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NEVER_CHECK_SUBJECT);
513 NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NO_WILDCARDS);
514 NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
515 NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS);
516 NODE_DEFINE_CONSTANT(target, X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS);
517 }
518
RegisterExternalReferences(ExternalReferenceRegistry * registry)519 void X509Certificate::RegisterExternalReferences(
520 ExternalReferenceRegistry* registry) {
521 registry->Register(X509Certificate::Parse);
522 registry->Register(Subject);
523 registry->Register(SubjectAltName);
524 registry->Register(InfoAccess);
525 registry->Register(Issuer);
526 registry->Register(ValidTo);
527 registry->Register(ValidFrom);
528 registry->Register(Fingerprint<EVP_sha1>);
529 registry->Register(Fingerprint<EVP_sha256>);
530 registry->Register(Fingerprint<EVP_sha512>);
531 registry->Register(KeyUsage);
532 registry->Register(SerialNumber);
533 registry->Register(Pem);
534 registry->Register(Raw);
535 registry->Register(PublicKey);
536 registry->Register(CheckCA);
537 registry->Register(CheckHost);
538 registry->Register(CheckEmail);
539 registry->Register(CheckIP);
540 registry->Register(CheckIssued);
541 registry->Register(CheckPrivateKey);
542 registry->Register(Verify);
543 registry->Register(ToLegacy);
544 registry->Register(GetIssuerCert);
545 }
546 } // namespace crypto
547 } // namespace node
548