GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_common.cc Lines: 542 712 76.1 %
Date: 2022-02-27 04:15:00 Branches: 287 493 58.2 %

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 kX509NameFlagsMultiline =
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
static constexpr int kX509NameFlagsRFC2253WithinUtf8JSON =
52
    XN_FLAG_RFC2253 &
53
    ~ASN1_STRFLGS_ESC_MSB &
54
    ~ASN1_STRFLGS_ESC_CTRL;
55
56
896
int SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) {
57
896
  X509_STORE* store = SSL_CTX_get_cert_store(ctx);
58
  DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
59
896
      X509_STORE_CTX_new());
60
1792
  return store_ctx.get() != nullptr &&
61

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

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

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

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







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

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

286
        if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
651
6
          return false;
652
        }
653
      } else {
654
        // Check if the char is a control character or non-ASCII character. Note
655
        // that char may or may not be a signed type. Regardless, non-ASCII
656
        // values will always be outside of this range.
657

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


1345
      } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) {
691
        // Note that the above condition explicitly excludes commas, which means
692
        // that those are encoded as Unicode escape sequences in the "else"
693
        // block. That is not strictly necessary, and Node.js itself would parse
694
        // it correctly either way. We only do this to account for third-party
695
        // code that might be splitting the string at commas (as Node.js itself
696
        // used to do).
697
1291
        BIO_write(out.get(), &c, 1);
698
      } else {
699
        // Control character or non-ASCII character. We treat everything as
700
        // Latin-1, which corresponds to the first 255 Unicode code points.
701
54
        const char hex[] = "0123456789abcdef";
702
54
        char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] };
703
54
        BIO_write(out.get(), u, sizeof(u));
704
      }
705
    }
706
42
    BIO_write(out.get(), "\"", 1);
707
  }
708
217
}
709
710
193
static inline void PrintLatin1AltName(const BIOPointer& out,
711
                                      const ASN1_IA5STRING* name,
712
                                      const char* safe_prefix = nullptr) {
713
193
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
714
               false, safe_prefix);
715
193
}
716
717
10
static inline void PrintUtf8AltName(const BIOPointer& out,
718
                                    const ASN1_UTF8STRING* name,
719
                                    const char* safe_prefix = nullptr) {
720
10
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
721
               true, safe_prefix);
