GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_common.cc Lines: 529 691 76.6 %
Date: 2022-04-12 04:14:44 Branches: 279 485 57.5 %

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
bool 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
114
bool SetTLSSession(
120
    const SSLPointer& ssl,
121
    const SSLSessionPointer& session) {
122

114
  return session != nullptr && SSL_set_session(ssl.get(), session.get()) == 1;
123
}
124
125
114
SSLSessionPointer GetTLSSession(const unsigned char* buf, size_t length) {
126
114
  return SSLSessionPointer(d2i_SSL_SESSION(nullptr, &buf, length));
127
}
128
129
960
long VerifyPeerCertificate(  // NOLINT(runtime/int)
130
    const SSLPointer& ssl,
131
    long def) {  // NOLINT(runtime/int)
132
960
  long err = def;  // NOLINT(runtime/int)
133
960
  if (X509* peer_cert = SSL_get_peer_certificate(ssl.get())) {
134
934
    X509_free(peer_cert);
135
934
    err = SSL_get_verify_result(ssl.get());
136
  } else {
137
26
    const SSL_CIPHER* curr_cipher = SSL_get_current_cipher(ssl.get());
138
26
    const SSL_SESSION* sess = SSL_get_session(ssl.get());
139
    // Allow no-cert for PSK authentication in TLS1.2 and lower.
140
    // In TLS1.3 check that session was reused because TLS1.3 PSK
141
    // looks like session resumption.
142

56
    if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk ||
143
30
        (SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION &&
144
6
         SSL_session_reused(ssl.get()))) {
145
7
      return X509_V_OK;
146
    }
147
  }
148
953
  return err;
149
}
150
151
12
bool UseSNIContext(
152
    const SSLPointer& ssl, BaseObjectPtr<SecureContext> context) {
153
12
  SSL_CTX* ctx = context->ctx_.get();
154
12
  X509* x509 = SSL_CTX_get0_certificate(ctx);
155
12
  EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx);
156
  STACK_OF(X509)* chain;
157
158
12
  int err = SSL_CTX_get0_chain_certs(ctx, &chain);
159
12
  if (err == 1) err = SSL_use_certificate(ssl.get(), x509);
160
12
  if (err == 1) err = SSL_use_PrivateKey(ssl.get(), pkey);
161

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







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

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

319
        if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
622
7
          return false;
623
        }
624
      } else {
625
        // Check if the char is a control character or non-ASCII character. Note
626
        // that char may or may not be a signed type. Regardless, non-ASCII
627
        // values will always be outside of this range.
628

4491
        if (c < ' ' || c > '~') {
629
14
          return false;
630
        }
631
      }
632
    }
633
  }
634
178
  return true;
635
}
636
637
224
static inline void PrintAltName(const BIOPointer& out, const char* name,
638
                                size_t length, bool utf8,
639
                                const char* safe_prefix) {
640
224
  if (IsSafeAltName(name, length, utf8)) {
641
    // For backward-compatibility, append "safe" names without any
642
    // modifications.
643
178
    if (safe_prefix != nullptr) {
644
10
      BIO_printf(out.get(), "%s:", safe_prefix);
645
    }
646
178
    BIO_write(out.get(), name, length);
647
  } else {
648
    // If a name is not "safe", we cannot embed it without special
649
    // encoding. This does not usually happen, but we don't want to hide
650
    // it from the user either. We use JSON compatible escaping here.
651
46
    BIO_write(out.get(), "\"", 1);
652
46
    if (safe_prefix != nullptr) {
653
9
      BIO_printf(out.get(), "%s:", safe_prefix);
654
    }
655
1601
    for (size_t j = 0; j < length; j++) {
656
1555
      char c = static_cast<char>(name[j]);
657
1555
      if (c == '\\') {
658
10
        BIO_write(out.get(), "\\\\", 2);
659
1545
      } else if (c == '"') {
660
4
        BIO_write(out.get(), "\\\"", 2);
661


1541
      } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) {
662
        // Note that the above condition explicitly excludes commas, which means
663
        // that those are encoded as Unicode escape sequences in the "else"
664
        // block. That is not strictly necessary, and Node.js itself would parse
665
        // it correctly either way. We only do this to account for third-party
666
        // code that might be splitting the string at commas (as Node.js itself
667
        // used to do).
668
1483
        BIO_write(out.get(), &c, 1);
669
      } else {
670
        // Control character or non-ASCII character. We treat everything as
671
        // Latin-1, which corresponds to the first 255 Unicode code points.
672
58
        const char hex[] = "0123456789abcdef";
673
58
        char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] };
674
58
        BIO_write(out.get(), u, sizeof(u));
675
      }
676
    }
677
46
    BIO_write(out.get(), "\"", 1);
678
  }
