GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_common.cc Lines: 533 703 75.8 %
Date: 2022-01-15 04:15:29 Branches: 282 485 58.1 %

Line Branch Exec Source
1
#include "allocated_buffer-inl.h"
2
#include "base_object-inl.h"
3
#include "env-inl.h"
4
#include "node_buffer.h"
5
#include "node_crypto.h"
6
#include "crypto/crypto_common.h"
7
#include "node.h"
8
#include "node_internals.h"
9
#include "node_url.h"
10
#include "string_bytes.h"
11
#include "memory_tracker-inl.h"
12
#include "v8.h"
13
14
#include <openssl/ec.h>
15
#include <openssl/ecdh.h>
16
#include <openssl/evp.h>
17
#include <openssl/pem.h>
18
#include <openssl/x509v3.h>
19
#include <openssl/hmac.h>
20
#include <openssl/rand.h>
21
#include <openssl/pkcs12.h>
22
23
#include <string>
24
#include <unordered_map>
25
26
namespace node {
27
28
using v8::Array;
29
using v8::ArrayBuffer;
30
using v8::ArrayBufferView;
31
using v8::BackingStore;
32
using v8::Context;
33
using v8::EscapableHandleScope;
34
using v8::Integer;
35
using v8::Local;
36
using v8::MaybeLocal;
37
using v8::NewStringType;
38
using v8::Object;
39
using v8::String;
40
using v8::Undefined;
41
using v8::Value;
42
43
namespace crypto {
44
static constexpr int X509_NAME_FLAGS =
45
    ASN1_STRFLGS_ESC_2253 |
46
    ASN1_STRFLGS_ESC_CTRL |
47
    ASN1_STRFLGS_UTF8_CONVERT |
48
    XN_FLAG_SEP_MULTILINE |
49
    XN_FLAG_FN_SN;
50
51
893
int SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) {
52
893
  X509_STORE* store = SSL_CTX_get_cert_store(ctx);
53
  DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
54
893
      X509_STORE_CTX_new());
55
1786
  return store_ctx.get() != nullptr &&
56

1786
         X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 &&
57
1786
         X509_STORE_CTX_get1_issuer(issuer, store_ctx.get(), cert) == 1;
58
}
59
60
void LogSecret(
61
    const SSLPointer& ssl,
62
    const char* name,
63
    const unsigned char* secret,
64
    size_t secretlen) {
65
  auto keylog_cb = SSL_CTX_get_keylog_callback(SSL_get_SSL_CTX(ssl.get()));
66
  unsigned char crandom[32];
67
68
  if (keylog_cb == nullptr ||
69
      SSL_get_client_random(ssl.get(), crandom, 32) != 32) {
70
    return;
71
  }
72
73
  std::string line = name;
74
  line += " " + StringBytes::hex_encode(
75
      reinterpret_cast<const char*>(crandom), 32);
76
  line += " " + StringBytes::hex_encode(
77
      reinterpret_cast<const char*>(secret), secretlen);
78
  keylog_cb(ssl.get(), line.c_str());
79
}
80
81
bool SetALPN(const SSLPointer& ssl, const std::string& alpn) {
82
  return SSL_set_alpn_protos(
83
      ssl.get(),
84
      reinterpret_cast<const uint8_t*>(alpn.c_str()),
85
      alpn.length()) == 0;
86
}
87
88
39
bool SetALPN(const SSLPointer& ssl, Local<Value> alpn) {
89
39
  if (!alpn->IsArrayBufferView())
90
    return false;
91
39
  ArrayBufferViewContents<unsigned char> protos(alpn.As<ArrayBufferView>());
92
39
  return SSL_set_alpn_protos(ssl.get(), protos.data(), protos.length()) == 0;
93
}
94
95
4
MaybeLocal<Value> GetSSLOCSPResponse(
96
    Environment* env,
97
    SSL* ssl,
98
    Local<Value> default_value) {
99
  const unsigned char* resp;
100
4
  int len = SSL_get_tlsext_status_ocsp_resp(ssl, &resp);
101
4
  if (resp == nullptr)
102
2
    return default_value;
103
104
  Local<Value> ret;
105
  MaybeLocal<Object> maybe_buffer =
106
2
      Buffer::Copy(env, reinterpret_cast<const char*>(resp), len);
107
108
2
  if (!maybe_buffer.ToLocal(&ret))
109
    return MaybeLocal<Value>();
110
111
2
  return ret;
112
}
113
114
bool SetTLSSession(
115
    const SSLPointer& ssl,
116
    const unsigned char* buf,
117
    size_t length) {
118
  SSLSessionPointer s(d2i_SSL_SESSION(nullptr, &buf, length));
119
  return s == nullptr ? false : SetTLSSession(ssl, s);
120
}
121
122
96
bool SetTLSSession(
123
    const SSLPointer& ssl,
124
    const SSLSessionPointer& session) {
125

96
  return session != nullptr && SSL_set_session(ssl.get(), session.get()) == 1;
126
}
127
128
96
SSLSessionPointer GetTLSSession(Local<Value> val) {
129
96
  if (!val->IsArrayBufferView())
130
    return SSLSessionPointer();
131
96
  ArrayBufferViewContents<unsigned char> sbuf(val.As<ArrayBufferView>());
132
96
  return GetTLSSession(sbuf.data(), sbuf.length());
133
}
134
135
96
SSLSessionPointer GetTLSSession(const unsigned char* buf, size_t length) {
136
96
  return SSLSessionPointer(d2i_SSL_SESSION(nullptr, &buf, length));
137
}
138
139
948
long VerifyPeerCertificate(  // NOLINT(runtime/int)
140
    const SSLPointer& ssl,
141
    long def) {  // NOLINT(runtime/int)
142
948
  long err = def;  // NOLINT(runtime/int)
143
948
  if (X509* peer_cert = SSL_get_peer_certificate(ssl.get())) {
144
922
    X509_free(peer_cert);
145
922
    err = SSL_get_verify_result(ssl.get());
146
  } else {
147
26
    const SSL_CIPHER* curr_cipher = SSL_get_current_cipher(ssl.get());
148
26
    const SSL_SESSION* sess = SSL_get_session(ssl.get());
149
    // Allow no-cert for PSK authentication in TLS1.2 and lower.
150
    // In TLS1.3 check that session was reused because TLS1.3 PSK
151
    // looks like session resumption.
152

56
    if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk ||
153
30
        (SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION &&
154
6
         SSL_session_reused(ssl.get()))) {
155
7
      return X509_V_OK;
156
    }
157
  }
158
941
  return err;
159
}
160
161
12
int UseSNIContext(const SSLPointer& ssl, BaseObjectPtr<SecureContext> context) {
162
12
  SSL_CTX* ctx = context->ctx_.get();
163
12
  X509* x509 = SSL_CTX_get0_certificate(ctx);
164
12
  EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx);
165
  STACK_OF(X509)* chain;
166
167
12
  int err = SSL_CTX_get0_chain_certs(ctx, &chain);
168
12
  if (err == 1) err = SSL_use_certificate(ssl.get(), x509);
169
12
  if (err == 1) err = SSL_use_PrivateKey(ssl.get(), pkey);
170

12
  if (err == 1 && chain != nullptr) err = SSL_set1_chain(ssl.get(), chain);
171
12
  return err;
