GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_common.cc Lines: 520 683 76.1 %
Date: 2022-06-06 04:15:48 Branches: 281 487 57.7 %

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

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

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

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

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







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

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

319
        if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
613
7
          return false;
614
        }
615
      } else {
616
        // Check if the char is a control character or non-ASCII character. Note
617
        // that char may or may not be a signed type. Regardless, non-ASCII
618
        // values will always be outside of this range.
619

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


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

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

26
    switch (nid) {
771
      case NID_id_on_SmtpUTF8Mailbox:
772
        prefix = "SmtpUTF8Mailbox";
773
        break;
774
12
      case NID_XmppAddr:
775
12
        prefix = "XmppAddr";
776
12
        break;
777
9
      case NID_SRVName:
778
9
        prefix = "SRVName";
779
9
        unicode = false;
780
9
        break;
781
      case NID_ms_upn:
782
        prefix = "UPN";
783
        break;
784
      case NID_NAIRealm:
785
        prefix = "NAIRealm";
786
        break;
787
    }
788
#endif  // OPENSSL_VERSION_MAJOR >= 3
789
26
    int val_type = gen->d.otherName->value->type;
790

26
    if (prefix == nullptr ||
791
12
        (unicode && val_type != V_ASN1_UTF8STRING) ||
792

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

159
      !Set<Value>(env->context(),
1099
                  info,
1100
                  env->version_string(),
1101
                  GetCurrentCipherValue<GetCipherVersion>(env, ssl))) {
1102
    return MaybeLocal<Object>();
1103
  }
1104
1105
53
  return scope.Escape(info);
1106
}
1107
1108
891
MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1109
891
  CHECK_EQ(SSL_is_server(ssl.get()), 0);
1110
  EVP_PKEY* raw_key;
1111
1112
891
  EscapableHandleScope scope(env->isolate());
1113
891
  Local<Object> info = Object::New(env->isolate());
1114
891
  if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1115
30
    return scope.Escape(info);
1116
1117
861
  Local<Context> context = env->context();
1118
1722
  crypto::EVPKeyPointer key(raw_key);
1119
1120
861
  int kid = EVP_PKEY_id(key.get());
1121
861
  int bits = EVP_PKEY_bits(key.get());
1122
861
  switch (kid) {
1123
7
    case EVP_PKEY_DH:
1124
28
      if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1125

28
          !Set<Integer>(context,
1126
               info,
1127
               env->size_string(),
1128
               Integer::New(env->isolate(), bits))) {
1129
        return MaybeLocal<Object>();
1130
      }
1131
7
      break;
1132
854
    case EVP_PKEY_EC:
1133
    case EVP_PKEY_X25519:
1134
    case EVP_PKEY_X448:
1135
      {
1136
        const char* curve_name;
1137
854
        if (kid == EVP_PKEY_EC) {
1138
10
          ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1139
5
          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1140
5
          curve_name = OBJ_nid2sn(nid);
1141
        } else {
1142
849
          curve_name = OBJ_nid2sn(kid);
1143
        }
1144
2562
        if (!Set<String>(context,
1145
                         info,
1146
                         env->type_string(),
1147
854
                         env->ecdh_string()) ||
1148
2562
            !Set<String>(context,
1149
                info,
1150
                env->name_string(),
1151
1708
                OneByteString(env->isolate(), curve_name)) ||
1152

3416
            !Set<Integer>(context,
1153
                 info,
1154
                 env->size_string(),
1155
                 Integer::New(env->isolate(), bits))) {
1156
          return MaybeLocal<Object>();
1157
854
        }
1158
      }
1159
854
      break;
1160
  }
1161
1162
861
  return scope.Escape(info);