722
10
}
723
724
// This function currently emulates the behavior of i2v_GENERAL_NAME in a safer
725
// and less ambiguous way.
726
// TODO(tniessen): gradually improve the format in the next major version(s)
727
244
static bool PrintGeneralName(const BIOPointer& out, const GENERAL_NAME* gen) {
728
244
  if (gen->type == GEN_DNS) {
729
24
    ASN1_IA5STRING* name = gen->d.dNSName;
730
24
    BIO_write(out.get(), "DNS:", 4);
731
    // Note that the preferred name syntax (see RFCs 5280 and 1034) with
732
    // wildcards is a subset of what we consider "safe", so spec-compliant DNS
733
    // names will never need to be escaped.
734
24
    PrintLatin1AltName(out, name);
735
220
  } else if (gen->type == GEN_EMAIL) {
736
4
    ASN1_IA5STRING* name = gen->d.rfc822Name;
737
4
    BIO_write(out.get(), "email:", 6);
738
4
    PrintLatin1AltName(out, name);
739
216
  } else if (gen->type == GEN_URI) {
740
159
    ASN1_IA5STRING* name = gen->d.uniformResourceIdentifier;
741
159
    BIO_write(out.get(), "URI:", 4);
742
    // The set of "safe" names was designed to include just about any URI,
743
    // with a few exceptions, most notably URIs that contains commas (see
744
    // RFC 2396). In other words, most legitimate URIs will not require
745
    // escaping.
746
159
    PrintLatin1AltName(out, name);
747
57
  } else if (gen->type == GEN_DIRNAME) {
748
    // Earlier versions of Node.js used X509_NAME_oneline to print the X509_NAME
749
    // object. The format was non standard and should be avoided. The use of
750
    // X509_NAME_oneline is discouraged by OpenSSL but was required for backward
751
    // compatibility. Conveniently, X509_NAME_oneline produced ASCII and the
752
    // output was unlikely to contains commas or other characters that would
753
    // require escaping. However, it SHOULD NOT produce ASCII output since an
754
    // RFC5280 AttributeValue may be a UTF8String.
755
    // Newer versions of Node.js have since switched to X509_NAME_print_ex to
756
    // produce a better format at the cost of backward compatibility. The new
757
    // format may contain Unicode characters and it is likely to contain commas,
758
    // which require escaping. Fortunately, the recently safeguarded function
759
    // PrintAltName handles all of that safely.
760
14
    BIO_printf(out.get(), "DirName:");
761
14
    BIOPointer tmp(BIO_new(BIO_s_mem()));
762
14
    CHECK(tmp);
763
14
    if (X509_NAME_print_ex(tmp.get(),
764
14
                           gen->d.dirn,
765
                           0,
766
14
                           kX509NameFlagsRFC2253WithinUtf8JSON) < 0) {
767
      return false;
768
    }
769
14
    char* oline = nullptr;
770
14
    size_t n_bytes = BIO_get_mem_data(tmp.get(), &oline);
771

14
    CHECK_IMPLIES(n_bytes != 0, oline != nullptr);
772
14
    PrintAltName(out, oline, n_bytes, true, nullptr);
773
43
  } else if (gen->type == GEN_IPADD) {
774
17
    BIO_printf(out.get(), "IP Address:");
775
17
    const ASN1_OCTET_STRING* ip = gen->d.ip;
776
17
    const unsigned char* b = ip->data;
777
17
    if (ip->length == 4) {
778
11
      BIO_printf(out.get(), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
779
6
    } else if (ip->length == 16) {
780
18
      for (unsigned int j = 0; j < 8; j++) {
781
16
        uint16_t pair = (b[2 * j] << 8) | b[2 * j + 1];
782
16
        BIO_printf(out.get(), (j == 0) ? "%X" : ":%X", pair);
783
      }
784
    } else {
785
#if OPENSSL_VERSION_MAJOR >= 3
786
4
      BIO_printf(out.get(), "<invalid length=%d>", ip->length);
787
#else
788
      BIO_printf(out.get(), "<invalid>");
789
#endif
790
    }
791
26
  } else if (gen->type == GEN_RID) {
792
    // Unlike OpenSSL's default implementation, never print the OID as text and
793
    // instead always print its numeric representation.
794
    char oline[256];
795
4
    OBJ_obj2txt(oline, sizeof(oline), gen->d.rid, true);
796
4
    BIO_printf(out.get(), "Registered ID:%s", oline);
797
22
  } else if (gen->type == GEN_OTHERNAME) {
798
    // TODO(tniessen): the format that is used here is based on OpenSSL's
799
    // implementation of i2v_GENERAL_NAME (as of OpenSSL 3.0.1), mostly for
800
    // backward compatibility. It is somewhat awkward, especially when passed to
801
    // translatePeerCertificate, and should be changed in the future, probably
802
    // to the format used by GENERAL_NAME_print (in a major release).
803
22
    bool unicode = true;
804
22
    const char* prefix = nullptr;
805
    // OpenSSL 1.1.1 does not support othername in i2v_GENERAL_NAME and may not
806
    // define these NIDs.
807
#if OPENSSL_VERSION_MAJOR >= 3
808
22
    int nid = OBJ_obj2nid(gen->d.otherName->type_id);
809

22
    switch (nid) {
810
      case NID_id_on_SmtpUTF8Mailbox:
811
        prefix = " SmtpUTF8Mailbox:";
812
        break;
813
10
      case NID_XmppAddr:
814
10
        prefix = " XmppAddr:";
815
10
        break;
816
8
      case NID_SRVName:
817
8
        prefix = " SRVName:";
818
8
        unicode = false;
819
8
        break;
820
      case NID_ms_upn:
821
        prefix = " UPN:";
822
        break;
823
      case NID_NAIRealm:
824
        prefix = " NAIRealm:";
825
        break;
826
    }
827
#endif  // OPENSSL_VERSION_MAJOR >= 3
828
22
    int val_type = gen->d.otherName->value->type;
829

22
    if (prefix == nullptr ||
830
10
        (unicode && val_type != V_ASN1_UTF8STRING) ||
831

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

159
      !Set<Value>(env->context(),
1146
                  info,
1147
                  env->version_string(),
1148
                  GetCipherVersion(env, ssl))) {
1149
    return MaybeLocal<Object>();
1150
  }
1151
1152
53
  return scope.Escape(info);
1153
}
1154
1155
884
MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1156
884
  CHECK_EQ(SSL_is_server(ssl.get()), 0);
1157
  EVP_PKEY* raw_key;
1158
1159
884
  EscapableHandleScope scope(env->isolate());
1160
884
  Local<Object> info = Object::New(env->isolate());
1161
884
  if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1162
30
    return scope.Escape(info);
1163
1164
854
  Local<Context> context = env->context();
1165
1708
  crypto::EVPKeyPointer key(raw_key);
1166
1167
854
  int kid = EVP_PKEY_id(key.get());
1168
854
  int bits = EVP_PKEY_bits(key.get());
1169
854
  switch (kid) {
1170
7
    case EVP_PKEY_DH:
1171
28
      if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1172

28
          !Set<Integer>(context,
1173
               info,
1174
               env->size_string(),
1175
               Integer::New(env->isolate(), bits))) {
1176
        return MaybeLocal<Object>();
1177
      }
1178
7
      break;
1179
847
    case EVP_PKEY_EC:
1180
    case EVP_PKEY_X25519:
1181
    case EVP_PKEY_X448:
1182
      {
1183
        const char* curve_name;
1184
847
        if (kid == EVP_PKEY_EC) {
1185
10
          ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1186
5
          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1187
5
          curve_name = OBJ_nid2sn(nid);
1188
        } else {
1189
842
          curve_name = OBJ_nid2sn(kid);
1190
        }
1191
2541
        if (!Set<String>(context,
1192
                         info,
1193
                         env->type_string(),
1194
847
                         env->ecdh_string()) ||
1195
2541
            !Set<String>(context,
1196
                info,
1197
                env->name_string(),
1198
1694
                OneByteString(env->isolate(), curve_name)) ||
1199

3388
            !Set<Integer>(context,
1200
                 info,
1201
                 env->size_string(),
1202
                 Integer::New(env->isolate(), bits))) {
1203
          return MaybeLocal<Object>();
1204
847
        }
1205
      }
1206
847
      break;
1207
  }
1208
1209
854
  return scope.Escape(info);
1210
}
1211
1212
73
MaybeLocal<Object> ECPointToBuffer(Environment* env,
1213
                                   const EC_GROUP* group,
1214
                                   const EC_POINT* point,
1215
                                   point_conversion_form_t form,
1216
                                   const char** error) {
1217
73
  size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
1218
73
  if (len == 0) {
1219
    if (error != nullptr) *error = "Failed to get public key length";
1220
    return MaybeLocal<Object>();
1221
  }
1222
1223
73
  std::unique_ptr<BackingStore> bs;
1224
  {
1225
73
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1226
73
    bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
1227
  }
1228
1229
146
  len = EC_POINT_point2oct(group,
1230
                           point,
1231
                           form,
1232
73
                           reinterpret_cast<unsigned char*>(bs->Data()),
1233
                           bs->ByteLength(),
1234
                           nullptr);
1235
73
  if (len == 0) {
1236
    if (error != nullptr) *error = "Failed to get public key";
1237
    return MaybeLocal<Object>();
1238
  }
1239
1240
73
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
1241
146
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
1242
}
1243
1244
496
MaybeLocal<Value> GetPeerCert(
1245
    Environment* env,
1246
    const SSLPointer& ssl,
1247
    bool abbreviated,
1248
    bool is_server) {
1249
496
  ClearErrorOnReturn clear_error_on_return;
1250
  Local<Object> result;
1251
  MaybeLocal<Object> maybe_cert;
1252
1253
  // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1254
  // contains the `peer_certificate`, but on server it doesn't.
1255
992
  X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr);