172
}
173
174
const char* GetClientHelloALPN(const SSLPointer& ssl) {
175
  const unsigned char* buf;
176
  size_t len;
177
  size_t rem;
178
179
  if (!SSL_client_hello_get0_ext(
180
          ssl.get(),
181
          TLSEXT_TYPE_application_layer_protocol_negotiation,
182
          &buf,
183
          &rem) ||
184
      rem < 2) {
185
    return nullptr;
186
  }
187
188
  len = (buf[0] << 8) | buf[1];
189
  if (len + 2 != rem) return nullptr;
190
  return reinterpret_cast<const char*>(buf + 3);
191
}
192
193
const char* GetClientHelloServerName(const SSLPointer& ssl) {
194
  const unsigned char* buf;
195
  size_t len;
196
  size_t rem;
197
198
  if (!SSL_client_hello_get0_ext(
199
          ssl.get(),
200
          TLSEXT_TYPE_server_name,
201
          &buf,
202
          &rem) || rem <= 2) {
203
    return nullptr;
204
  }
205
206
  len = (*buf << 8) | *(buf + 1);
207
  if (len + 2 != rem)
208
    return nullptr;
209
  rem = len;
210
211
  if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return nullptr;
212
  rem--;
213
  if (rem <= 2)
214
    return nullptr;
215
  len = (*(buf + 3) << 8) | *(buf + 4);
216
  if (len + 2 > rem)
217
    return nullptr;
218
  return reinterpret_cast<const char*>(buf + 5);
219
}
220
221
25
const char* GetServerName(SSL* ssl) {
222
25
  return SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
223
}
224
225
bool SetGroups(SecureContext* sc, const char* groups) {
226
  return SSL_CTX_set1_groups_list(**sc, groups) == 1;
227
}
228
229
453
const char* X509ErrorCode(long err) {  // NOLINT(runtime/int)
230
453
  const char* code = "UNSPECIFIED";
231
#define CASE_X509_ERR(CODE) case X509_V_ERR_##CODE: code = #CODE; break;
232







453
  switch (err) {
233
    // if you modify anything in here, *please* update the respective section in
234
    // doc/api/tls.md as well
235
19
    CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT)
236
1
    CASE_X509_ERR(UNABLE_TO_GET_CRL)
237
    CASE_X509_ERR(UNABLE_TO_DECRYPT_CERT_SIGNATURE)
238
    CASE_X509_ERR(UNABLE_TO_DECRYPT_CRL_SIGNATURE)
239
    CASE_X509_ERR(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY)
240
    CASE_X509_ERR(CERT_SIGNATURE_FAILURE)
241
    CASE_X509_ERR(CRL_SIGNATURE_FAILURE)
242
    CASE_X509_ERR(CERT_NOT_YET_VALID)
243
    CASE_X509_ERR(CERT_HAS_EXPIRED)
244
    CASE_X509_ERR(CRL_NOT_YET_VALID)
245
    CASE_X509_ERR(CRL_HAS_EXPIRED)
246
    CASE_X509_ERR(ERROR_IN_CERT_NOT_BEFORE_FIELD)
247
    CASE_X509_ERR(ERROR_IN_CERT_NOT_AFTER_FIELD)
248
    CASE_X509_ERR(ERROR_IN_CRL_LAST_UPDATE_FIELD)
249
    CASE_X509_ERR(ERROR_IN_CRL_NEXT_UPDATE_FIELD)
250
    CASE_X509_ERR(OUT_OF_MEM)
251
241
    CASE_X509_ERR(DEPTH_ZERO_SELF_SIGNED_CERT)
252
18
    CASE_X509_ERR(SELF_SIGNED_CERT_IN_CHAIN)
253
4
    CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
254
167
    CASE_X509_ERR(UNABLE_TO_VERIFY_LEAF_SIGNATURE)
255
    CASE_X509_ERR(CERT_CHAIN_TOO_LONG)
256
1
    CASE_X509_ERR(CERT_REVOKED)
257
    CASE_X509_ERR(INVALID_CA)
258
    CASE_X509_ERR(PATH_LENGTH_EXCEEDED)
259
1
    CASE_X509_ERR(INVALID_PURPOSE)
260
    CASE_X509_ERR(CERT_UNTRUSTED)
261
    CASE_X509_ERR(CERT_REJECTED)
262
    CASE_X509_ERR(HOSTNAME_MISMATCH)
263
  }
264
#undef CASE_X509_ERR
265
453
  return code;
266
}
267
268
MaybeLocal<Value> GetValidationErrorReason(Environment* env, int err) {
269
  if (err == 0)
270
    return Undefined(env->isolate());
271
  const char* reason = X509_verify_cert_error_string(err);
272
  return OneByteString(env->isolate(), reason);
273
}
274
275
MaybeLocal<Value> GetValidationErrorCode(Environment* env, int err) {
276
  if (err == 0)
277
    return Undefined(env->isolate());
278
  return OneByteString(env->isolate(), X509ErrorCode(err));
279
}
280
281
12
MaybeLocal<Value> GetCert(Environment* env, const SSLPointer& ssl) {
282
12
  ClearErrorOnReturn clear_error_on_return;
283
12
  X509* cert = SSL_get_certificate(ssl.get());
284
12
  if (cert == nullptr)
285
2
    return Undefined(env->isolate());
286
287
11
  MaybeLocal<Object> maybe_cert = X509ToObject(env, cert);
288
11
  return maybe_cert.FromMaybe<Value>(Local<Value>());
289
}
290
291
4951
Local<Value> ToV8Value(Environment* env, const BIOPointer& bio) {
292
  BUF_MEM* mem;
293
4951
  BIO_get_mem_ptr(bio.get(), &mem);
294
  MaybeLocal<String> ret =
295
      String::NewFromUtf8(
296
          env->isolate(),
297
4951
          mem->data,
298
          NewStringType::kNormal,
299
4951
          mem->length);
300
4951
  USE(BIO_reset(bio.get()));
301
4951
  return ret.FromMaybe(Local<Value>());
302
}
303
304
namespace {
305
template <typename T>
306
46572
bool Set(
307
    Local<Context> context,
308
    Local<Object> target,
309
    Local<Value> name,
310
    MaybeLocal<T> maybe_value) {
311
  Local<Value> value;
312
46572
  if (!maybe_value.ToLocal(&value))
313
    return false;
314
315
  // Undefined is ignored, but still considered successful
316
93144
  if (value->IsUndefined())
317
7038
    return true;
318
319
79068
  return !target->Set(context, name, value).IsNothing();
320
}
321
322
159
MaybeLocal<Value> GetCipherValue(Environment* env,
323
    const SSL_CIPHER* cipher,
324
    const char* (*getstr)(const SSL_CIPHER* cipher)) {
325
159
  if (cipher == nullptr)
326
    return Undefined(env->isolate());
327
328
318
  return OneByteString(env->isolate(), getstr(cipher));
329
}
330
331
53
MaybeLocal<Value> GetCipherName(Environment* env, const SSL_CIPHER* cipher) {
332
53
  return GetCipherValue(env, cipher, SSL_CIPHER_get_name);
333
}
334
335
53
MaybeLocal<Value> GetCipherStandardName(
336
    Environment* env,
337
    const SSL_CIPHER* cipher) {
338
53
  return GetCipherValue(env, cipher, SSL_CIPHER_standard_name);
339
}
340
341
53
MaybeLocal<Value> GetCipherVersion(Environment* env, const SSL_CIPHER* cipher) {
342
53
  return GetCipherValue(env, cipher, SSL_CIPHER_get_version);
343
}
344
345
448
StackOfX509 CloneSSLCerts(X509Pointer&& cert,
346
                          const STACK_OF(X509)* const ssl_certs) {
347
896
  StackOfX509 peer_certs(sk_X509_new(nullptr));
348
448
  if (cert)
349
    sk_X509_push(peer_certs.get(), cert.release());
350
1238
  for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
351
790
    X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i)));