1163
}
1164
1165
73
MaybeLocal<Object> ECPointToBuffer(Environment* env,
1166
                                   const EC_GROUP* group,
1167
                                   const EC_POINT* point,
1168
                                   point_conversion_form_t form,
1169
                                   const char** error) {
1170
73
  size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
1171
73
  if (len == 0) {
1172
    if (error != nullptr) *error = "Failed to get public key length";
1173
    return MaybeLocal<Object>();
1174
  }
1175
1176
73
  std::unique_ptr<BackingStore> bs;
1177
  {
1178
73
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1179
73
    bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
1180
  }
1181
1182
146
  len = EC_POINT_point2oct(group,
1183
                           point,
1184
                           form,
1185
73
                           reinterpret_cast<unsigned char*>(bs->Data()),
1186
                           bs->ByteLength(),
1187
                           nullptr);
1188
73
  if (len == 0) {
1189
    if (error != nullptr) *error = "Failed to get public key";
1190
    return MaybeLocal<Object>();
1191
  }
1192
1193
73
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
1194
146
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
1195
}
1196
1197
497
MaybeLocal<Value> GetPeerCert(
1198
    Environment* env,
1199
    const SSLPointer& ssl,
1200
    bool abbreviated,
1201
    bool is_server) {
1202
497
  ClearErrorOnReturn clear_error_on_return;
1203
  Local<Object> result;
1204
  MaybeLocal<Object> maybe_cert;
1205
1206
  // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1207
  // contains the `peer_certificate`, but on server it doesn't.
1208
994
  X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr);
1209
497
  STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get());
1210


497
  if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
1211
10
    return Undefined(env->isolate());
1212
1213
  // Short result requested.
1214
492
  if (abbreviated) {
1215
    maybe_cert =
1216
43
        X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0));
1217
86
    return maybe_cert.ToLocal(&result) ? result : MaybeLocal<Value>();
1218
  }
1219
1220
898
  StackOfX509 peer_certs = CloneSSLCerts(std::move(cert), ssl_certs);
1221
449
  if (peer_certs == nullptr)
1222
    return Undefined(env->isolate());
1223
1224
  // First and main certificate.
1225
898
  X509Pointer first_cert(sk_X509_value(peer_certs.get(), 0));
1226
449
  CHECK(first_cert);
1227
449
  maybe_cert = X509ToObject(env, first_cert.release());
1228
449
  if (!maybe_cert.ToLocal(&result))
1229
    return MaybeLocal<Value>();
1230
1231
  Local<Object> issuer_chain;
1232
  MaybeLocal<Object> maybe_issuer_chain;
1233
1234
  maybe_issuer_chain =
1235
      AddIssuerChainToObject(
1236
          &cert,
1237
          result,
1238
449
          std::move(peer_certs),
1239
449
          env);
1240
449
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1241
    return MaybeLocal<Value>();
1242
1243
  maybe_issuer_chain =
1244
      GetLastIssuedCert(
1245
          &cert,
1246
          ssl,
1247
          issuer_chain,
1248
449
          env);
1249
1250
  issuer_chain.Clear();
1251
449
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1252
    return MaybeLocal<Value>();
1253
1254
  // Last certificate should be self-signed.
1255
897
  if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK &&
1256

1345
      !Set<Object>(env->context(),
1257
           issuer_chain,
1258
           env->issuercert_string(),
1259
           issuer_chain)) {
1260
    return MaybeLocal<Value>();
1261
  }
1262
1263
449
  return result;