1256
496
  STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get());
1257


496
  if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
1258
10
    return Undefined(env->isolate());
1259
1260
  // Short result requested.
1261
491
  if (abbreviated) {
1262
    maybe_cert =
1263
43
        X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0));
1264
86
    return maybe_cert.ToLocal(&result) ? result : MaybeLocal<Value>();
1265
  }
1266
1267
896
  StackOfX509 peer_certs = CloneSSLCerts(std::move(cert), ssl_certs);
1268
448
  if (peer_certs == nullptr)
1269
    return Undefined(env->isolate());
1270
1271
  // First and main certificate.
1272
896
  X509Pointer first_cert(sk_X509_value(peer_certs.get(), 0));
1273
448
  CHECK(first_cert);
1274
448
  maybe_cert = X509ToObject(env, first_cert.release());
1275
448
  if (!maybe_cert.ToLocal(&result))
1276
    return MaybeLocal<Value>();
1277
1278
  Local<Object> issuer_chain;
1279
  MaybeLocal<Object> maybe_issuer_chain;
1280
1281
  maybe_issuer_chain =
1282
      AddIssuerChainToObject(
1283
          &cert,
1284
          result,
1285
448
          std::move(peer_certs),
1286
448
          env);
1287
448
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1288
    return MaybeLocal<Value>();