352

790
    if (!cert || !sk_X509_push(peer_certs.get(), cert.get()))
353
      return StackOfX509();
354
    // `cert` is now managed by the stack.
355
790
    cert.release();
356
  }
357
448
  return peer_certs;
358
}
359
360
448
MaybeLocal<Object> AddIssuerChainToObject(
361
    X509Pointer* cert,
362
    Local<Object> object,
363
    StackOfX509&& peer_certs,
364
    Environment* const env) {
365
448
  Local<Context> context = env->isolate()->GetCurrentContext();
366
448
  cert->reset(sk_X509_delete(peer_certs.get(), 0));
367
  for (;;) {
368
    int i;
369
453
    for (i = 0; i < sk_X509_num(peer_certs.get()); i++) {
370
342
      X509* ca = sk_X509_value(peer_certs.get(), i);
371
342
      if (X509_check_issued(ca, cert->get()) != X509_V_OK)
372
2
        continue;
373
374
      Local<Object> ca_info;
375
340
      MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca);
376
340
      if (!maybe_ca_info.ToLocal(&ca_info))
377
        return MaybeLocal<Object>();
378
379
680
      if (!Set<Object>(context, object, env->issuercert_string(), ca_info))
380
        return MaybeLocal<Object>();
381
340
      object = ca_info;
382
383
      // NOTE: Intentionally freeing cert that is not used anymore.
384
      // Delete cert and continue aggregating issuers.
385
340
      cert->reset(sk_X509_delete(peer_certs.get(), i));
386
340
      break;
387
    }
388
389
    // Issuer not found, break out of the loop.
390
451
    if (i == sk_X509_num(peer_certs.get()))
391
448
      break;
392
3
  }
393
448
  return MaybeLocal<Object>(object);
394
}
395
396
448
MaybeLocal<Object> GetLastIssuedCert(
397
    X509Pointer* cert,
398
    const SSLPointer& ssl,
399
    Local<Object> issuer_chain,
400
    Environment* const env) {
401
448
  Local<Context> context = env->isolate()->GetCurrentContext();
402
819
  while (X509_check_issued(cert->get(), cert->get()) != X509_V_OK) {
403
    X509* ca;
404
372
    if (SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get(), &ca) <= 0)
405
1
      break;
406
407
    Local<Object> ca_info;
408
372
    MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca);
409
372
    if (!maybe_ca_info.ToLocal(&ca_info))
410
      return MaybeLocal<Object>();
411
412
744
    if (!Set<Object>(context, issuer_chain, env->issuercert_string(), ca_info))
413
      return MaybeLocal<Object>();
414
372
    issuer_chain = ca_info;
415
416
    // Take the value of cert->get() before the call to cert->reset()
417
    // in order to compare it to ca after and provide a way to exit this loop
418
    // in case it gets stuck.
419
372
    X509* value_before_reset = cert->get();
420
421
    // Delete previous cert and continue aggregating issuers.
422
372
    cert->reset(ca);
423
424
372
    if (value_before_reset == ca)
425
1
      break;
426
  }
427
448
  return MaybeLocal<Object>(issuer_chain);