679
224
}
680
681
198
static inline void PrintLatin1AltName(const BIOPointer& out,
682
                                      const ASN1_IA5STRING* name,
683
                                      const char* safe_prefix = nullptr) {
684
198
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
685
               false, safe_prefix);
686
198
}
687
688
12
static inline void PrintUtf8AltName(const BIOPointer& out,
689
                                    const ASN1_UTF8STRING* name,
690
                                    const char* safe_prefix = nullptr) {
691
12
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
692
               true, safe_prefix);
693
12
}
694
695
// This function emulates the behavior of i2v_GENERAL_NAME in a safer and less
696
// ambiguous way. "othername:" entries use the GENERAL_NAME_print format.
697
252
static bool PrintGeneralName(const BIOPointer& out, const GENERAL_NAME* gen) {
698
252
  if (gen->type == GEN_DNS) {
699
25
    ASN1_IA5STRING* name = gen->d.dNSName;
700
25
    BIO_write(out.get(), "DNS:", 4);
701
    // Note that the preferred name syntax (see RFCs 5280 and 1034) with
702
    // wildcards is a subset of what we consider "safe", so spec-compliant DNS
703
    // names will never need to be escaped.
704
25
    PrintLatin1AltName(out, name);
705
227
  } else if (gen->type == GEN_EMAIL) {
706
4
    ASN1_IA5STRING* name = gen->d.rfc822Name;
707
4
    BIO_write(out.get(), "email:", 6);
708
4
    PrintLatin1AltName(out, name);
709
223
  } else if (gen->type == GEN_URI) {
710
162
    ASN1_IA5STRING* name = gen->d.uniformResourceIdentifier;
711
162
    BIO_write(out.get(), "URI:", 4);
712
    // The set of "safe" names was designed to include just about any URI,
713
    // with a few exceptions, most notably URIs that contains commas (see
714
    // RFC 2396). In other words, most legitimate URIs will not require
715
    // escaping.
716
162
    PrintLatin1AltName(out, name);
717
61
  } else if (gen->type == GEN_DIRNAME) {
718
    // Earlier versions of Node.js used X509_NAME_oneline to print the X509_NAME
719
    // object. The format was non standard and should be avoided. The use of
720
    // X509_NAME_oneline is discouraged by OpenSSL but was required for backward
721
    // compatibility. Conveniently, X509_NAME_oneline produced ASCII and the
722
    // output was unlikely to contains commas or other characters that would
723
    // require escaping. However, it SHOULD NOT produce ASCII output since an
724
    // RFC5280 AttributeValue may be a UTF8String.
725
    // Newer versions of Node.js have since switched to X509_NAME_print_ex to
726
    // produce a better format at the cost of backward compatibility. The new
727
    // format may contain Unicode characters and it is likely to contain commas,
728
    // which require escaping. Fortunately, the recently safeguarded function
729
    // PrintAltName handles all of that safely.
730
14
    BIO_printf(out.get(), "DirName:");
731
14
    BIOPointer tmp(BIO_new(BIO_s_mem()));
732
14
    CHECK(tmp);
733
14
    if (X509_NAME_print_ex(tmp.get(),
734
14
                           gen->d.dirn,
735
                           0,
736
14
                           kX509NameFlagsRFC2253WithinUtf8JSON) < 0) {
737
      return false;
738
    }
739
14
    char* oline = nullptr;
740
14
    long n_bytes = BIO_get_mem_data(tmp.get(), &oline);  // NOLINT(runtime/int)
741
14
    CHECK_GE(n_bytes, 0);
742

14
    CHECK_IMPLIES(n_bytes != 0, oline != nullptr);
743
14
    PrintAltName(out, oline, static_cast<size_t>(n_bytes), true, nullptr);
744
47
  } else if (gen->type == GEN_IPADD) {
745
17
    BIO_printf(out.get(), "IP Address:");
746
17
    const ASN1_OCTET_STRING* ip = gen->d.ip;
747
17
    const unsigned char* b = ip->data;
748
17
    if (ip->length == 4) {
749
11
      BIO_printf(out.get(), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
750
6
    } else if (ip->length == 16) {
751
18
      for (unsigned int j = 0; j < 8; j++) {
752
16
        uint16_t pair = (b[2 * j] << 8) | b[2 * j + 1];
753
16
        BIO_printf(out.get(), (j == 0) ? "%X" : ":%X", pair);
754
      }
755
    } else {
756
#if OPENSSL_VERSION_MAJOR >= 3
757
4
      BIO_printf(out.get(), "<invalid length=%d>", ip->length);
758
#else
759
      BIO_printf(out.get(), "<invalid>");
760
#endif
761
    }
762
30
  } else if (gen->type == GEN_RID) {
763
    // Unlike OpenSSL's default implementation, never print the OID as text and
764
    // instead always print its numeric representation.
765
    char oline[256];
766
4
    OBJ_obj2txt(oline, sizeof(oline), gen->d.rid, true);
767
4
    BIO_printf(out.get(), "Registered ID:%s", oline);
768
26
  } else if (gen->type == GEN_OTHERNAME) {
769
    // The format that is used here is based on OpenSSL's implementation of
770
    // GENERAL_NAME_print (as of OpenSSL 3.0.1). Earlier versions of Node.js
771
    // instead produced the same format as i2v_GENERAL_NAME, which was somewhat
772
    // awkward, especially when passed to translatePeerCertificate.
773
26
    bool unicode = true;
774
26
    const char* prefix = nullptr;
775
    // OpenSSL 1.1.1 does not support othername in GENERAL_NAME_print and may
776
    // not define these NIDs.
777
#if OPENSSL_VERSION_MAJOR >= 3
778
26
    int nid = OBJ_obj2nid(gen->d.otherName->type_id);
779

26
    switch (nid) {
780
      case NID_id_on_SmtpUTF8Mailbox:
781
        prefix = "SmtpUTF8Mailbox";
782
        break;
783
12
      case NID_XmppAddr:
784
12
        prefix = "XmppAddr";
785
12
        break;
786
9
      case NID_SRVName:
787
9
        prefix = "SRVName";
788
9
        unicode = false;
789
9
        break;
790
      case NID_ms_upn:
791
        prefix = "UPN";
792
        break;
793
      case NID_NAIRealm:
794
        prefix = "NAIRealm";
795
        break;
796
    }
797
#endif  // OPENSSL_VERSION_MAJOR >= 3
798
26
    int val_type = gen->d.otherName->value->type;
799

26
    if (prefix == nullptr ||
800
12
        (unicode && val_type != V_ASN1_UTF8STRING) ||
801

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

159
      !Set<Value>(env->context(),
1116
                  info,
1117
                  env->version_string(),
1118
                  GetCipherVersion(env, ssl))) {
1119
    return MaybeLocal<Object>();
1120
  }
1121
1122
53
  return scope.Escape(info);
1123
}
1124
1125
887
MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1126
887
  CHECK_EQ(SSL_is_server(ssl.get()), 0);
1127
  EVP_PKEY* raw_key;
1128
1129
887
  EscapableHandleScope scope(env->isolate());
1130
887
  Local<Object> info = Object::New(env->isolate());
1131
887
  if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1132
30
    return scope.Escape(info);
1133
1134
857
  Local<Context> context = env->context();
1135
1714
  crypto::EVPKeyPointer key(raw_key);
1136
1137
857
  int kid = EVP_PKEY_id(key.get());
1138
857
  int bits = EVP_PKEY_bits(key.get());
1139
857
  switch (kid) {
1140
7
    case EVP_PKEY_DH:
1141
28
      if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1142

28
          !Set<Integer>(context,
1143
               info,
1144
               env->size_string(),
1145
               Integer::New(env->isolate(), bits))) {
1146
        return MaybeLocal<Object>();
1147
      }
1148
7
      break;
1149
850
    case EVP_PKEY_EC:
1150
    case EVP_PKEY_X25519:
1151
    case EVP_PKEY_X448:
1152
      {
1153
        const char* curve_name;
1154
850
        if (kid == EVP_PKEY_EC) {
1155
10
          ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1156
5
          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1157
5
          curve_name = OBJ_nid2sn(nid);
1158
        } else {
1159
845
          curve_name = OBJ_nid2sn(kid);
1160
        }
1161
2550
        if (!Set<String>(context,
1162
                         info,
1163
                         env->type_string(),
1164
850
                         env->ecdh_string()) ||
1165
2550
            !Set<String>(context,
1166
                info,
1167
                env->name_string(),
1168
1700
                OneByteString(env->isolate(), curve_name)) ||
1169

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


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

1342
      !Set<Object>(env->context(),
1274
           issuer_chain,
1275
           env->issuercert_string(),
1276
           issuer_chain)) {
1277
    return MaybeLocal<Value>();
1278
  }
1279
1280
448
  return result;
1281
}
1282
1283
1230
MaybeLocal<Object> X509ToObject(
1284
    Environment* env,
1285
    X509* cert) {
1286
1230
  EscapableHandleScope scope(env->isolate());
1287
1230
  Local<Context> context = env->context();
1288
1230
  Local<Object> info = Object::New(env->isolate());
1289
1290
2460
  BIOPointer bio(BIO_new(BIO_s_mem()));
1291
1230
  CHECK(bio);
1292
1293
2460
  if (!Set<Value>(context,
1294
                  info,
1295
                  env->subject_string(),
1296
1230
                  GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1297
2460
      !Set<Value>(context,
1298
                  info,
1299
                  env->issuer_string(),
1300
1230
                  GetX509NameObject<X509_get_issuer_name>(env, cert)) ||
1301
2460
      !Set<Value>(context,
1302
                  info,
1303
                  env->subjectaltname_string(),
1304
2460
                  GetSubjectAltNameString(env, bio, cert)) ||
1305

3690
      !Set<Value>(context,
1306
                  info,
1307
                  env->infoaccess_string(),
1308
                  GetInfoAccessString(env, bio, cert))) {
1309
    return MaybeLocal<Object>();
1310
  }
1311
1312
2460
  EVPKeyPointer pkey(X509_get_pubkey(cert));
1313
1230
  RSAPointer rsa;
1314
1230
  ECPointer ec;
1315
1230
  if (pkey) {
1316
1230
    switch (EVP_PKEY_id(pkey.get())) {
1317
1183
      case EVP_PKEY_RSA:
1318
1183
        rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1319
1183
        break;
1320
47
      case EVP_PKEY_EC:
1321
47
        ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1322
47
        break;
1323
    }
1324
  }
1325
1326
1230
  if (rsa) {
1327
    const BIGNUM* n;
1328
    const BIGNUM* e;
1329
1183
    RSA_get0_key(rsa.get(), &n, &e, nullptr);
1330
2366
    if (!Set<Value>(context,
1331
                    info,
1332
                    env->modulus_string(),
1333
1183
                    GetModulusString(env, bio, n)) ||
1334
3549
        !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1335
2366
        !Set<Value>(context,
1336
                    info,
1337
                    env->exponent_string(),
1338
2366
                    GetExponentString(env, bio, e)) ||
1339

3549
        !Set<Object>(context,
1340
                     info,
1341
                     env->pubkey_string(),
1342
                     GetPubKey(env, rsa))) {
1343
      return MaybeLocal<Object>();
1344
    }
1345
47
  } else if (ec) {
1346
47
    const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1347
1348
94
    if (!Set<Value>(context,
1349
                    info,
1350
                    env->bits_string(),
1351
94
                    GetECGroup(env, group, ec)) ||
1352

141
        !Set<Value>(context,
1353
                    info,
1354
                    env->pubkey_string(),
1355
                    GetECPubKey(env, group, ec))) {
1356
      return MaybeLocal<Object>();
1357
    }
1358
1359
47
    const int nid = EC_GROUP_get_curve_name(group);
1360
47
    if (nid != 0) {
1361
      // Curve is well-known, get its OID and NIST nick-name (if it has one).
1362
1363
94
      if (!Set<Value>(context,
1364
                      info,
1365
                      env->asn1curve_string(),
1366
94
                      GetCurveName<OBJ_nid2sn>(env, nid)) ||
1367

141
          !Set<Value>(context,
1368
                      info,
1369
                      env->nistcurve_string(),
1370
                      GetCurveName<EC_curve_nid2nist>(env, nid))) {
1371
        return MaybeLocal<Object>();
1372
      }
1373
    } else {
1374
      // Unnamed curves can be described by their mathematical properties,
1375
      // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1376
    }
1377
  }
1378
1379
  // pkey, rsa, and ec pointers are no longer needed.
1380
1230
  pkey.reset();
1381
1230
  rsa.reset();
1382
1230
  ec.reset();
1383
1384
2460
  if (!Set<Value>(context,
1385
                  info,
1386
                  env->valid_from_string(),
1387
2460
                  GetValidFrom(env, cert, bio)) ||
1388

3690
      !Set<Value>(context,
1389
                  info,
1390
                  env->valid_to_string(),
1391
                  GetValidTo(env, cert, bio))) {
1392
    return MaybeLocal<Object>();
1393
  }
1394
1395
  // bio is no longer needed
1396
1230
  bio.reset();
1397
1398
2460
  if (!Set<Value>(context,
1399
                  info,
1400
                  env->fingerprint_string(),
1401
1230
                  GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1402
2460
      !Set<Value>(context,
1403
                  info,
1404
                  env->fingerprint256_string(),
1405
1230
                  GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1406
2460
      !Set<Value>(context,
1407
                  info,
1408
                  env->fingerprint512_string(),
1409
1230
                  GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1410
2460
      !Set<Value>(context,
1411
                  info,
1412
                  env->ext_key_usage_string(),
1413
1230
                  GetKeyUsage(env, cert)) ||
1414
2460
      !Set<Value>(context,
1415
                  info,
1416
                  env->serial_number_string(),
1417
2460
                  GetSerialNumber(env, cert)) ||
1418

3690
      !Set<Object>(context,
1419
                   info,
1420
                   env->raw_string(),
1421
                   GetRawDERCertificate(env, cert))) {
1422
    return MaybeLocal<Object>();
1423
  }
1424
1425
1230
  return scope.Escape(info);
1426
}
1427
1428
}  // namespace crypto
1429
}  // namespace node