1289
1290
  maybe_issuer_chain =
1291
      GetLastIssuedCert(
1292
          &cert,
1293
          ssl,
1294
          issuer_chain,
1295
448
          env);
1296
1297
  issuer_chain.Clear();
1298
448
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1299
    return MaybeLocal<Value>();
1300
1301
  // Last certificate should be self-signed.
1302
895
  if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK &&
1303

1342
      !Set<Object>(env->context(),
1304
           issuer_chain,
1305
           env->issuercert_string(),
1306
           issuer_chain)) {
1307
    return MaybeLocal<Value>();
1308
  }
1309
1310
448
  return result;
1311
}
1312
1313
1215
MaybeLocal<Object> X509ToObject(
1314
    Environment* env,
1315
    X509* cert,
1316
    bool names_as_string) {
1317
1215
  EscapableHandleScope scope(env->isolate());
1318
1215
  Local<Context> context = env->context();
1319
1215
  Local<Object> info = Object::New(env->isolate());
1320
1321
2430
  BIOPointer bio(BIO_new(BIO_s_mem()));
1322
1215
  CHECK(bio);
1323
1324
1215
  if (names_as_string) {
1325
    // TODO(tniessen): this branch should not have to exist. It is only here
1326
    // because toLegacyObject() does not actually return a legacy object, and
1327
    // instead represents subject and issuer as strings.
1328
2
    if (!Set<Value>(context,
1329
                    info,
1330
                    env->subject_string(),
1331
2
                    GetSubject(env, bio, cert)) ||
1332

3
        !Set<Value>(context,
1333
                    info,
1334
                    env->issuer_string(),
1335
                    GetIssuerString(env, bio, cert))) {
1336
      return MaybeLocal<Object>();
1337
    }
1338
  } else {
1339
2428
    if (!Set<Value>(context,
1340
                    info,
1341
                    env->subject_string(),
1342
2428
                    GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1343

3642
        !Set<Value>(context,
1344
                    info,
1345
                    env->issuer_string(),
1346
                    GetX509NameObject<X509_get_issuer_name>(env, cert))) {
1347
      return MaybeLocal<Object>();
1348
    }
1349
  }
1350
1351
2430
  if (!Set<Value>(context,
1352
                  info,
1353
                  env->subjectaltname_string(),
1354
2430
                  GetSubjectAltNameString(env, bio, cert)) ||
1355

3645
      !Set<Value>(context,
1356
                  info,
1357
                  env->infoaccess_string(),
1358
                  GetInfoAccessString(env, bio, cert))) {
1359
    return MaybeLocal<Object>();
1360
  }
1361
1362
2430
  EVPKeyPointer pkey(X509_get_pubkey(cert));
1363
1215
  RSAPointer rsa;
1364
1215
  ECPointer ec;
1365
1215
  if (pkey) {
1366
1215
    switch (EVP_PKEY_id(pkey.get())) {
1367
1168
      case EVP_PKEY_RSA:
1368
1168
        rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1369
1168
        break;
1370
47
      case EVP_PKEY_EC:
1371
47
        ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1372
47
        break;
1373
    }
1374
  }
1375
1376
1215
  if (rsa) {
1377
    const BIGNUM* n;
1378
    const BIGNUM* e;
1379
1168
    RSA_get0_key(rsa.get(), &n, &e, nullptr);
1380
2336
    if (!Set<Value>(context,
1381
                    info,
1382
                    env->modulus_string(),
1383
1168
                    GetModulusString(env, bio, n)) ||
1384
3504
        !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1385
2336
        !Set<Value>(context,
1386
                    info,
1387
                    env->exponent_string(),
1388
2336
                    GetExponentString(env, bio, e)) ||
1389

3504
        !Set<Object>(context,
1390
                     info,
1391
                     env->pubkey_string(),
1392
                     GetPubKey(env, rsa))) {
1393
      return MaybeLocal<Object>();
1394
    }
1395
47
  } else if (ec) {
1396
47
    const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1397
1398
94
    if (!Set<Value>(context,
1399
                    info,
1400
                    env->bits_string(),
1401
94
                    GetECGroup(env, group, ec)) ||
1402

141
        !Set<Value>(context,
1403
                    info,
1404
                    env->pubkey_string(),
1405
                    GetECPubKey(env, group, ec))) {
1406
      return MaybeLocal<Object>();
1407
    }
1408
1409
47
    const int nid = EC_GROUP_get_curve_name(group);
1410
47
    if (nid != 0) {
1411
      // Curve is well-known, get its OID and NIST nick-name (if it has one).
1412
1413
94
      if (!Set<Value>(context,
1414
                      info,
1415
                      env->asn1curve_string(),
1416
94
                      GetCurveASN1Name(env, nid)) ||
1417

141
          !Set<Value>(context,
1418
                      info,
1419
                      env->nistcurve_string(),
1420
                      GetCurveNistName(env, nid))) {
1421
        return MaybeLocal<Object>();
1422
      }
1423
    } else {
1424
      // Unnamed curves can be described by their mathematical properties,
1425
      // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1426
    }
1427
  }
1428
1429
  // pkey, rsa, and ec pointers are no longer needed.
1430
1215
  pkey.reset();
1431
1215
  rsa.reset();
1432
1215
  ec.reset();
1433
1434
2430
  if (!Set<Value>(context,
1435
                  info,
1436
                  env->valid_from_string(),
1437
2430
                  GetValidFrom(env, cert, bio)) ||
1438

3645
      !Set<Value>(context,
1439
                  info,
1440
                  env->valid_to_string(),
1441
                  GetValidTo(env, cert, bio))) {
1442
    return MaybeLocal<Object>();
1443
  }
1444
1445
  // bio is no longer needed
1446
1215
  bio.reset();
1447
1448
2430
  if (!Set<Value>(context,
1449
                  info,
1450
                  env->fingerprint_string(),
1451
1215
                  GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1452
2430
      !Set<Value>(context,
1453
                  info,
1454
                  env->fingerprint256_string(),
1455
1215
                  GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1456
2430
      !Set<Value>(context,
1457
                  info,
1458
                  env->fingerprint512_string(),
1459
1215
                  GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1460
2430
      !Set<Value>(context,
1461
                  info,
1462
                  env->ext_key_usage_string(),
1463
1215
                  GetKeyUsage(env, cert)) ||
1464
2430
      !Set<Value>(context,
1465
                  info,
1466
                  env->serial_number_string(),
1467
2430
                  GetSerialNumber(env, cert)) ||
1468

3645
      !Set<Object>(context,
1469
                   info,
1470
                   env->raw_string(),
1471
                   GetRawDERCertificate(env, cert))) {
1472
    return MaybeLocal<Object>();
1473
  }
1474
1475
1215
  return scope.Escape(info);
1476
}
1477
1478
}  // namespace crypto
1479
}  // namespace node