• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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