428
}
429
430
3648
void AddFingerprintDigest(
431
    const unsigned char* md,
432
    unsigned int md_size,
433
    char (*fingerprint)[3 * EVP_MAX_MD_SIZE + 1]) {
434
  unsigned int i;
435
3648
  const char hex[] = "0123456789ABCDEF";
436
437
144704
  for (i = 0; i < md_size; i++) {
438
141056
    (*fingerprint)[3*i] = hex[(md[i] & 0xf0) >> 4];
439
141056
    (*fingerprint)[(3*i)+1] = hex[(md[i] & 0x0f)];
440
141056
    (*fingerprint)[(3*i)+2] = ':';
441
  }
442
443
3648
  if (md_size > 0) {
444
3648
    (*fingerprint)[(3*(md_size-1))+2] = '\0';
445
  } else {
446
    (*fingerprint)[0] = '\0';
447
  }
448
3648
}
449
450
47
MaybeLocal<Value> GetCurveASN1Name(Environment* env, const int nid) {
451
47
  const char* nist = OBJ_nid2sn(nid);
452
  return nist != nullptr ?
453
      MaybeLocal<Value>(OneByteString(env->isolate(), nist)) :
454
94
      MaybeLocal<Value>(Undefined(env->isolate()));
455
}
456
457
47
MaybeLocal<Value> GetCurveNistName(Environment* env, const int nid) {
458
47
  const char* nist = EC_curve_nid2nist(nid);
459
  return nist != nullptr ?
460
      MaybeLocal<Value>(OneByteString(env->isolate(), nist)) :
461
94
      MaybeLocal<Value>(Undefined(env->isolate()));
462
}
463
464
47
MaybeLocal<Value> GetECPubKey(
465
    Environment* env,
466
    const EC_GROUP* group,
467
    const ECPointer& ec) {
468
47
  const EC_POINT* pubkey = EC_KEY_get0_public_key(ec.get());
469
47
  if (pubkey == nullptr)
470
    return Undefined(env->isolate());
471
472
47
  return ECPointToBuffer(
473
      env,
474
      group,
475
      pubkey,
476
47
      EC_KEY_get_conv_form(ec.get()),
477
94
      nullptr).FromMaybe(Local<Object>());
478
}
479
480
47
MaybeLocal<Value> GetECGroup(
481
    Environment* env,
482
    const EC_GROUP* group,
483
    const ECPointer& ec) {
484
47
  if (group == nullptr)
485
    return Undefined(env->isolate());
486
487
47
  int bits = EC_GROUP_order_bits(group);
488
47
  if (bits <= 0)
489
    return Undefined(env->isolate());
490
491
94
  return Integer::New(env->isolate(), bits);
492
}
493
494
1168
MaybeLocal<Object> GetPubKey(Environment* env, const RSAPointer& rsa) {
495
1168
  int size = i2d_RSA_PUBKEY(rsa.get(), nullptr);
496
1168
  CHECK_GE(size, 0);
497
498
2336
  std::unique_ptr<BackingStore> bs;
499
  {
500
1168
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
501
1168
    bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
502
  }
503
504
1168
  unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
505
1168
  CHECK_GE(i2d_RSA_PUBKEY(rsa.get(), &serialized), 0);
506
507
1168
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
508
2336
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
509
}
510
511
1168
MaybeLocal<Value> GetExponentString(
512
    Environment* env,
513
    const BIOPointer& bio,
514
    const BIGNUM* e) {
515
1168
  uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
516
1168
  uint32_t lo = static_cast<uint32_t>(exponent_word);
517
1168
  uint32_t hi = static_cast<uint32_t>(exponent_word >> 32);
518
1168
  if (hi == 0)
519
1168
    BIO_printf(bio.get(), "0x%x", lo);
520
  else
521
    BIO_printf(bio.get(), "0x%x%08x", hi, lo);
522
523
2336
  return ToV8Value(env, bio);
524
}
525
526
1168
Local<Value> GetBits(Environment* env, const BIGNUM* n) {
527
2336
  return Integer::New(env->isolate(), BN_num_bits(n));
528
}
529
530
1168
MaybeLocal<Value> GetModulusString(
531
    Environment* env,
532
    const BIOPointer& bio,
533
    const BIGNUM* n) {
534
1168
  BN_print(bio.get(), n);
535
2336
  return ToV8Value(env, bio);
536
}
537
}  // namespace
538
539
1217
MaybeLocal<Object> GetRawDERCertificate(Environment* env, X509* cert) {
540
1217
  int size = i2d_X509(cert, nullptr);
541
542
2434
  std::unique_ptr<BackingStore> bs;
543
  {
544
1217
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
545
1217
    bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
546
  }
547
548
1217
  unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
549
1217
  CHECK_GE(i2d_X509(cert, &serialized), 0);
550
551
1217
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
552
2434
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
553
}
554
555
1218
MaybeLocal<Value> GetSerialNumber(Environment* env, X509* cert) {
556
1218
  if (ASN1_INTEGER* serial_number = X509_get_serialNumber(cert)) {
557
1218
    BignumPointer bn(ASN1_INTEGER_to_BN(serial_number, nullptr));
558
1218
    if (bn) {
559
1218
      char* data = BN_bn2hex(bn.get());
560
1218
      ByteSource buf = ByteSource::Allocated(data, strlen(data));
561
1218
      if (buf)
562
2436
        return OneByteString(env->isolate(), buf.get());
563
    }
564
  }
565
566
  return Undefined(env->isolate());
567
}
568
569
1216
MaybeLocal<Value> GetKeyUsage(Environment* env, X509* cert) {
570
  StackOfASN1 eku(static_cast<STACK_OF(ASN1_OBJECT)*>(
571
2432
      X509_get_ext_d2i(cert, NID_ext_key_usage, nullptr, nullptr)));
572
1216
  if (eku) {
573
9
    const int count = sk_ASN1_OBJECT_num(eku.get());
574
9
    MaybeStackBuffer<Local<Value>, 16> ext_key_usage(count);
575
    char buf[256];
576
577
9
    int j = 0;
578
20
    for (int i = 0; i < count; i++) {
579
11
      if (OBJ_obj2txt(buf,
580
                      sizeof(buf),
581
22
                      sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) {
582
22
        ext_key_usage[j++] = OneByteString(env->isolate(), buf);
583
      }
584
    }
585
586
18
    return Array::New(env->isolate(), ext_key_usage.out(), count);
587
  }
588
589
2414
  return Undefined(env->isolate());
590
}
591
592
3648
MaybeLocal<Value> GetFingerprintDigest(
593
    Environment* env,
594
    const EVP_MD* method,
595
    X509* cert) {
596
  unsigned char md[EVP_MAX_MD_SIZE];
597
  unsigned int md_size;
598
  char fingerprint[EVP_MAX_MD_SIZE * 3 + 1];
599
600
3648
  if (X509_digest(cert, method, md, &md_size)) {
601
3648
    AddFingerprintDigest(md, md_size, &fingerprint);
602
7296
    return OneByteString(env->isolate(), fingerprint);
603
  }
604
  return Undefined(env->isolate());
605
}
606
607
1216
MaybeLocal<Value> GetValidTo(
608
    Environment* env,
609
    X509* cert,
610
    const BIOPointer& bio) {
611
1216
  ASN1_TIME_print(bio.get(), X509_get0_notAfter(cert));
612
2432
  return ToV8Value(env, bio);
613
}
614
615
1216
MaybeLocal<Value> GetValidFrom(
616
    Environment* env,
617
    X509* cert,
618
    const BIOPointer& bio) {
619
1216
  ASN1_TIME_print(bio.get(), X509_get0_notBefore(cert));
620
2432
  return ToV8Value(env, bio);
621
}
622
623
217
static inline bool IsSafeAltName(const char* name, size_t length, bool utf8) {
624
4914
  for (size_t i = 0; i < length; i++) {
625
4737
    char c = name[i];
626
4737
    switch (c) {
627
25
    case '"':
628
    case '\\':
629
      // These mess with encoding rules.
630
      // Fall through.
631
    case ',':
632
      // Commas make it impossible to split the list of subject alternative
633
      // names unambiguously, which is why we have to escape.
634
      // Fall through.
635
    case '\'':
636
      // Single quotes are unlikely to appear in any legitimate values, but they
637
      // could be used to make a value look like it was escaped (i.e., enclosed
638
      // in single/double quotes).
639
25
      return false;
640
4712
    default:
641
4712
      if (utf8) {
642
        // In UTF8 strings, we require escaping for any ASCII control character,
643
        // but NOT for non-ASCII characters. Note that all bytes of any code
644
        // point that consists of more than a single byte have their MSB set.
645

124
        if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
646
4
          return false;
647
        }
648
      } else {
649
        // Check if the char is a control character or non-ASCII character. Note
650
        // that char may or may not be a signed type. Regardless, non-ASCII
651
        // values will always be outside of this range.
652

4588
        if (c < ' ' || c > '~') {
653
11
          return false;
654
        }
655
      }
656
    }
657
  }
658
177
  return true;
659
}
660
661
217
static inline void PrintAltName(const BIOPointer& out, const char* name,
662
                                size_t length, bool utf8,
663
                                const char* safe_prefix) {
664
217
  if (IsSafeAltName(name, length, utf8)) {
665
    // For backward-compatibility, append "safe" names without any
666
    // modifications.
667
177
    if (safe_prefix != nullptr) {
668
8
      BIO_printf(out.get(), "%s:", safe_prefix);
669
    }
670
177
    BIO_write(out.get(), name, length);
671
  } else {
672
    // If a name is not "safe", we cannot embed it without special
673
    // encoding. This does not usually happen, but we don't want to hide
674
    // it from the user either. We use JSON compatible escaping here.
675
40
    BIO_write(out.get(), "\"", 1);
676
40
    if (safe_prefix != nullptr) {
677
8
      BIO_printf(out.get(), "%s:", safe_prefix);
678
    }
679
1411
    for (size_t j = 0; j < length; j++) {
680
1371
      char c = static_cast<char>(name[j]);
681
1371
      if (c == '\\') {
682
16
        BIO_write(out.get(), "\\\\", 2);
683
1355
      } else if (c == '"') {
684
4
        BIO_write(out.get(), "\\\"", 2);
685


1351
      } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) {
686
        // Note that the above condition explicitly excludes commas, which means
687
        // that those are encoded as Unicode escape sequences in the "else"
688
        // block. That is not strictly necessary, and Node.js itself would parse
689
        // it correctly either way. We only do this to account for third-party
690
        // code that might be splitting the string at commas (as Node.js itself
691
        // used to do).
692
1319
        BIO_write(out.get(), &c, 1);
693
      } else {
694
        // Control character or non-ASCII character. We treat everything as
695
        // Latin-1, which corresponds to the first 255 Unicode code points.
696
32
        const char hex[] = "0123456789abcdef";
697
32
        char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] };
698
32
        BIO_write(out.get(), u, sizeof(u));
699
      }
700
    }
701
40
    BIO_write(out.get(), "\"", 1);
702
  }
703
217
}
704
705
193
static inline void PrintLatin1AltName(const BIOPointer& out,
706
                                      const ASN1_IA5STRING* name,
707
                                      const char* safe_prefix = nullptr) {
708
193
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
709
               false, safe_prefix);
710
193
}
711
712
10
static inline void PrintUtf8AltName(const BIOPointer& out,
713
                                    const ASN1_UTF8STRING* name,
714
                                    const char* safe_prefix = nullptr) {
715
10
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
716
               true, safe_prefix);
