1 #include "crypto/crypto_common.h"
2 #include "base_object-inl.h"
3 #include "env-inl.h"
4 #include "memory_tracker-inl.h"
5 #include "node.h"
6 #include "node_buffer.h"
7 #include "node_crypto.h"
8 #include "node_internals.h"
9 #include "string_bytes.h"
10 #include "v8.h"
11
12 #include <openssl/ec.h>
13 #include <openssl/ecdh.h>
14 #include <openssl/evp.h>
15 #include <openssl/pem.h>
16 #include <openssl/x509v3.h>
17 #include <openssl/hmac.h>
18 #include <openssl/rand.h>
19 #include <openssl/pkcs12.h>
20
21 #include <string>
22 #include <unordered_map>
23
24 namespace node {
25
26 using v8::Array;
27 using v8::ArrayBuffer;
28 using v8::BackingStore;
29 using v8::Boolean;
30 using v8::Context;
31 using v8::EscapableHandleScope;
32 using v8::Integer;
33 using v8::Local;
34 using v8::MaybeLocal;
35 using v8::NewStringType;
36 using v8::Object;
37 using v8::String;
38 using v8::Undefined;
39 using v8::Value;
40
41 namespace crypto {
42 static constexpr int kX509NameFlagsMultiline =
43 ASN1_STRFLGS_ESC_2253 |
44 ASN1_STRFLGS_ESC_CTRL |
45 ASN1_STRFLGS_UTF8_CONVERT |
46 XN_FLAG_SEP_MULTILINE |
47 XN_FLAG_FN_SN;
48
49 static constexpr int kX509NameFlagsRFC2253WithinUtf8JSON =
50 XN_FLAG_RFC2253 &
51 ~ASN1_STRFLGS_ESC_MSB &
52 ~ASN1_STRFLGS_ESC_CTRL;
53
SSL_CTX_get_issuer(SSL_CTX * ctx,X509 * cert)54 X509Pointer SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert) {
55 X509_STORE* store = SSL_CTX_get_cert_store(ctx);
56 DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
57 X509_STORE_CTX_new());
58 X509Pointer result;
59 X509* issuer;
60 if (store_ctx.get() != nullptr &&
61 X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 &&
62 X509_STORE_CTX_get1_issuer(&issuer, store_ctx.get(), cert) == 1) {
63 result.reset(issuer);
64 }
65 return result;
66 }
67
LogSecret(const SSLPointer & ssl,const char * name,const unsigned char * secret,size_t secretlen)68 void LogSecret(
69 const SSLPointer& ssl,
70 const char* name,
71 const unsigned char* secret,
72 size_t secretlen) {
73 auto keylog_cb = SSL_CTX_get_keylog_callback(SSL_get_SSL_CTX(ssl.get()));
74 // All supported versions of TLS/SSL fix the client random to the same size.
75 constexpr size_t kTlsClientRandomSize = SSL3_RANDOM_SIZE;
76 unsigned char crandom[kTlsClientRandomSize];
77
78 if (keylog_cb == nullptr ||
79 SSL_get_client_random(ssl.get(), crandom, kTlsClientRandomSize) !=
80 kTlsClientRandomSize) {
81 return;
82 }
83
84 std::string line = name;
85 line += " " + StringBytes::hex_encode(reinterpret_cast<const char*>(crandom),
86 kTlsClientRandomSize);
87 line += " " + StringBytes::hex_encode(
88 reinterpret_cast<const char*>(secret), secretlen);
89 keylog_cb(ssl.get(), line.c_str());
90 }
91
GetSSLOCSPResponse(Environment * env,SSL * ssl,Local<Value> default_value)92 MaybeLocal<Value> GetSSLOCSPResponse(
93 Environment* env,
94 SSL* ssl,
95 Local<Value> default_value) {
96 const unsigned char* resp;
97 int len = SSL_get_tlsext_status_ocsp_resp(ssl, &resp);
98 if (resp == nullptr)
99 return default_value;
100
101 Local<Value> ret;
102 MaybeLocal<Object> maybe_buffer =
103 Buffer::Copy(env, reinterpret_cast<const char*>(resp), len);
104
105 if (!maybe_buffer.ToLocal(&ret))
106 return MaybeLocal<Value>();
107
108 return ret;
109 }
110
SetTLSSession(const SSLPointer & ssl,const SSLSessionPointer & session)111 bool SetTLSSession(
112 const SSLPointer& ssl,
113 const SSLSessionPointer& session) {
114 return session != nullptr && SSL_set_session(ssl.get(), session.get()) == 1;
115 }
116
GetTLSSession(const unsigned char * buf,size_t length)117 SSLSessionPointer GetTLSSession(const unsigned char* buf, size_t length) {
118 return SSLSessionPointer(d2i_SSL_SESSION(nullptr, &buf, length));
119 }
120
VerifyPeerCertificate(const SSLPointer & ssl,long def)121 long VerifyPeerCertificate( // NOLINT(runtime/int)
122 const SSLPointer& ssl,
123 long def) { // NOLINT(runtime/int)
124 long err = def; // NOLINT(runtime/int)
125 if (X509* peer_cert = SSL_get_peer_certificate(ssl.get())) {
126 X509_free(peer_cert);
127 err = SSL_get_verify_result(ssl.get());
128 } else {
129 const SSL_CIPHER* curr_cipher = SSL_get_current_cipher(ssl.get());
130 const SSL_SESSION* sess = SSL_get_session(ssl.get());
131 // Allow no-cert for PSK authentication in TLS1.2 and lower.
132 // In TLS1.3 check that session was reused because TLS1.3 PSK
133 // looks like session resumption.
134 if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk ||
135 (SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION &&
136 SSL_session_reused(ssl.get()))) {
137 return X509_V_OK;
138 }
139 }
140 return err;
141 }
142
UseSNIContext(const SSLPointer & ssl,BaseObjectPtr<SecureContext> context)143 bool UseSNIContext(
144 const SSLPointer& ssl, BaseObjectPtr<SecureContext> context) {
145 SSL_CTX* ctx = context->ctx().get();
146 X509* x509 = SSL_CTX_get0_certificate(ctx);
147 EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx);
148 STACK_OF(X509)* chain;
149
150 int err = SSL_CTX_get0_chain_certs(ctx, &chain);
151 if (err == 1) err = SSL_use_certificate(ssl.get(), x509);
152 if (err == 1) err = SSL_use_PrivateKey(ssl.get(), pkey);
153 if (err == 1 && chain != nullptr) err = SSL_set1_chain(ssl.get(), chain);
154 return err == 1;
155 }
156
GetClientHelloALPN(const SSLPointer & ssl)157 const char* GetClientHelloALPN(const SSLPointer& ssl) {
158 const unsigned char* buf;
159 size_t len;
160 size_t rem;
161
162 if (!SSL_client_hello_get0_ext(
163 ssl.get(),
164 TLSEXT_TYPE_application_layer_protocol_negotiation,
165 &buf,
166 &rem) ||
167 rem < 2) {
168 return nullptr;
169 }
170
171 len = (buf[0] << 8) | buf[1];
172 if (len + 2 != rem) return nullptr;
173 return reinterpret_cast<const char*>(buf + 3);
174 }
175
GetClientHelloServerName(const SSLPointer & ssl)176 const char* GetClientHelloServerName(const SSLPointer& ssl) {
177 const unsigned char* buf;
178 size_t len;
179 size_t rem;
180
181 if (!SSL_client_hello_get0_ext(
182 ssl.get(),
183 TLSEXT_TYPE_server_name,
184 &buf,
185 &rem) || rem <= 2) {
186 return nullptr;
187 }
188
189 len = (*buf << 8) | *(buf + 1);
190 if (len + 2 != rem)
191 return nullptr;
192 rem = len;
193
194 if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return nullptr;
195 rem--;
196 if (rem <= 2)
197 return nullptr;
198 len = (*(buf + 3) << 8) | *(buf + 4);
199 if (len + 2 > rem)
200 return nullptr;
201 return reinterpret_cast<const char*>(buf + 5);
202 }
203
GetServerName(SSL * ssl)204 const char* GetServerName(SSL* ssl) {
205 return SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
206 }
207
SetGroups(SecureContext * sc,const char * groups)208 bool SetGroups(SecureContext* sc, const char* groups) {
209 return SSL_CTX_set1_groups_list(sc->ctx().get(), groups) == 1;
210 }
211
X509ErrorCode(long err)212 const char* X509ErrorCode(long err) { // NOLINT(runtime/int)
213 const char* code = "UNSPECIFIED";
214 #define CASE_X509_ERR(CODE) case X509_V_ERR_##CODE: code = #CODE; break;
215 switch (err) {
216 // if you modify anything in here, *please* update the respective section in
217 // doc/api/tls.md as well
218 CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT)
219 CASE_X509_ERR(UNABLE_TO_GET_CRL)
220 CASE_X509_ERR(UNABLE_TO_DECRYPT_CERT_SIGNATURE)
221 CASE_X509_ERR(UNABLE_TO_DECRYPT_CRL_SIGNATURE)
222 CASE_X509_ERR(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY)
223 CASE_X509_ERR(CERT_SIGNATURE_FAILURE)
224 CASE_X509_ERR(CRL_SIGNATURE_FAILURE)
225 CASE_X509_ERR(CERT_NOT_YET_VALID)
226 CASE_X509_ERR(CERT_HAS_EXPIRED)
227 CASE_X509_ERR(CRL_NOT_YET_VALID)
228 CASE_X509_ERR(CRL_HAS_EXPIRED)
229 CASE_X509_ERR(ERROR_IN_CERT_NOT_BEFORE_FIELD)
230 CASE_X509_ERR(ERROR_IN_CERT_NOT_AFTER_FIELD)
231 CASE_X509_ERR(ERROR_IN_CRL_LAST_UPDATE_FIELD)
232 CASE_X509_ERR(ERROR_IN_CRL_NEXT_UPDATE_FIELD)
233 CASE_X509_ERR(OUT_OF_MEM)
234 CASE_X509_ERR(DEPTH_ZERO_SELF_SIGNED_CERT)
235 CASE_X509_ERR(SELF_SIGNED_CERT_IN_CHAIN)
236 CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
237 CASE_X509_ERR(UNABLE_TO_VERIFY_LEAF_SIGNATURE)
238 CASE_X509_ERR(CERT_CHAIN_TOO_LONG)
239 CASE_X509_ERR(CERT_REVOKED)
240 CASE_X509_ERR(INVALID_CA)
241 CASE_X509_ERR(PATH_LENGTH_EXCEEDED)
242 CASE_X509_ERR(INVALID_PURPOSE)
243 CASE_X509_ERR(CERT_UNTRUSTED)
244 CASE_X509_ERR(CERT_REJECTED)
245 CASE_X509_ERR(HOSTNAME_MISMATCH)
246 }
247 #undef CASE_X509_ERR
248 return code;
249 }
250
GetValidationErrorReason(Environment * env,int err)251 MaybeLocal<Value> GetValidationErrorReason(Environment* env, int err) {
252 if (err == 0)
253 return Undefined(env->isolate());
254 const char* reason = X509_verify_cert_error_string(err);
255 return OneByteString(env->isolate(), reason);
256 }
257
GetValidationErrorCode(Environment * env,int err)258 MaybeLocal<Value> GetValidationErrorCode(Environment* env, int err) {
259 if (err == 0)
260 return Undefined(env->isolate());
261 return OneByteString(env->isolate(), X509ErrorCode(err));
262 }
263
GetCert(Environment * env,const SSLPointer & ssl)264 MaybeLocal<Value> GetCert(Environment* env, const SSLPointer& ssl) {
265 ClearErrorOnReturn clear_error_on_return;
266 X509* cert = SSL_get_certificate(ssl.get());
267 if (cert == nullptr)
268 return Undefined(env->isolate());
269
270 MaybeLocal<Object> maybe_cert = X509ToObject(env, cert);
271 return maybe_cert.FromMaybe<Value>(Local<Value>());
272 }
273
ToV8Value(Environment * env,const BIOPointer & bio)274 Local<Value> ToV8Value(Environment* env, const BIOPointer& bio) {
275 BUF_MEM* mem;
276 BIO_get_mem_ptr(bio.get(), &mem);
277 MaybeLocal<String> ret =
278 String::NewFromUtf8(
279 env->isolate(),
280 mem->data,
281 NewStringType::kNormal,
282 mem->length);
283 CHECK_EQ(BIO_reset(bio.get()), 1);
284 return ret.FromMaybe(Local<Value>());
285 }
286
287 namespace {
288 template <typename T>
Set(Local<Context> context,Local<Object> target,Local<Value> name,MaybeLocal<T> maybe_value)289 bool Set(
290 Local<Context> context,
291 Local<Object> target,
292 Local<Value> name,
293 MaybeLocal<T> maybe_value) {
294 Local<Value> value;
295 if (!maybe_value.ToLocal(&value))
296 return false;
297
298 // Undefined is ignored, but still considered successful
299 if (value->IsUndefined())
300 return true;
301
302 return !target->Set(context, name, value).IsNothing();
303 }
304
305 template <const char* (*getstr)(const SSL_CIPHER* cipher)>
GetCipherValue(Environment * env,const SSL_CIPHER * cipher)306 MaybeLocal<Value> GetCipherValue(Environment* env, const SSL_CIPHER* cipher) {
307 if (cipher == nullptr)
308 return Undefined(env->isolate());
309
310 return OneByteString(env->isolate(), getstr(cipher));
311 }
312
313 constexpr auto GetCipherName = GetCipherValue<SSL_CIPHER_get_name>;
314 constexpr auto GetCipherStandardName = GetCipherValue<SSL_CIPHER_standard_name>;
315 constexpr auto GetCipherVersion = GetCipherValue<SSL_CIPHER_get_version>;
316
CloneSSLCerts(X509Pointer && cert,const STACK_OF (X509)* const ssl_certs)317 StackOfX509 CloneSSLCerts(X509Pointer&& cert,
318 const STACK_OF(X509)* const ssl_certs) {
319 StackOfX509 peer_certs(sk_X509_new(nullptr));
320 if (!peer_certs) return StackOfX509();
321 if (cert && !sk_X509_push(peer_certs.get(), cert.release()))
322 return StackOfX509();
323 for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
324 X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i)));
325 if (!cert || !sk_X509_push(peer_certs.get(), cert.get()))
326 return StackOfX509();
327 // `cert` is now managed by the stack.
328 cert.release();
329 }
330 return peer_certs;
331 }
332
AddIssuerChainToObject(X509Pointer * cert,Local<Object> object,StackOfX509 && peer_certs,Environment * const env)333 MaybeLocal<Object> AddIssuerChainToObject(
334 X509Pointer* cert,
335 Local<Object> object,
336 StackOfX509&& peer_certs,
337 Environment* const env) {
338 Local<Context> context = env->isolate()->GetCurrentContext();
339 cert->reset(sk_X509_delete(peer_certs.get(), 0));
340 for (;;) {
341 int i;
342 for (i = 0; i < sk_X509_num(peer_certs.get()); i++) {
343 X509* ca = sk_X509_value(peer_certs.get(), i);
344 if (X509_check_issued(ca, cert->get()) != X509_V_OK)
345 continue;
346
347 Local<Object> ca_info;
348 MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca);
349 if (!maybe_ca_info.ToLocal(&ca_info))
350 return MaybeLocal<Object>();
351
352 if (!Set<Object>(context, object, env->issuercert_string(), ca_info))
353 return MaybeLocal<Object>();
354 object = ca_info;
355
356 // NOTE: Intentionally freeing cert that is not used anymore.
357 // Delete cert and continue aggregating issuers.
358 cert->reset(sk_X509_delete(peer_certs.get(), i));
359 break;
360 }
361
362 // Issuer not found, break out of the loop.
363 if (i == sk_X509_num(peer_certs.get()))
364 break;
365 }
366 return MaybeLocal<Object>(object);
367 }
368
GetLastIssuedCert(X509Pointer * cert,const SSLPointer & ssl,Local<Object> issuer_chain,Environment * const env)369 MaybeLocal<Object> GetLastIssuedCert(
370 X509Pointer* cert,
371 const SSLPointer& ssl,
372 Local<Object> issuer_chain,
373 Environment* const env) {
374 Local<Context> context = env->isolate()->GetCurrentContext();
375 while (X509_check_issued(cert->get(), cert->get()) != X509_V_OK) {
376 X509Pointer ca;
377 if (!(ca = SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get())))
378 break;
379
380 Local<Object> ca_info;
381 MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca.get());
382 if (!maybe_ca_info.ToLocal(&ca_info))
383 return MaybeLocal<Object>();
384
385 if (!Set<Object>(context, issuer_chain, env->issuercert_string(), ca_info))
386 return MaybeLocal<Object>();
387 issuer_chain = ca_info;
388
389 // For self-signed certificates whose keyUsage field does not include
390 // keyCertSign, X509_check_issued() will return false. Avoid going into an
391 // infinite loop by checking if SSL_CTX_get_issuer() returned the same
392 // certificate.
393 if (cert->get() == ca.get()) break;
394
395 // Delete previous cert and continue aggregating issuers.
396 *cert = std::move(ca);
397 }
398 return MaybeLocal<Object>(issuer_chain);
399 }
400
AddFingerprintDigest(const unsigned char * md,unsigned int md_size,char fingerprint[3* EVP_MAX_MD_SIZE])401 void AddFingerprintDigest(
402 const unsigned char* md,
403 unsigned int md_size,
404 char fingerprint[3 * EVP_MAX_MD_SIZE]) {
405 unsigned int i;
406 const char hex[] = "0123456789ABCDEF";
407
408 for (i = 0; i < md_size; i++) {
409 fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
410 fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
411 fingerprint[(3*i)+2] = ':';
412 }
413
414 DCHECK_GT(md_size, 0);
415 fingerprint[(3 * (md_size - 1)) + 2] = '\0';
416 }
417
418 template <const char* (*nid2string)(int nid)>
GetCurveName(Environment * env,const int nid)419 MaybeLocal<Value> GetCurveName(Environment* env, const int nid) {
420 const char* name = nid2string(nid);
421 return name != nullptr ?
422 MaybeLocal<Value>(OneByteString(env->isolate(), name)) :
423 MaybeLocal<Value>(Undefined(env->isolate()));
424 }
425
GetECPubKey(Environment * env,const EC_GROUP * group,const ECPointer & ec)426 MaybeLocal<Value> GetECPubKey(
427 Environment* env,
428 const EC_GROUP* group,
429 const ECPointer& ec) {
430 const EC_POINT* pubkey = EC_KEY_get0_public_key(ec.get());
431 if (pubkey == nullptr)
432 return Undefined(env->isolate());
433
434 return ECPointToBuffer(
435 env,
436 group,
437 pubkey,
438 EC_KEY_get_conv_form(ec.get()),
439 nullptr).FromMaybe(Local<Object>());
440 }
441
GetECGroup(Environment * env,const EC_GROUP * group,const ECPointer & ec)442 MaybeLocal<Value> GetECGroup(
443 Environment* env,
444 const EC_GROUP* group,
445 const ECPointer& ec) {
446 if (group == nullptr)
447 return Undefined(env->isolate());
448
449 int bits = EC_GROUP_order_bits(group);
450 if (bits <= 0)
451 return Undefined(env->isolate());
452
453 return Integer::New(env->isolate(), bits);
454 }
455
GetPubKey(Environment * env,const RSAPointer & rsa)456 MaybeLocal<Object> GetPubKey(Environment* env, const RSAPointer& rsa) {
457 int size = i2d_RSA_PUBKEY(rsa.get(), nullptr);
458 CHECK_GE(size, 0);
459
460 std::unique_ptr<BackingStore> bs;
461 {
462 NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
463 bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
464 }
465
466 unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
467 CHECK_GE(i2d_RSA_PUBKEY(rsa.get(), &serialized), 0);
468
469 Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
470 return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
471 }
472
GetExponentString(Environment * env,const BIOPointer & bio,const BIGNUM * e)473 MaybeLocal<Value> GetExponentString(
474 Environment* env,
475 const BIOPointer& bio,
476 const BIGNUM* e) {
477 uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
478 BIO_printf(bio.get(), "0x%" PRIx64, exponent_word);
479 return ToV8Value(env, bio);
480 }
481
GetBits(Environment * env,const BIGNUM * n)482 Local<Value> GetBits(Environment* env, const BIGNUM* n) {
483 return Integer::New(env->isolate(), BN_num_bits(n));
484 }
485
GetModulusString(Environment * env,const BIOPointer & bio,const BIGNUM * n)486 MaybeLocal<Value> GetModulusString(
487 Environment* env,
488 const BIOPointer& bio,
489 const BIGNUM* n) {
490 BN_print(bio.get(), n);
491 return ToV8Value(env, bio);
492 }
493 } // namespace
494
GetRawDERCertificate(Environment * env,X509 * cert)495 MaybeLocal<Value> GetRawDERCertificate(Environment* env, X509* cert) {
496 int size = i2d_X509(cert, nullptr);
497
498 std::unique_ptr<BackingStore> bs;
499 {
500 NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
501 bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
502 }
503
504 unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
505 CHECK_GE(i2d_X509(cert, &serialized), 0);
506
507 Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
508 return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
509 }
510
GetSerialNumber(Environment * env,X509 * cert)511 MaybeLocal<Value> GetSerialNumber(Environment* env, X509* cert) {
512 if (ASN1_INTEGER* serial_number = X509_get_serialNumber(cert)) {
513 BignumPointer bn(ASN1_INTEGER_to_BN(serial_number, nullptr));
514 if (bn) {
515 char* data = BN_bn2hex(bn.get());
516 ByteSource buf = ByteSource::Allocated(data, strlen(data));
517 if (buf) return OneByteString(env->isolate(), buf.data<unsigned char>());
518 }
519 }
520
521 return Undefined(env->isolate());
522 }
523
GetKeyUsage(Environment * env,X509 * cert)524 MaybeLocal<Value> GetKeyUsage(Environment* env, X509* cert) {
525 StackOfASN1 eku(static_cast<STACK_OF(ASN1_OBJECT)*>(
526 X509_get_ext_d2i(cert, NID_ext_key_usage, nullptr, nullptr)));
527 if (eku) {
528 const int count = sk_ASN1_OBJECT_num(eku.get());
529 MaybeStackBuffer<Local<Value>, 16> ext_key_usage(count);
530 char buf[256];
531
532 int j = 0;
533 for (int i = 0; i < count; i++) {
534 if (OBJ_obj2txt(buf,
535 sizeof(buf),
536 sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) {
537 ext_key_usage[j++] = OneByteString(env->isolate(), buf);
538 }
539 }
540
541 return Array::New(env->isolate(), ext_key_usage.out(), count);
542 }
543
544 return Undefined(env->isolate());
545 }
546
GetCurrentCipherName(Environment * env,const SSLPointer & ssl)547 MaybeLocal<Value> GetCurrentCipherName(Environment* env,
548 const SSLPointer& ssl) {
549 return GetCipherName(env, SSL_get_current_cipher(ssl.get()));
550 }
551
GetCurrentCipherVersion(Environment * env,const SSLPointer & ssl)552 MaybeLocal<Value> GetCurrentCipherVersion(Environment* env,
553 const SSLPointer& ssl) {
554 return GetCipherVersion(env, SSL_get_current_cipher(ssl.get()));
555 }
556
GetFingerprintDigest(Environment * env,const EVP_MD * method,X509 * cert)557 MaybeLocal<Value> GetFingerprintDigest(
558 Environment* env,
559 const EVP_MD* method,
560 X509* cert) {
561 unsigned char md[EVP_MAX_MD_SIZE];
562 unsigned int md_size;
563 char fingerprint[EVP_MAX_MD_SIZE * 3];
564
565 if (X509_digest(cert, method, md, &md_size)) {
566 AddFingerprintDigest(md, md_size, fingerprint);
567 return OneByteString(env->isolate(), fingerprint);
568 }
569 return Undefined(env->isolate());
570 }
571
GetValidTo(Environment * env,X509 * cert,const BIOPointer & bio)572 MaybeLocal<Value> GetValidTo(
573 Environment* env,
574 X509* cert,
575 const BIOPointer& bio) {
576 ASN1_TIME_print(bio.get(), X509_get0_notAfter(cert));
577 return ToV8Value(env, bio);
578 }
579
GetValidFrom(Environment * env,X509 * cert,const BIOPointer & bio)580 MaybeLocal<Value> GetValidFrom(
581 Environment* env,
582 X509* cert,
583 const BIOPointer& bio) {
584 ASN1_TIME_print(bio.get(), X509_get0_notBefore(cert));
585 return ToV8Value(env, bio);
586 }
587
IsSafeAltName(const char * name,size_t length,bool utf8)588 static inline bool IsSafeAltName(const char* name, size_t length, bool utf8) {
589 for (size_t i = 0; i < length; i++) {
590 char c = name[i];
591 switch (c) {
592 case '"':
593 case '\\':
594 // These mess with encoding rules.
595 // Fall through.
596 case ',':
597 // Commas make it impossible to split the list of subject alternative
598 // names unambiguously, which is why we have to escape.
599 // Fall through.
600 case '\'':
601 // Single quotes are unlikely to appear in any legitimate values, but they
602 // could be used to make a value look like it was escaped (i.e., enclosed
603 // in single/double quotes).
604 return false;
605 default:
606 if (utf8) {
607 // In UTF8 strings, we require escaping for any ASCII control character,
608 // but NOT for non-ASCII characters. Note that all bytes of any code
609 // point that consists of more than a single byte have their MSB set.
610 if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
611 return false;
612 }
613 } else {
614 // Check if the char is a control character or non-ASCII character. Note
615 // that char may or may not be a signed type. Regardless, non-ASCII
616 // values will always be outside of this range.
617 if (c < ' ' || c > '~') {
618 return false;
619 }
620 }
621 }
622 }
623 return true;
624 }
625
PrintAltName(const BIOPointer & out,const char * name,size_t length,bool utf8,const char * safe_prefix)626 static inline void PrintAltName(const BIOPointer& out, const char* name,
627 size_t length, bool utf8,
628 const char* safe_prefix) {
629 if (IsSafeAltName(name, length, utf8)) {
630 // For backward-compatibility, append "safe" names without any
631 // modifications.
632 if (safe_prefix != nullptr) {
633 BIO_printf(out.get(), "%s:", safe_prefix);
634 }
635 BIO_write(out.get(), name, length);
636 } else {
637 // If a name is not "safe", we cannot embed it without special
638 // encoding. This does not usually happen, but we don't want to hide
639 // it from the user either. We use JSON compatible escaping here.
640 BIO_write(out.get(), "\"", 1);
641 if (safe_prefix != nullptr) {
642 BIO_printf(out.get(), "%s:", safe_prefix);
643 }
644 for (size_t j = 0; j < length; j++) {
645 char c = static_cast<char>(name[j]);
646 if (c == '\\') {
647 BIO_write(out.get(), "\\\\", 2);
648 } else if (c == '"') {
649 BIO_write(out.get(), "\\\"", 2);
650 } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) {
651 // Note that the above condition explicitly excludes commas, which means
652 // that those are encoded as Unicode escape sequences in the "else"
653 // block. That is not strictly necessary, and Node.js itself would parse
654 // it correctly either way. We only do this to account for third-party
655 // code that might be splitting the string at commas (as Node.js itself
656 // used to do).
657 BIO_write(out.get(), &c, 1);
658 } else {
659 // Control character or non-ASCII character. We treat everything as
660 // Latin-1, which corresponds to the first 255 Unicode code points.
661 const char hex[] = "0123456789abcdef";
662 char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] };
663 BIO_write(out.get(), u, sizeof(u));
664 }
665 }
666 BIO_write(out.get(), "\"", 1);
667 }
668 }
669
PrintLatin1AltName(const BIOPointer & out,const ASN1_IA5STRING * name,const char * safe_prefix=nullptr)670 static inline void PrintLatin1AltName(const BIOPointer& out,
671 const ASN1_IA5STRING* name,
672 const char* safe_prefix = nullptr) {
673 PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
674 false, safe_prefix);
675 }
676
PrintUtf8AltName(const BIOPointer & out,const ASN1_UTF8STRING * name,const char * safe_prefix=nullptr)677 static inline void PrintUtf8AltName(const BIOPointer& out,
678 const ASN1_UTF8STRING* name,
679 const char* safe_prefix = nullptr) {
680 PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
681 true, safe_prefix);
682 }
683
684 // This function emulates the behavior of i2v_GENERAL_NAME in a safer and less
685 // ambiguous way. "othername:" entries use the GENERAL_NAME_print format.
PrintGeneralName(const BIOPointer & out,const GENERAL_NAME * gen)686 static bool PrintGeneralName(const BIOPointer& out, const GENERAL_NAME* gen) {
687 if (gen->type == GEN_DNS) {
688 ASN1_IA5STRING* name = gen->d.dNSName;
689 BIO_write(out.get(), "DNS:", 4);
690 // Note that the preferred name syntax (see RFCs 5280 and 1034) with
691 // wildcards is a subset of what we consider "safe", so spec-compliant DNS
692 // names will never need to be escaped.
693 PrintLatin1AltName(out, name);
694 } else if (gen->type == GEN_EMAIL) {
695 ASN1_IA5STRING* name = gen->d.rfc822Name;
696 BIO_write(out.get(), "email:", 6);
697 PrintLatin1AltName(out, name);
698 } else if (gen->type == GEN_URI) {
699 ASN1_IA5STRING* name = gen->d.uniformResourceIdentifier;
700 BIO_write(out.get(), "URI:", 4);
701 // The set of "safe" names was designed to include just about any URI,
702 // with a few exceptions, most notably URIs that contains commas (see
703 // RFC 2396). In other words, most legitimate URIs will not require
704 // escaping.
705 PrintLatin1AltName(out, name);
706 } else if (gen->type == GEN_DIRNAME) {
707 // Earlier versions of Node.js used X509_NAME_oneline to print the X509_NAME
708 // object. The format was non standard and should be avoided. The use of
709 // X509_NAME_oneline is discouraged by OpenSSL but was required for backward
710 // compatibility. Conveniently, X509_NAME_oneline produced ASCII and the
711 // output was unlikely to contains commas or other characters that would
712 // require escaping. However, it SHOULD NOT produce ASCII output since an
713 // RFC5280 AttributeValue may be a UTF8String.
714 // Newer versions of Node.js have since switched to X509_NAME_print_ex to
715 // produce a better format at the cost of backward compatibility. The new
716 // format may contain Unicode characters and it is likely to contain commas,
717 // which require escaping. Fortunately, the recently safeguarded function
718 // PrintAltName handles all of that safely.
719 BIO_printf(out.get(), "DirName:");
720 BIOPointer tmp(BIO_new(BIO_s_mem()));
721 CHECK(tmp);
722 if (X509_NAME_print_ex(tmp.get(),
723 gen->d.dirn,
724 0,
725 kX509NameFlagsRFC2253WithinUtf8JSON) < 0) {
726 return false;
727 }
728 char* oline = nullptr;
729 long n_bytes = BIO_get_mem_data(tmp.get(), &oline); // NOLINT(runtime/int)
730 CHECK_GE(n_bytes, 0);
731 CHECK_IMPLIES(n_bytes != 0, oline != nullptr);
732 PrintAltName(out, oline, static_cast<size_t>(n_bytes), true, nullptr);
733 } else if (gen->type == GEN_IPADD) {
734 BIO_printf(out.get(), "IP Address:");
735 const ASN1_OCTET_STRING* ip = gen->d.ip;
736 const unsigned char* b = ip->data;
737 if (ip->length == 4) {
738 BIO_printf(out.get(), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
739 } else if (ip->length == 16) {
740 for (unsigned int j = 0; j < 8; j++) {
741 uint16_t pair = (b[2 * j] << 8) | b[2 * j + 1];
742 BIO_printf(out.get(), (j == 0) ? "%X" : ":%X", pair);
743 }
744 } else {
745 #if OPENSSL_VERSION_MAJOR >= 3
746 BIO_printf(out.get(), "<invalid length=%d>", ip->length);
747 #else
748 BIO_printf(out.get(), "<invalid>");
749 #endif
750 }
751 } else if (gen->type == GEN_RID) {
752 // Unlike OpenSSL's default implementation, never print the OID as text and
753 // instead always print its numeric representation.
754 char oline[256];
755 OBJ_obj2txt(oline, sizeof(oline), gen->d.rid, true);
756 BIO_printf(out.get(), "Registered ID:%s", oline);
757 } else if (gen->type == GEN_OTHERNAME) {
758 // The format that is used here is based on OpenSSL's implementation of
759 // GENERAL_NAME_print (as of OpenSSL 3.0.1). Earlier versions of Node.js
760 // instead produced the same format as i2v_GENERAL_NAME, which was somewhat
761 // awkward, especially when passed to translatePeerCertificate.
762 bool unicode = true;
763 const char* prefix = nullptr;
764 // OpenSSL 1.1.1 does not support othername in GENERAL_NAME_print and may
765 // not define these NIDs.
766 #if OPENSSL_VERSION_MAJOR >= 3
767 int nid = OBJ_obj2nid(gen->d.otherName->type_id);
768 switch (nid) {
769 case NID_id_on_SmtpUTF8Mailbox:
770 prefix = "SmtpUTF8Mailbox";
771 break;
772 case NID_XmppAddr:
773 prefix = "XmppAddr";
774 break;
775 case NID_SRVName:
776 prefix = "SRVName";
777 unicode = false;
778 break;
779 case NID_ms_upn:
780 prefix = "UPN";
781 break;
782 case NID_NAIRealm:
783 prefix = "NAIRealm";
784 break;
785 }
786 #endif // OPENSSL_VERSION_MAJOR >= 3
787 int val_type = gen->d.otherName->value->type;
788 if (prefix == nullptr ||
789 (unicode && val_type != V_ASN1_UTF8STRING) ||
790 (!unicode && val_type != V_ASN1_IA5STRING)) {
791 BIO_printf(out.get(), "othername:<unsupported>");
792 } else {
793 BIO_printf(out.get(), "othername:");
794 if (unicode) {
795 PrintUtf8AltName(out, gen->d.otherName->value->value.utf8string,
796 prefix);
797 } else {
798 PrintLatin1AltName(out, gen->d.otherName->value->value.ia5string,
799 prefix);
800 }
801 }
802 } else if (gen->type == GEN_X400) {
803 // TODO(tniessen): this is what OpenSSL does, implement properly instead
804 BIO_printf(out.get(), "X400Name:<unsupported>");
805 } else if (gen->type == GEN_EDIPARTY) {
806 // TODO(tniessen): this is what OpenSSL does, implement properly instead
807 BIO_printf(out.get(), "EdiPartyName:<unsupported>");
808 } else {
809 // This is safe because X509V3_EXT_d2i would have returned nullptr in this
810 // case already.
811 UNREACHABLE();
812 }
813
814 return true;
815 }
816
SafeX509SubjectAltNamePrint(const BIOPointer & out,X509_EXTENSION * ext)817 bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {
818 const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
819 CHECK(method == X509V3_EXT_get_nid(NID_subject_alt_name));
820
821 GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(ext));
822 if (names == nullptr)
823 return false;
824
825 bool ok = true;
826
827 for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) {
828 GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i);
829
830 if (i != 0)
831 BIO_write(out.get(), ", ", 2);
832
833 if (!(ok = PrintGeneralName(out, gen))) {
834 break;
835 }
836 }
837 sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
838
839 return ok;
840 }
841
SafeX509InfoAccessPrint(const BIOPointer & out,X509_EXTENSION * ext)842 bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
843 const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
844 CHECK(method == X509V3_EXT_get_nid(NID_info_access));
845
846 AUTHORITY_INFO_ACCESS* descs =
847 static_cast<AUTHORITY_INFO_ACCESS*>(X509V3_EXT_d2i(ext));
848 if (descs == nullptr)
849 return false;
850
851 bool ok = true;
852
853 for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) {
854 ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i);
855
856 if (i != 0)
857 BIO_write(out.get(), "\n", 1);
858
859 char objtmp[80];
860 i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method);
861 BIO_printf(out.get(), "%s - ", objtmp);
862 if (!(ok = PrintGeneralName(out, desc->location))) {
863 break;
864 }
865 }
866 sk_ACCESS_DESCRIPTION_pop_free(descs, ACCESS_DESCRIPTION_free);
867
868 #if OPENSSL_VERSION_MAJOR < 3
869 BIO_write(out.get(), "\n", 1);
870 #endif
871
872 return ok;
873 }
874
GetSubjectAltNameString(Environment * env,X509 * cert,const BIOPointer & bio)875 v8::MaybeLocal<v8::Value> GetSubjectAltNameString(Environment* env,
876 X509* cert,
877 const BIOPointer& bio) {
878 int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
879 if (index < 0)
880 return Undefined(env->isolate());
881
882 X509_EXTENSION* ext = X509_get_ext(cert, index);
883 CHECK_NOT_NULL(ext);
884
885 if (!SafeX509SubjectAltNamePrint(bio, ext)) {
886 CHECK_EQ(BIO_reset(bio.get()), 1);
887 return v8::Null(env->isolate());
888 }
889
890 return ToV8Value(env, bio);
891 }
892
GetInfoAccessString(Environment * env,X509 * cert,const BIOPointer & bio)893 v8::MaybeLocal<v8::Value> GetInfoAccessString(Environment* env,
894 X509* cert,
895 const BIOPointer& bio) {
896 int index = X509_get_ext_by_NID(cert, NID_info_access, -1);
897 if (index < 0)
898 return Undefined(env->isolate());
899
900 X509_EXTENSION* ext = X509_get_ext(cert, index);
901 CHECK_NOT_NULL(ext);
902
903 if (!SafeX509InfoAccessPrint(bio, ext)) {
904 CHECK_EQ(BIO_reset(bio.get()), 1);
905 return v8::Null(env->isolate());
906 }
907
908 return ToV8Value(env, bio);
909 }
910
GetIssuerString(Environment * env,X509 * cert,const BIOPointer & bio)911 MaybeLocal<Value> GetIssuerString(Environment* env,
912 X509* cert,
913 const BIOPointer& bio) {
914 X509_NAME* issuer_name = X509_get_issuer_name(cert);
915 if (X509_NAME_print_ex(
916 bio.get(),
917 issuer_name,
918 0,
919 kX509NameFlagsMultiline) <= 0) {
920 CHECK_EQ(BIO_reset(bio.get()), 1);
921 return Undefined(env->isolate());
922 }
923
924 return ToV8Value(env, bio);
925 }
926
GetSubject(Environment * env,X509 * cert,const BIOPointer & bio)927 MaybeLocal<Value> GetSubject(Environment* env,
928 X509* cert,
929 const BIOPointer& bio) {
930 if (X509_NAME_print_ex(
931 bio.get(),
932 X509_get_subject_name(cert),
933 0,
934 kX509NameFlagsMultiline) <= 0) {
935 CHECK_EQ(BIO_reset(bio.get()), 1);
936 return Undefined(env->isolate());
937 }
938
939 return ToV8Value(env, bio);
940 }
941
942 template <X509_NAME* get_name(const X509*)>
GetX509NameObject(Environment * env,X509 * cert)943 static MaybeLocal<Value> GetX509NameObject(Environment* env, X509* cert) {
944 X509_NAME* name = get_name(cert);
945 CHECK_NOT_NULL(name);
946
947 int cnt = X509_NAME_entry_count(name);
948 CHECK_GE(cnt, 0);
949
950 Local<Object> result =
951 Object::New(env->isolate(), Null(env->isolate()), nullptr, nullptr, 0);
952 if (result.IsEmpty()) {
953 return MaybeLocal<Value>();
954 }
955
956 for (int i = 0; i < cnt; i++) {
957 X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, i);
958 CHECK_NOT_NULL(entry);
959
960 // We intentionally ignore the value of X509_NAME_ENTRY_set because the
961 // representation as an object does not allow grouping entries into sets
962 // anyway, and multi-value RDNs are rare, i.e., the vast majority of
963 // Relative Distinguished Names contains a single type-value pair only.
964 const ASN1_OBJECT* type = X509_NAME_ENTRY_get_object(entry);
965 const ASN1_STRING* value = X509_NAME_ENTRY_get_data(entry);
966
967 // If OpenSSL knows the type, use the short name of the type as the key, and
968 // the numeric representation of the type's OID otherwise.
969 int type_nid = OBJ_obj2nid(type);
970 char type_buf[80];
971 const char* type_str;
972 if (type_nid != NID_undef) {
973 type_str = OBJ_nid2sn(type_nid);
974 CHECK_NOT_NULL(type_str);
975 } else {
976 OBJ_obj2txt(type_buf, sizeof(type_buf), type, true);
977 type_str = type_buf;
978 }
979
980 Local<String> v8_name;
981 if (!String::NewFromUtf8(env->isolate(), type_str).ToLocal(&v8_name)) {
982 return MaybeLocal<Value>();
983 }
984
985 // The previous implementation used X509_NAME_print_ex, which escapes some
986 // characters in the value. The old implementation did not decode/unescape
987 // values correctly though, leading to ambiguous and incorrect
988 // representations. The new implementation only converts to Unicode and does
989 // not escape anything.
990 unsigned char* value_str;
991 int value_str_size = ASN1_STRING_to_UTF8(&value_str, value);
992 if (value_str_size < 0) {
993 return Undefined(env->isolate());
994 }
995 auto free_value_str = OnScopeLeave([&]() { OPENSSL_free(value_str); });
996
997 Local<String> v8_value;
998 if (!String::NewFromUtf8(env->isolate(),
999 reinterpret_cast<const char*>(value_str),
1000 NewStringType::kNormal,
1001 value_str_size)
1002 .ToLocal(&v8_value)) {
1003 return MaybeLocal<Value>();
1004 }
1005
1006 // For backward compatibility, we only create arrays if multiple values
1007 // exist for the same key. That is not great but there is not much we can
1008 // change here without breaking things. Note that this creates nested data
1009 // structures, yet still does not allow representing Distinguished Names
1010 // accurately.
1011 bool multiple;
1012 if (!result->HasOwnProperty(env->context(), v8_name).To(&multiple)) {
1013 return MaybeLocal<Value>();
1014 } else if (multiple) {
1015 Local<Value> accum;
1016 if (!result->Get(env->context(), v8_name).ToLocal(&accum)) {
1017 return MaybeLocal<Value>();
1018 }
1019 if (!accum->IsArray()) {
1020 accum = Array::New(env->isolate(), &accum, 1);
1021 if (result->Set(env->context(), v8_name, accum).IsNothing()) {
1022 return MaybeLocal<Value>();
1023 }
1024 }
1025 Local<Array> array = accum.As<Array>();
1026 if (array->Set(env->context(), array->Length(), v8_value).IsNothing()) {
1027 return MaybeLocal<Value>();
1028 }
1029 } else if (result->Set(env->context(), v8_name, v8_value).IsNothing()) {
1030 return MaybeLocal<Value>();
1031 }
1032 }
1033
1034 return result;
1035 }
1036
1037 template <MaybeLocal<Value> (*Get)(Environment* env, const SSL_CIPHER* cipher)>
GetCurrentCipherValue(Environment * env,const SSLPointer & ssl)1038 MaybeLocal<Value> GetCurrentCipherValue(Environment* env,
1039 const SSLPointer& ssl) {
1040 return Get(env, SSL_get_current_cipher(ssl.get()));
1041 }
1042
GetClientHelloCiphers(Environment * env,const SSLPointer & ssl)1043 MaybeLocal<Array> GetClientHelloCiphers(
1044 Environment* env,
1045 const SSLPointer& ssl) {
1046 EscapableHandleScope scope(env->isolate());
1047 const unsigned char* buf;
1048 size_t len = SSL_client_hello_get0_ciphers(ssl.get(), &buf);
1049 size_t count = len / 2;
1050 MaybeStackBuffer<Local<Value>, 16> ciphers(count);
1051 int j = 0;
1052 for (size_t n = 0; n < len; n += 2) {
1053 const SSL_CIPHER* cipher = SSL_CIPHER_find(ssl.get(), buf);
1054 buf += 2;
1055 Local<Object> obj = Object::New(env->isolate());
1056 if (!Set(env->context(),
1057 obj,
1058 env->name_string(),
1059 GetCipherName(env, cipher)) ||
1060 !Set(env->context(),
1061 obj,
1062 env->standard_name_string(),
1063 GetCipherStandardName(env, cipher)) ||
1064 !Set(env->context(),
1065 obj,
1066 env->version_string(),
1067 GetCipherVersion(env, cipher))) {
1068 return MaybeLocal<Array>();
1069 }
1070 ciphers[j++] = obj;
1071 }
1072 Local<Array> ret = Array::New(env->isolate(), ciphers.out(), count);
1073 return scope.Escape(ret);
1074 }
1075
1076
GetCipherInfo(Environment * env,const SSLPointer & ssl)1077 MaybeLocal<Object> GetCipherInfo(Environment* env, const SSLPointer& ssl) {
1078 if (SSL_get_current_cipher(ssl.get()) == nullptr)
1079 return MaybeLocal<Object>();
1080 EscapableHandleScope scope(env->isolate());
1081 Local<Object> info = Object::New(env->isolate());
1082
1083 if (!Set<Value>(env->context(),
1084 info,
1085 env->name_string(),
1086 GetCurrentCipherValue<GetCipherName>(env, ssl)) ||
1087 !Set<Value>(env->context(),
1088 info,
1089 env->standard_name_string(),
1090 GetCurrentCipherValue<GetCipherStandardName>(env, ssl)) ||
1091 !Set<Value>(env->context(),
1092 info,
1093 env->version_string(),
1094 GetCurrentCipherValue<GetCipherVersion>(env, ssl))) {
1095 return MaybeLocal<Object>();
1096 }
1097
1098 return scope.Escape(info);
1099 }
1100
GetEphemeralKey(Environment * env,const SSLPointer & ssl)1101 MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1102 CHECK_EQ(SSL_is_server(ssl.get()), 0);
1103 EVP_PKEY* raw_key;
1104
1105 EscapableHandleScope scope(env->isolate());
1106 Local<Object> info = Object::New(env->isolate());
1107 if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1108 return scope.Escape(info);
1109
1110 Local<Context> context = env->context();
1111 crypto::EVPKeyPointer key(raw_key);
1112
1113 int kid = EVP_PKEY_id(key.get());
1114 int bits = EVP_PKEY_bits(key.get());
1115 switch (kid) {
1116 case EVP_PKEY_DH:
1117 if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1118 !Set<Integer>(context,
1119 info,
1120 env->size_string(),
1121 Integer::New(env->isolate(), bits))) {
1122 return MaybeLocal<Object>();
1123 }
1124 break;
1125 case EVP_PKEY_EC:
1126 case EVP_PKEY_X25519:
1127 case EVP_PKEY_X448:
1128 {
1129 const char* curve_name;
1130 if (kid == EVP_PKEY_EC) {
1131 ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1132 int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1133 curve_name = OBJ_nid2sn(nid);
1134 } else {
1135 curve_name = OBJ_nid2sn(kid);
1136 }
1137 if (!Set<String>(context,
1138 info,
1139 env->type_string(),
1140 env->ecdh_string()) ||
1141 !Set<String>(context,
1142 info,
1143 env->name_string(),
1144 OneByteString(env->isolate(), curve_name)) ||
1145 !Set<Integer>(context,
1146 info,
1147 env->size_string(),
1148 Integer::New(env->isolate(), bits))) {
1149 return MaybeLocal<Object>();
1150 }
1151 }
1152 break;
1153 }
1154
1155 return scope.Escape(info);
1156 }
1157
ECPointToBuffer(Environment * env,const EC_GROUP * group,const EC_POINT * point,point_conversion_form_t form,const char ** error)1158 MaybeLocal<Object> ECPointToBuffer(Environment* env,
1159 const EC_GROUP* group,
1160 const EC_POINT* point,
1161 point_conversion_form_t form,
1162 const char** error) {
1163 size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
1164 if (len == 0) {
1165 if (error != nullptr) *error = "Failed to get public key length";
1166 return MaybeLocal<Object>();
1167 }
1168
1169 std::unique_ptr<BackingStore> bs;
1170 {
1171 NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1172 bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
1173 }
1174
1175 len = EC_POINT_point2oct(group,
1176 point,
1177 form,
1178 reinterpret_cast<unsigned char*>(bs->Data()),
1179 bs->ByteLength(),
1180 nullptr);
1181 if (len == 0) {
1182 if (error != nullptr) *error = "Failed to get public key";
1183 return MaybeLocal<Object>();
1184 }
1185
1186 Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
1187 return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
1188 }
1189
GetPeerCert(Environment * env,const SSLPointer & ssl,bool abbreviated,bool is_server)1190 MaybeLocal<Value> GetPeerCert(
1191 Environment* env,
1192 const SSLPointer& ssl,
1193 bool abbreviated,
1194 bool is_server) {
1195 ClearErrorOnReturn clear_error_on_return;
1196 Local<Object> result;
1197 MaybeLocal<Object> maybe_cert;
1198
1199 // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1200 // contains the `peer_certificate`, but on server it doesn't.
1201 X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr);
1202 STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get());
1203 if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
1204 return Undefined(env->isolate());
1205
1206 // Short result requested.
1207 if (abbreviated) {
1208 maybe_cert =
1209 X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0));
1210 return maybe_cert.ToLocal(&result) ? result : MaybeLocal<Value>();
1211 }
1212
1213 StackOfX509 peer_certs = CloneSSLCerts(std::move(cert), ssl_certs);
1214 if (peer_certs == nullptr)
1215 return Undefined(env->isolate());
1216
1217 // First and main certificate.
1218 X509Pointer first_cert(sk_X509_value(peer_certs.get(), 0));
1219 CHECK(first_cert);
1220 maybe_cert = X509ToObject(env, first_cert.release());
1221 if (!maybe_cert.ToLocal(&result))
1222 return MaybeLocal<Value>();
1223
1224 Local<Object> issuer_chain;
1225 MaybeLocal<Object> maybe_issuer_chain;
1226
1227 maybe_issuer_chain =
1228 AddIssuerChainToObject(
1229 &cert,
1230 result,
1231 std::move(peer_certs),
1232 env);
1233 if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1234 return MaybeLocal<Value>();
1235
1236 maybe_issuer_chain =
1237 GetLastIssuedCert(
1238 &cert,
1239 ssl,
1240 issuer_chain,
1241 env);
1242
1243 issuer_chain.Clear();
1244 if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1245 return MaybeLocal<Value>();
1246
1247 // Last certificate should be self-signed.
1248 if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK &&
1249 !Set<Object>(env->context(),
1250 issuer_chain,
1251 env->issuercert_string(),
1252 issuer_chain)) {
1253 return MaybeLocal<Value>();
1254 }
1255
1256 return result;
1257 }
1258
X509ToObject(Environment * env,X509 * cert)1259 MaybeLocal<Object> X509ToObject(
1260 Environment* env,
1261 X509* cert) {
1262 EscapableHandleScope scope(env->isolate());
1263 Local<Context> context = env->context();
1264 Local<Object> info = Object::New(env->isolate());
1265
1266 BIOPointer bio(BIO_new(BIO_s_mem()));
1267 CHECK(bio);
1268
1269 // X509_check_ca() returns a range of values. Only 1 means "is a CA"
1270 auto is_ca = Boolean::New(env->isolate(), 1 == X509_check_ca(cert));
1271 if (!Set<Value>(context,
1272 info,
1273 env->subject_string(),
1274 GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1275 !Set<Value>(context,
1276 info,
1277 env->issuer_string(),
1278 GetX509NameObject<X509_get_issuer_name>(env, cert)) ||
1279 !Set<Value>(context,
1280 info,
1281 env->subjectaltname_string(),
1282 GetSubjectAltNameString(env, cert, bio)) ||
1283 !Set<Value>(context,
1284 info,
1285 env->infoaccess_string(),
1286 GetInfoAccessString(env, cert, bio)) ||
1287 !Set<Boolean>(context, info, env->ca_string(), is_ca)) {
1288 return MaybeLocal<Object>();
1289 }
1290
1291 EVPKeyPointer pkey(X509_get_pubkey(cert));
1292 RSAPointer rsa;
1293 ECPointer ec;
1294 if (pkey) {
1295 switch (EVP_PKEY_id(pkey.get())) {
1296 case EVP_PKEY_RSA:
1297 rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1298 break;
1299 case EVP_PKEY_EC:
1300 ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1301 break;
1302 }
1303 }
1304
1305 if (rsa) {
1306 const BIGNUM* n;
1307 const BIGNUM* e;
1308 RSA_get0_key(rsa.get(), &n, &e, nullptr);
1309 if (!Set<Value>(context,
1310 info,
1311 env->modulus_string(),
1312 GetModulusString(env, bio, n)) ||
1313 !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1314 !Set<Value>(context,
1315 info,
1316 env->exponent_string(),
1317 GetExponentString(env, bio, e)) ||
1318 !Set<Object>(context,
1319 info,
1320 env->pubkey_string(),
1321 GetPubKey(env, rsa))) {
1322 return MaybeLocal<Object>();
1323 }
1324 } else if (ec) {
1325 const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1326
1327 if (!Set<Value>(context,
1328 info,
1329 env->bits_string(),
1330 GetECGroup(env, group, ec)) ||
1331 !Set<Value>(context,
1332 info,
1333 env->pubkey_string(),
1334 GetECPubKey(env, group, ec))) {
1335 return MaybeLocal<Object>();
1336 }
1337
1338 const int nid = EC_GROUP_get_curve_name(group);
1339 if (nid != 0) {
1340 // Curve is well-known, get its OID and NIST nick-name (if it has one).
1341
1342 if (!Set<Value>(context,
1343 info,
1344 env->asn1curve_string(),
1345 GetCurveName<OBJ_nid2sn>(env, nid)) ||
1346 !Set<Value>(context,
1347 info,
1348 env->nistcurve_string(),
1349 GetCurveName<EC_curve_nid2nist>(env, nid))) {
1350 return MaybeLocal<Object>();
1351 }
1352 } else {
1353 // Unnamed curves can be described by their mathematical properties,
1354 // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1355 }
1356 }
1357
1358 // pkey, rsa, and ec pointers are no longer needed.
1359 pkey.reset();
1360 rsa.reset();
1361 ec.reset();
1362
1363 if (!Set<Value>(context,
1364 info,
1365 env->valid_from_string(),
1366 GetValidFrom(env, cert, bio)) ||
1367 !Set<Value>(context,
1368 info,
1369 env->valid_to_string(),
1370 GetValidTo(env, cert, bio))) {
1371 return MaybeLocal<Object>();
1372 }
1373
1374 // bio is no longer needed
1375 bio.reset();
1376
1377 if (!Set<Value>(context,
1378 info,
1379 env->fingerprint_string(),
1380 GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1381 !Set<Value>(context,
1382 info,
1383 env->fingerprint256_string(),
1384 GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1385 !Set<Value>(context,
1386 info,
1387 env->fingerprint512_string(),
1388 GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1389 !Set<Value>(
1390 context, info, env->ext_key_usage_string(), GetKeyUsage(env, cert)) ||
1391 !Set<Value>(context,
1392 info,
1393 env->serial_number_string(),
1394 GetSerialNumber(env, cert)) ||
1395 !Set<Value>(
1396 context, info, env->raw_string(), GetRawDERCertificate(env, cert))) {
1397 return MaybeLocal<Object>();
1398 }
1399
1400 return scope.Escape(info);
1401 }
1402
1403 } // namespace crypto
1404 } // namespace node
1405