1264
}
1265
1266
1232
MaybeLocal<Object> X509ToObject(
1267
    Environment* env,
1268
    X509* cert) {
1269
1232
  EscapableHandleScope scope(env->isolate());
1270
1232
  Local<Context> context = env->context();
1271
1232
  Local<Object> info = Object::New(env->isolate());
1272
1273
2464
  BIOPointer bio(BIO_new(BIO_s_mem()));
1274
1232
  CHECK(bio);
1275
1276
2464
  if (!Set<Value>(context,
1277
                  info,
1278
                  env->subject_string(),
1279
1232
                  GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1280
2464
      !Set<Value>(context,
1281
                  info,
1282
                  env->issuer_string(),
1283
1232
                  GetX509NameObject<X509_get_issuer_name>(env, cert)) ||
1284
2464
      !Set<Value>(context,
1285
                  info,
1286
                  env->subjectaltname_string(),
1287
2464
                  GetSubjectAltNameString(env, bio, cert)) ||
1288

3696
      !Set<Value>(context,
1289
                  info,
1290
                  env->infoaccess_string(),
1291
                  GetInfoAccessString(env, bio, cert))) {
1292
    return MaybeLocal<Object>();
1293
  }
1294
1295
2464
  EVPKeyPointer pkey(X509_get_pubkey(cert));
1296
1232
  RSAPointer rsa;
1297
1232
  ECPointer ec;
1298
1232
  if (pkey) {
1299
1232
    switch (EVP_PKEY_id(pkey.get())) {
1300
1185
      case EVP_PKEY_RSA:
1301
1185
        rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1302
1185
        break;
1303
47
      case EVP_PKEY_EC:
1304
47
        ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1305
47
        break;
1306
    }
1307
  }
1308
1309
1232
  if (rsa) {
1310
    const BIGNUM* n;
1311
    const BIGNUM* e;
1312
1185
    RSA_get0_key(rsa.get(), &n, &e, nullptr);
1313
2370
    if (!Set<Value>(context,
1314
                    info,
1315
                    env->modulus_string(),
1316
1185
                    GetModulusString(env, bio, n)) ||
1317
3555
        !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1318
2370
        !Set<Value>(context,
1319
                    info,
1320
                    env->exponent_string(),
1321
2370
                    GetExponentString(env, bio, e)) ||
1322

3555
        !Set<Object>(context,
1323
                     info,
1324
                     env->pubkey_string(),
1325
                     GetPubKey(env, rsa))) {
1326
      return MaybeLocal<Object>();
1327
    }
1328
47
  } else if (ec) {
1329
47
    const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1330
1331
94
    if (!Set<Value>(context,
1332
                    info,
1333
                    env->bits_string(),
1334
94
                    GetECGroup(env, group, ec)) ||
1335

141
        !Set<Value>(context,
1336
                    info,
1337
                    env->pubkey_string(),
1338
                    GetECPubKey(env, group, ec))) {
1339
      return MaybeLocal<Object>();
1340
    }
1341
1342
47
    const int nid = EC_GROUP_get_curve_name(group);
1343
47
    if (nid != 0) {
1344
      // Curve is well-known, get its OID and NIST nick-name (if it has one).
1345
1346
94
      if (!Set<Value>(context,
1347
                      info,
1348
                      env->asn1curve_string(),
1349
94
                      GetCurveName<OBJ_nid2sn>(env, nid)) ||
1350

141
          !Set<Value>(context,
1351
                      info,
1352
                      env->nistcurve_string(),
1353
                      GetCurveName<EC_curve_nid2nist>(env, nid))) {
1354
        return MaybeLocal<Object>();
1355
      }
1356
    } else {
1357
      // Unnamed curves can be described by their mathematical properties,
1358
      // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1359
    }
1360
  }
1361
1362
  // pkey, rsa, and ec pointers are no longer needed.
1363
1232
  pkey.reset();
1364
1232
  rsa.reset();
1365
1232
  ec.reset();
1366
1367
2464
  if (!Set<Value>(context,
1368
                  info,
1369
                  env->valid_from_string(),
1370
2464
                  GetValidFrom(env, cert, bio)) ||
1371

3696
      !Set<Value>(context,
1372
                  info,
1373
                  env->valid_to_string(),
1374
                  GetValidTo(env, cert, bio))) {
1375
    return MaybeLocal<Object>();
1376
  }
1377
1378
  // bio is no longer needed
1379
1232
  bio.reset();
1380
1381
2464
  if (!Set<Value>(context,
1382
                  info,
1383
                  env->fingerprint_string(),
1384
1232
                  GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1385
2464
      !Set<Value>(context,
1386
                  info,
1387
                  env->fingerprint256_string(),
1388
1232
                  GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1389
2464
      !Set<Value>(context,
1390
                  info,
1391
                  env->fingerprint512_string(),
1392
1232
                  GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1393
2464
      !Set<Value>(context,
1394
                  info,
1395
                  env->ext_key_usage_string(),
1396
1232
                  GetKeyUsage(env, cert)) ||
1397
2464
      !Set<Value>(context,
1398
                  info,
1399
                  env->serial_number_string(),
1400
2464
                  GetSerialNumber(env, cert)) ||
1401

3696
      !Set<Object>(context,
1402
                   info,
1403
                   env->raw_string(),
1404
                   GetRawDERCertificate(env, cert))) {
1405
    return MaybeLocal<Object>();
1406
  }
1407
1408
1232
  return scope.Escape(info);
1409
}
1410
1411
}  // namespace crypto
1412
}  // namespace node