717
10
}
718
719
// This function currently emulates the behavior of i2v_GENERAL_NAME in a safer
720
// and less ambiguous way.
721
// TODO(tniessen): gradually improve the format in the next major version(s)
722
244
static bool PrintGeneralName(const BIOPointer& out, const GENERAL_NAME* gen) {
723
244
  if (gen->type == GEN_DNS) {
724
24
    ASN1_IA5STRING* name = gen->d.dNSName;
725
24
    BIO_write(out.get(), "DNS:", 4);
726
    // Note that the preferred name syntax (see RFCs 5280 and 1034) with
727
    // wildcards is a subset of what we consider "safe", so spec-compliant DNS
728
    // names will never need to be escaped.
729
24
    PrintLatin1AltName(out, name);
730
220
  } else if (gen->type == GEN_EMAIL) {
731
4
    ASN1_IA5STRING* name = gen->d.rfc822Name;
732
4
    BIO_write(out.get(), "email:", 6);
733
4
    PrintLatin1AltName(out, name);
734
216
  } else if (gen->type == GEN_URI) {
735
159
    ASN1_IA5STRING* name = gen->d.uniformResourceIdentifier;
736
159
    BIO_write(out.get(), "URI:", 4);
737
    // The set of "safe" names was designed to include just about any URI,
738
    // with a few exceptions, most notably URIs that contains commas (see
739
    // RFC 2396). In other words, most legitimate URIs will not require
740
    // escaping.
741
159
    PrintLatin1AltName(out, name);
742
57
  } else if (gen->type == GEN_DIRNAME) {
743
    // For backward compatibility, use X509_NAME_oneline to print the
744
    // X509_NAME object. The format is non standard and should be avoided
745
    // elsewhere, but conveniently, the function produces ASCII and the output
746
    // is unlikely to contains commas or other characters that would require
747
    // escaping. With that in mind, note that it SHOULD NOT produce ASCII
748
    // output since an RFC5280 AttributeValue may be a UTF8String.
749
    // TODO(tniessen): switch to RFC2253 rules in a major release
750
14
    BIO_printf(out.get(), "DirName:");
751
    char oline[256];
752
14
    if (X509_NAME_oneline(gen->d.dirn, oline, sizeof(oline)) != nullptr) {
753
14
      PrintAltName(out, oline, strlen(oline), false, nullptr);
754
    } else {
755
      return false;
756
    }
757
43
  } else if (gen->type == GEN_IPADD) {
758
17
    BIO_printf(out.get(), "IP Address:");
759
17
    const ASN1_OCTET_STRING* ip = gen->d.ip;
760
17
    const unsigned char* b = ip->data;
761
17
    if (ip->length == 4) {
762
11
      BIO_printf(out.get(), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
763
6
    } else if (ip->length == 16) {
764
18
      for (unsigned int j = 0; j < 8; j++) {
765
16
        uint16_t pair = (b[2 * j] << 8) | b[2 * j + 1];
766
16
        BIO_printf(out.get(), (j == 0) ? "%X" : ":%X", pair);
767
      }
768
    } else {
769
#if OPENSSL_VERSION_MAJOR >= 3
770
4
      BIO_printf(out.get(), "<invalid length=%d>", ip->length);
771
#else
772
      BIO_printf(out.get(), "<invalid>");
773
#endif
774
    }
775
26
  } else if (gen->type == GEN_RID) {
776
    // TODO(tniessen): unlike OpenSSL's default implementation, never print the
777
    // OID as text and instead always print its numeric representation, which is
778
    // backward compatible in practice and more future proof (see OBJ_obj2txt).
779
    char oline[256];
780
4
    i2t_ASN1_OBJECT(oline, sizeof(oline), gen->d.rid);
781
4
    BIO_printf(out.get(), "Registered ID:%s", oline);
782
22
  } else if (gen->type == GEN_OTHERNAME) {
783
    // TODO(tniessen): the format that is used here is based on OpenSSL's
784
    // implementation of i2v_GENERAL_NAME (as of OpenSSL 3.0.1), mostly for
785
    // backward compatibility. It is somewhat awkward, especially when passed to
786
    // translatePeerCertificate, and should be changed in the future, probably
787
    // to the format used by GENERAL_NAME_print (in a major release).
788
22
    bool unicode = true;
789
22
    const char* prefix = nullptr;
790
    // OpenSSL 1.1.1 does not support othername in i2v_GENERAL_NAME and may not
791
    // define these NIDs.
792
#if OPENSSL_VERSION_MAJOR >= 3
793
22
    int nid = OBJ_obj2nid(gen->d.otherName->type_id);
794

22
    switch (nid) {
795
      case NID_id_on_SmtpUTF8Mailbox:
796
        prefix = " SmtpUTF8Mailbox:";
797
        break;
798
10
      case NID_XmppAddr:
799
10
        prefix = " XmppAddr:";
800
10
        break;
801
8
      case NID_SRVName:
802
8
        prefix = " SRVName:";
803
8
        unicode = false;
804
8
        break;
805
      case NID_ms_upn:
806
        prefix = " UPN:";
807
        break;
808
      case NID_NAIRealm:
809
        prefix = " NAIRealm:";
810
        break;
811
    }
812
#endif  // OPENSSL_VERSION_MAJOR >= 3
813
22
    int val_type = gen->d.otherName->value->type;
814

22
    if (prefix == nullptr ||
815
10
        (unicode && val_type != V_ASN1_UTF8STRING) ||
816

18
        (!unicode && val_type != V_ASN1_IA5STRING)) {
817
6
      BIO_printf(out.get(), "othername:<unsupported>");
818
    } else {
819
16
      BIO_printf(out.get(), "othername:");
820
16
      if (unicode) {
821
10
        PrintUtf8AltName(out, gen->d.otherName->value->value.utf8string,
822
                         prefix);
823
      } else {
824
6
        PrintLatin1AltName(out, gen->d.otherName->value->value.ia5string,
825
                           prefix);
826
      }
827
    }
828
  } else if (gen->type == GEN_X400) {
829
    // TODO(tniessen): this is what OpenSSL does, implement properly instead
830
    BIO_printf(out.get(), "X400Name:<unsupported>");
831
  } else if (gen->type == GEN_EDIPARTY) {
832
    // TODO(tniessen): this is what OpenSSL does, implement properly instead
833
    BIO_printf(out.get(), "EdiPartyName:<unsupported>");
834
  } else {
835
    // This is safe because X509V3_EXT_d2i would have returned nullptr in this
836
    // case already.
837
    UNREACHABLE();
838
  }
839
840
244
  return true;
841
}
842
843
75
bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {
844
75
  const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
845
75
  CHECK(method == X509V3_EXT_get_nid(NID_subject_alt_name));
846
847
75
  GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(ext));
848
75
  if (names == nullptr)
849
    return false;
850
851
75
  bool ok = true;
852
853
162
  for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) {
854
87
    GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i);
855
856
87
    if (i != 0)
857
12
      BIO_write(out.get(), ", ", 2);
858
859
87
    if (!(ok = PrintGeneralName(out, gen))) {
860
      break;
861
    }
862
  }
863
75
  sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
864
865
75
  return ok;
866
}
867
868
81
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
869
81
  const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
870
81
  CHECK(method == X509V3_EXT_get_nid(NID_info_access));
871
872
  AUTHORITY_INFO_ACCESS* descs =
873
81
      static_cast<AUTHORITY_INFO_ACCESS*>(X509V3_EXT_d2i(ext));
874
81
  if (descs == nullptr)
875
    return false;
876
877
81
  bool ok = true;
878
879
238
  for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) {
880
157
    ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i);
881
882
157
    if (i != 0)
883
76
      BIO_write(out.get(), "\n", 1);
884
885
    char objtmp[80];
886
157
    i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method);
887
157
    BIO_printf(out.get(), "%s - ", objtmp);
888
157
    if (!(ok = PrintGeneralName(out, desc->location))) {
889
      break;
890
    }
891
  }
892
81
  sk_ACCESS_DESCRIPTION_pop_free(descs, ACCESS_DESCRIPTION_free);
893
894
#if OPENSSL_VERSION_MAJOR < 3
895
  BIO_write(out.get(), "\n", 1);
896
#endif
897
898
81
  return ok;
899
}
900
901
1249
v8::MaybeLocal<v8::Value> GetSubjectAltNameString(
902
    Environment* env,
903
    const BIOPointer& bio,
904
    X509* cert) {
905
1249
  int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
906
1249
  if (index < 0)
907
2348
    return Undefined(env->isolate());
908
909
75
  X509_EXTENSION* ext = X509_get_ext(cert, index);
910
75
  CHECK_NOT_NULL(ext);
911
912
75
  if (!SafeX509SubjectAltNamePrint(bio, ext)) {
913
    USE(BIO_reset(bio.get()));
914
    return v8::Null(env->isolate());
915
  }
916
917
150
  return ToV8Value(env, bio);
918
}
919
920
1221
v8::MaybeLocal<v8::Value> GetInfoAccessString(
921
    Environment* env,
922
    const BIOPointer& bio,
923
    X509* cert) {
924
1221
  int index = X509_get_ext_by_NID(cert, NID_info_access, -1);
925
1221
  if (index < 0)
926
2280
    return Undefined(env->isolate());
927
928
81
  X509_EXTENSION* ext = X509_get_ext(cert, index);
929
81
  CHECK_NOT_NULL(ext);
930
931
81
  if (!SafeX509InfoAccessPrint(bio, ext)) {
932
    USE(BIO_reset(bio.get()));
933
    return v8::Null(env->isolate());
934
  }
935
936
162
  return ToV8Value(env, bio);
937
}
938
939
12
MaybeLocal<Value> GetIssuerString(
940
    Environment* env,
941
    const BIOPointer& bio,
942
    X509* cert) {
943
12
  X509_NAME* issuer_name = X509_get_issuer_name(cert);
944
12
  if (X509_NAME_print_ex(bio.get(), issuer_name, 0, X509_NAME_FLAGS) <= 0) {
945
    USE(BIO_reset(bio.get()));
946
    return Undefined(env->isolate());
947
  }
948
949
24
  return ToV8Value(env, bio);
950
}
951
952
14
MaybeLocal<Value> GetSubject(
953
    Environment* env,
954
    const BIOPointer& bio,
955
    X509* cert) {
956
14
  if (X509_NAME_print_ex(
957
          bio.get(),
958
14
          X509_get_subject_name(cert),
959
          0,
960
14
          X509_NAME_FLAGS) <= 0) {
961
    USE(BIO_reset(bio.get()));
962
    return Undefined(env->isolate());
963
  }
964
965
28
  return ToV8Value(env, bio);
966
}
967
968
template <X509_NAME* get_name(const X509*)>
969
4856
static MaybeLocal<Value> GetX509NameObject(Environment* env, X509* cert) {
970
4856
  X509_NAME* name = get_name(cert);
971
4856
  CHECK_NOT_NULL(name);
972
973
4856
  int cnt = X509_NAME_entry_count(name);
974
4856
  CHECK_GE(cnt, 0);
975
976
  Local<Object> result =
977
9712
      Object::New(env->isolate(), Null(env->isolate()), nullptr, nullptr, 0);
978
4856
  if (result.IsEmpty()) {
979
    return MaybeLocal<Value>();
980
  }
981
982
35790
  for (int i = 0; i < cnt; i++) {
983
30934
    X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, i);
984
30934
    CHECK_NOT_NULL(entry);
985
986
    // We intentionally ignore the value of X509_NAME_ENTRY_set because the
987
    // representation as an object does not allow grouping entries into sets
988
    // anyway, and multi-value RDNs are rare, i.e., the vast majority of
989
    // Relative Distinguished Names contains a single type-value pair only.
990
30934
    const ASN1_OBJECT* type = X509_NAME_ENTRY_get_object(entry);
991
30934
    const ASN1_STRING* value = X509_NAME_ENTRY_get_data(entry);
992
993
    // If OpenSSL knows the type, use the short name of the type as the key, and
994
    // the numeric representation of the type's OID otherwise.
995
30934
    int type_nid = OBJ_obj2nid(type);
996
    char type_buf[80];
997
    const char* type_str;
998
30934
    if (type_nid != NID_undef) {
999
30934
      type_str = OBJ_nid2sn(type_nid);
1000
30934
      CHECK_NOT_NULL(type_str);
1001
    } else {
1002
      OBJ_obj2txt(type_buf, sizeof(type_buf), type, true);
1003
      type_str = type_buf;
1004
    }
1005
1006
    Local<String> v8_name;
1007
61868
    if (!String::NewFromUtf8(env->isolate(), type_str).ToLocal(&v8_name)) {
1008
      return MaybeLocal<Value>();
1009
    }
1010
1011
    // The previous implementation used X509_NAME_print_ex, which escapes some
1012
    // characters in the value. The old implementation did not decode/unescape
1013
    // values correctly though, leading to ambiguous and incorrect
1014
    // representations. The new implementation only converts to Unicode and does
1015
    // not escape anything.
1016
    unsigned char* value_str;
1017
30934
    int value_str_size = ASN1_STRING_to_UTF8(&value_str, value);
1018
30934
    if (value_str_size < 0) {
1019
      return Undefined(env->isolate());
1020
    }
1021
1022
    Local<String> v8_value;
1023
30934
    if (!String::NewFromUtf8(env->isolate(),
1024
                             reinterpret_cast<const char*>(value_str),
1025
                             NewStringType::kNormal,
1026
30934
                             value_str_size).ToLocal(&v8_value)) {
1027
      OPENSSL_free(value_str);
1028
      return MaybeLocal<Value>();
1029
    }
1030
1031
30934
    OPENSSL_free(value_str);
1032
1033
    // For backward compatibility, we only create arrays if multiple values
1034
    // exist for the same key. That is not great but there is not much we can
1035
    // change here without breaking things. Note that this creates nested data
1036
    // structures, yet still does not allow representing Distinguished Names
1037
    // accurately.
1038
    bool multiple;
1039
61868
    if (!result->HasOwnProperty(env->context(), v8_name).To(&multiple)) {
1040
      return MaybeLocal<Value>();
1041
30934
    } else if (multiple) {
1042
      Local<Value> accum;
1043
88
      if (!result->Get(env->context(), v8_name).ToLocal(&accum)) {
1044
        return MaybeLocal<Value>();
1045
      }
1046
44
      if (!accum->IsArray()) {
1047
72
        accum = Array::New(env->isolate(), &accum, 1);
1048
72
        if (result->Set(env->context(), v8_name, accum).IsNothing()) {
1049
          return MaybeLocal<Value>();
1050
        }
1051
      }
1052
44
      Local<Array> array = accum.As<Array>();
1053
88
      if (array->Set(env->context(), array->Length(), v8_value).IsNothing()) {
1054
        return MaybeLocal<Value>();
1055
      }
1056
61780
    } else if (result->Set(env->context(), v8_name, v8_value).IsNothing()) {
1057
      return MaybeLocal<Value>();
1058
    }
1059
  }
1060
1061
4856
  return result;
1062
}
1063
1064
53
MaybeLocal<Value> GetCipherName(Environment* env, const SSLPointer& ssl) {
1065
53
  return GetCipherName(env, SSL_get_current_cipher(ssl.get()));
1066
}
1067
1068
53
MaybeLocal<Value> GetCipherStandardName(
1069
    Environment* env,
1070
    const SSLPointer& ssl) {
1071
53
  return GetCipherStandardName(env, SSL_get_current_cipher(ssl.get()));
1072
}
1073
1074
53
MaybeLocal<Value> GetCipherVersion(Environment* env, const SSLPointer& ssl) {
1075
53
  return GetCipherVersion(env, SSL_get_current_cipher(ssl.get()));
1076
}
1077
1078
MaybeLocal<Array> GetClientHelloCiphers(
1079
    Environment* env,
1080
    const SSLPointer& ssl) {
1081
  EscapableHandleScope scope(env->isolate());
1082
  const unsigned char* buf;
1083
  size_t len = SSL_client_hello_get0_ciphers(ssl.get(), &buf);
1084
  size_t count = len / 2;
1085
  MaybeStackBuffer<Local<Value>, 16> ciphers(count);
1086
  int j = 0;
1087
  for (size_t n = 0; n < len; n += 2) {
1088
    const SSL_CIPHER* cipher = SSL_CIPHER_find(ssl.get(), buf);
1089
    buf += 2;
1090
    Local<Object> obj = Object::New(env->isolate());
1091
    if (!Set(env->context(),
1092
             obj,
1093
             env->name_string(),
1094
             GetCipherName(env, cipher)) ||
1095
        !Set(env->context(),
1096
             obj,
1097
             env->standard_name_string(),
1098
             GetCipherStandardName(env, cipher)) ||
1099
        !Set(env->context(),
1100
             obj,
1101
             env->version_string(),
1102
             GetCipherVersion(env, cipher))) {
1103
      return MaybeLocal<Array>();
1104
    }
1105
    ciphers[j++] = obj;
1106
  }
1107
  Local<Array> ret = Array::New(env->isolate(), ciphers.out(), count);
1108
  return scope.Escape(ret);
1109
}
1110
1111
1112
53
MaybeLocal<Object> GetCipherInfo(Environment* env, const SSLPointer& ssl) {
1113
53
  if (SSL_get_current_cipher(ssl.get()) == nullptr)
1114
    return MaybeLocal<Object>();
1115
53
  EscapableHandleScope scope(env->isolate());
1116
53
  Local<Object> info = Object::New(env->isolate());
1117
1118
106
  if (!Set<Value>(env->context(),
1119
                  info,
1120
                  env->name_string(),
1121
53
                  GetCipherName(env, ssl)) ||
1122
106
      !Set<Value>(env->context(),
1123
                  info,
1124
                  env->standard_name_string(),
1125
106
                  GetCipherStandardName(env, ssl)) ||
1126

159
      !Set<Value>(env->context(),
1127
                  info,
1128
                  env->version_string(),
1129
                  GetCipherVersion(env, ssl))) {
1130
    return MaybeLocal<Object>();
1131
  }
1132
1133
53
  return scope.Escape(info);
1134
}
1135
1136
875
MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1137
875
  CHECK_EQ(SSL_is_server(ssl.get()), 0);
1138
  EVP_PKEY* raw_key;
1139
1140
875
  EscapableHandleScope scope(env->isolate());
1141
875
  Local<Object> info = Object::New(env->isolate());
1142
875
  if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1143
30
    return scope.Escape(info);
1144
1145
845
  Local<Context> context = env->context();
1146
1690
  crypto::EVPKeyPointer key(raw_key);
1147
1148
845
  int kid = EVP_PKEY_id(key.get());
1149
845
  int bits = EVP_PKEY_bits(key.get());
1150
845
  switch (kid) {
1151
7
    case EVP_PKEY_DH:
1152
28
      if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1153

28
          !Set<Integer>(context,
1154
               info,
1155
               env->size_string(),
1156
               Integer::New(env->isolate(), bits))) {
1157
        return MaybeLocal<Object>();
1158
      }
1159
7
      break;
1160
838
    case EVP_PKEY_EC:
1161
    case EVP_PKEY_X25519:
1162
    case EVP_PKEY_X448:
1163
      {
1164
        const char* curve_name;
1165
838
        if (kid == EVP_PKEY_EC) {
1166
10
          ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1167
5
          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1168
5
          curve_name = OBJ_nid2sn(nid);
1169
        } else {
1170
833
          curve_name = OBJ_nid2sn(kid);
1171
        }
1172
2514
        if (!Set<String>(context,
1173
                         info,
1174
                         env->type_string(),
1175
838
                         env->ecdh_string()) ||
1176
2514
            !Set<String>(context,
1177
                info,
1178
                env->name_string(),
1179
1676
                OneByteString(env->isolate(), curve_name)) ||
1180

3352
            !Set<Integer>(context,
1181
                 info,
1182
                 env->size_string(),
1183
                 Integer::New(env->isolate(), bits))) {
1184
          return MaybeLocal<Object>();
1185
838
        }
1186
      }
1187
838
      break;
1188
  }
1189
1190
845
  return scope.Escape(info);
1191
}
1192
1193
73
MaybeLocal<Object> ECPointToBuffer(Environment* env,
1194
                                   const EC_GROUP* group,
1195
                                   const EC_POINT* point,
1196
                                   point_conversion_form_t form,
1197
                                   const char** error) {
1198
73
  size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
1199
73
  if (len == 0) {
1200
    if (error != nullptr) *error = "Failed to get public key length";
1201
    return MaybeLocal<Object>();
1202
  }
1203
1204
73
  std::unique_ptr<BackingStore> bs;
1205
  {
1206
73
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1207
73
    bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
1208
  }
1209
1210
146
  len = EC_POINT_point2oct(group,
1211
                           point,
1212
                           form,
1213
73
                           reinterpret_cast<unsigned char*>(bs->Data()),
1214
                           bs->ByteLength(),
1215
                           nullptr);
1216
73
  if (len == 0) {
1217
    if (error != nullptr) *error = "Failed to get public key";
1218
    return MaybeLocal<Object>();
1219
  }
1220
1221
73
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
1222
146
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
1223
}
1224
1225
496
MaybeLocal<Value> GetPeerCert(
1226
    Environment* env,
1227
    const SSLPointer& ssl,
1228
    bool abbreviated,
1229
    bool is_server) {
1230
496
  ClearErrorOnReturn clear_error_on_return;
1231
  Local<Object> result;
1232
  MaybeLocal<Object> maybe_cert;
1233
1234
  // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1235
  // contains the `peer_certificate`, but on server it doesn't.
1236
992
  X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr);
1237
496
  STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get());
1238


496
  if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
1239
10
    return Undefined(env->isolate());
1240
1241
  // Short result requested.
1242
491
  if (abbreviated) {
1243
    maybe_cert =
1244
43
        X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0));
1245
86
    return maybe_cert.ToLocal(&result) ? result : MaybeLocal<Value>();
1246
  }
1247
1248
896
  StackOfX509 peer_certs = CloneSSLCerts(std::move(cert), ssl_certs);
1249
448
  if (peer_certs == nullptr)
1250
    return Undefined(env->isolate());
1251
1252
  // First and main certificate.
1253
896
  X509Pointer first_cert(sk_X509_value(peer_certs.get(), 0));
1254
448
  CHECK(first_cert);
1255
448
  maybe_cert = X509ToObject(env, first_cert.release());
1256
448
  if (!maybe_cert.ToLocal(&result))
1257
    return MaybeLocal<Value>();
1258
1259
  Local<Object> issuer_chain;
1260
  MaybeLocal<Object> maybe_issuer_chain;
1261
1262
  maybe_issuer_chain =
1263
      AddIssuerChainToObject(
1264
          &cert,
1265
          result,
1266
448
          std::move(peer_certs),
1267
448
          env);
1268
448
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1269
    return MaybeLocal<Value>();
1270
1271
  maybe_issuer_chain =
1272
      GetLastIssuedCert(
1273
          &cert,
1274
          ssl,
1275
          issuer_chain,
1276
448
          env);
1277
1278
  issuer_chain.Clear();
1279
448
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1280
    return MaybeLocal<Value>();
1281
1282
  // Last certificate should be self-signed.
1283
895
  if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK &&
1284

1342
      !Set<Object>(env->context(),
1285
           issuer_chain,
1286
           env->issuercert_string(),
1287
           issuer_chain)) {
1288
    return MaybeLocal<Value>();
1289
  }
1290
1291
448
  return result;
1292
}
1293
1294
1215
MaybeLocal<Object> X509ToObject(
1295
    Environment* env,
1296
    X509* cert,
1297
    bool names_as_string) {
1298
1215
  EscapableHandleScope scope(env->isolate());
1299
1215
  Local<Context> context = env->context();
1300
1215
  Local<Object> info = Object::New(env->isolate());
1301
1302
2430
  BIOPointer bio(BIO_new(BIO_s_mem()));
1303
1304
1215
  if (names_as_string) {
1305
    // TODO(tniessen): this branch should not have to exist. It is only here
1306
    // because toLegacyObject() does not actually return a legacy object, and
1307
    // instead represents subject and issuer as strings.
1308
2
    if (!Set<Value>(context,
1309
                    info,
1310
                    env->subject_string(),
1311
2
                    GetSubject(env, bio, cert)) ||
1312

3
        !Set<Value>(context,
1313
                    info,
1314
                    env->issuer_string(),
1315
                    GetIssuerString(env, bio, cert))) {
1316
      return MaybeLocal<Object>();
1317
    }
1318
  } else {
1319
2428
    if (!Set<Value>(context,
1320
                    info,
1321
                    env->subject_string(),
1322
2428
                    GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1323

3642
        !Set<Value>(context,
1324
                    info,
1325
                    env->issuer_string(),
1326
                    GetX509NameObject<X509_get_issuer_name>(env, cert))) {
1327
      return MaybeLocal<Object>();
1328
    }
1329
  }
1330
1331
2430
  if (!Set<Value>(context,
1332
                  info,
1333
                  env->subjectaltname_string(),
1334
2430
                  GetSubjectAltNameString(env, bio, cert)) ||
1335

3645
      !Set<Value>(context,
1336
                  info,
1337
                  env->infoaccess_string(),
1338
                  GetInfoAccessString(env, bio, cert))) {
1339
    return MaybeLocal<Object>();
1340
  }
1341
1342
2430
  EVPKeyPointer pkey(X509_get_pubkey(cert));
1343
1215
  RSAPointer rsa;
1344
1215
  ECPointer ec;
1345
1215
  if (pkey) {
1346
1215
    switch (EVP_PKEY_id(pkey.get())) {
1347
1168
      case EVP_PKEY_RSA:
1348
1168
        rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1349
1168
        break;
1350
47
      case EVP_PKEY_EC:
1351
47
        ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1352
47
        break;
1353
    }
1354
  }
1355
1356
1215
  if (rsa) {
1357
    const BIGNUM* n;
1358
    const BIGNUM* e;
1359
1168
    RSA_get0_key(rsa.get(), &n, &e, nullptr);
1360
2336
    if (!Set<Value>(context,
1361
                    info,
1362
                    env->modulus_string(),
1363
1168
                    GetModulusString(env, bio, n)) ||
1364
3504
        !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1365
2336
        !Set<Value>(context,
1366
                    info,
1367
                    env->exponent_string(),
1368
2336
                    GetExponentString(env, bio, e)) ||
1369

3504
        !Set<Object>(context,
1370
                     info,
1371
                     env->pubkey_string(),
1372
                     GetPubKey(env, rsa))) {
1373
      return MaybeLocal<Object>();
1374
    }
1375
47
  } else if (ec) {
1376
47
    const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1377
1378
94
    if (!Set<Value>(context,
1379
                    info,
1380
                    env->bits_string(),
1381
94
                    GetECGroup(env, group, ec)) ||
1382

141
        !Set<Value>(context,
1383
                    info,
1384
                    env->pubkey_string(),
1385
                    GetECPubKey(env, group, ec))) {
1386
      return MaybeLocal<Object>();
1387
    }
1388
1389
47
    const int nid = EC_GROUP_get_curve_name(group);
1390
47
    if (nid != 0) {
1391
      // Curve is well-known, get its OID and NIST nick-name (if it has one).
1392
1393
94
      if (!Set<Value>(context,
1394
                      info,
1395
                      env->asn1curve_string(),
1396
94
                      GetCurveASN1Name(env, nid)) ||
1397

141
          !Set<Value>(context,
1398
                      info,
1399
                      env->nistcurve_string(),
1400
                      GetCurveNistName(env, nid))) {
1401
        return MaybeLocal<Object>();
1402
      }
1403
    } else {
1404
      // Unnamed curves can be described by their mathematical properties,
1405
      // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1406
    }
1407
  }
1408
1409
  // pkey, rsa, and ec pointers are no longer needed.
1410
1215
  pkey.reset();
1411
1215
  rsa.reset();
1412
1215
  ec.reset();
1413
1414
2430
  if (!Set<Value>(context,
1415
                  info,
1416
                  env->valid_from_string(),
1417
2430
                  GetValidFrom(env, cert, bio)) ||
1418

3645
      !Set<Value>(context,
1419
                  info,
1420
                  env->valid_to_string(),
1421
                  GetValidTo(env, cert, bio))) {
1422
    return MaybeLocal<Object>();
1423
  }
1424
1425
  // bio is no longer needed
1426
1215
  bio.reset();
1427
1428
2430
  if (!Set<Value>(context,
1429
                  info,
1430
                  env->fingerprint_string(),
1431
1215
                  GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1432
2430
      !Set<Value>(context,
1433
                  info,
1434
                  env->fingerprint256_string(),
1435
1215
                  GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1436
2430
      !Set<Value>(context,
1437
                  info,
1438
                  env->fingerprint512_string(),
1439
1215
                  GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1440
2430
      !Set<Value>(context,
1441
                  info,
1442
                  env->ext_key_usage_string(),
1443
1215
                  GetKeyUsage(env, cert)) ||
1444
2430
      !Set<Value>(context,
1445
                  info,
1446
                  env->serial_number_string(),
1447
2430
                  GetSerialNumber(env, cert)) ||
1448

3645
      !Set<Object>(context,
1449
                   info,
1450
                   env->raw_string(),
1451
                   GetRawDERCertificate(env, cert))) {
1452
    return MaybeLocal<Object>();
1453
  }
1454
1455
1215
  return scope.Escape(info);
1456
}
1457
1458
}  // namespace crypto
1459
}  // namespace node