GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: crypto/crypto_common.cc Lines: 519 677 76.7 %
Date: 2022-12-31 04:22:30 Branches: 283 493 57.4 %

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::BackingStore;
30
using v8::Boolean;
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
907
X509Pointer SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert) {
56
907
  X509_STORE* store = SSL_CTX_get_cert_store(ctx);
57
  DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
58
1814
      X509_STORE_CTX_new());
59
907
  X509Pointer result;
60
  X509* issuer;
61
1814
  if (store_ctx.get() != nullptr &&
62

1814
      X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 &&
63
907
      X509_STORE_CTX_get1_issuer(&issuer, store_ctx.get(), cert) == 1) {
64
432
    result.reset(issuer);
65
  }
66
907
  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
  // All supported versions of TLS/SSL fix the client random to the same size.
76
  constexpr size_t kTlsClientRandomSize = SSL3_RANDOM_SIZE;
77
  unsigned char crandom[kTlsClientRandomSize];
78
79
  if (keylog_cb == nullptr ||
80
      SSL_get_client_random(ssl.get(), crandom, kTlsClientRandomSize) !=
81
          kTlsClientRandomSize) {
82
    return;
83
  }
84
85
  std::string line = name;
86
  line += " " + StringBytes::hex_encode(reinterpret_cast<const char*>(crandom),
87
                                        kTlsClientRandomSize);
88
  line += " " + StringBytes::hex_encode(
89
      reinterpret_cast<const char*>(secret), secretlen);
90
  keylog_cb(ssl.get(), line.c_str());
91
}
92
93
4
MaybeLocal<Value> GetSSLOCSPResponse(
94
    Environment* env,
95
    SSL* ssl,
96
    Local<Value> default_value) {
97
  const unsigned char* resp;
98
4
  int len = SSL_get_tlsext_status_ocsp_resp(ssl, &resp);
99
4
  if (resp == nullptr)
100
2
    return default_value;
101
102
  Local<Value> ret;
103
  MaybeLocal<Object> maybe_buffer =
104
2
      Buffer::Copy(env, reinterpret_cast<const char*>(resp), len);
105
106
2
  if (!maybe_buffer.ToLocal(&ret))
107
    return MaybeLocal<Value>();
108
109
2
  return ret;
110
}
111
112
108
bool SetTLSSession(
113
    const SSLPointer& ssl,
114
    const SSLSessionPointer& session) {
115

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

58
    if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk ||
136
32
        (SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION &&
137
7
         SSL_session_reused(ssl.get()))) {
138
7
      return X509_V_OK;
139
    }
140
  }
141
962
  return err;
142
}
143
144
12
bool UseSNIContext(
145
    const SSLPointer& ssl, BaseObjectPtr<SecureContext> context) {
146
12
  SSL_CTX* ctx = context->ctx().get();
147
12
  X509* x509 = SSL_CTX_get0_certificate(ctx);
148
12
  EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx);
149
  STACK_OF(X509)* chain;
150
151
12
  int err = SSL_CTX_get0_chain_certs(ctx, &chain);
152
12
  if (err == 1) err = SSL_use_certificate(ssl.get(), x509);
153
12
  if (err == 1) err = SSL_use_PrivateKey(ssl.get(), pkey);
154

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







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

451
  if (cert && !sk_X509_push(peer_certs.get(), cert.release()))
323
    return StackOfX509();
324
1246
  for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
325
795
    X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i)));
326

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

319
        if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
602
7
          return false;
603
        }
604
      } else {
605
        // Check if the char is a control character or non-ASCII character. Note
606
        // that char may or may not be a signed type. Regardless, non-ASCII
607
        // values will always be outside of this range.
608

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


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

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

26
    switch (nid) {
760
      case NID_id_on_SmtpUTF8Mailbox:
761
        prefix = "SmtpUTF8Mailbox";
762
        break;
763
12
      case NID_XmppAddr:
764
12
        prefix = "XmppAddr";
765
12
        break;
766
9
      case NID_SRVName:
767
9
        prefix = "SRVName";
768
9
        unicode = false;
769
9
        break;
770
      case NID_ms_upn:
771
        prefix = "UPN";
772
        break;
773
      case NID_NAIRealm:
774
        prefix = "NAIRealm";
775
        break;
776
    }
777
#endif  // OPENSSL_VERSION_MAJOR >= 3
778
26
    int val_type = gen->d.otherName->value->type;
779

26
    if (prefix == nullptr ||
780
12
        (unicode && val_type != V_ASN1_UTF8STRING) ||
781

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

171
      !Set<Value>(env->context(),
1087
                  info,
1088
                  env->version_string(),
1089
                  GetCurrentCipherValue<GetCipherVersion>(env, ssl))) {
1090
    return MaybeLocal<Object>();
1091
  }
1092
1093
57
  return scope.Escape(info);
1094
}
1095
1096
896
MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1097
896
  CHECK_EQ(SSL_is_server(ssl.get()), 0);
1098
  EVP_PKEY* raw_key;
1099
1100
896
  EscapableHandleScope scope(env->isolate());
1101
896
  Local<Object> info = Object::New(env->isolate());
1102
896
  if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1103
27
    return scope.Escape(info);
1104
1105
869
  Local<Context> context = env->context();
1106
1738
  crypto::EVPKeyPointer key(raw_key);
1107
1108
869
  int kid = EVP_PKEY_id(key.get());
1109
869
  int bits = EVP_PKEY_bits(key.get());
1110
869
  switch (kid) {
1111
6
    case EVP_PKEY_DH:
1112
24
      if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1113

24
          !Set<Integer>(context,
1114
               info,
1115
               env->size_string(),
1116
               Integer::New(env->isolate(), bits))) {
1117
        return MaybeLocal<Object>();
1118
      }
1119
6
      break;
1120
863
    case EVP_PKEY_EC:
1121
    case EVP_PKEY_X25519:
1122
    case EVP_PKEY_X448:
1123
      {
1124
        const char* curve_name;
1125
863
        if (kid == EVP_PKEY_EC) {
1126
10
          ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1127
5
          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1128
5
          curve_name = OBJ_nid2sn(nid);
1129
        } else {
1130
858
          curve_name = OBJ_nid2sn(kid);
1131
        }
1132
2589
        if (!Set<String>(context,
1133
                         info,
1134
                         env->type_string(),
1135
863
                         env->ecdh_string()) ||
1136
2589
            !Set<String>(context,
1137
                info,
1138
                env->name_string(),
1139
1726
                OneByteString(env->isolate(), curve_name)) ||
1140

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


498
  if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
1199
8
    return Undefined(env->isolate());
1200
1201
  // Short result requested.
1202
494
  if (abbreviated) {
1203
    maybe_cert =
1204
43
        X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0));
1205
86
    return maybe_cert.ToLocal(&result) ? result : MaybeLocal<Value>();
1206
  }
1207
1208
902
  StackOfX509 peer_certs = CloneSSLCerts(std::move(cert), ssl_certs);
1209
451
  if (peer_certs == nullptr)
1210
    return Undefined(env->isolate());
1211
1212
  // First and main certificate.
1213
902
  X509Pointer first_cert(sk_X509_value(peer_certs.get(), 0));
1214
451
  CHECK(first_cert);
1215
451
  maybe_cert = X509ToObject(env, first_cert.release());
1216
451
  if (!maybe_cert.ToLocal(&result))
1217
    return MaybeLocal<Value>();
1218
1219
  Local<Object> issuer_chain;
1220
  MaybeLocal<Object> maybe_issuer_chain;
1221
1222
  maybe_issuer_chain =
1223
      AddIssuerChainToObject(
1224
          &cert,
1225
          result,
1226
451
          std::move(peer_certs),
1227
451
          env);
1228
451
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1229
    return MaybeLocal<Value>();
1230
1231
  maybe_issuer_chain =
1232
      GetLastIssuedCert(
1233
          &cert,
1234
          ssl,
1235
          issuer_chain,
1236
451
          env);
1237
1238
  issuer_chain.Clear();
1239
451
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1240
    return MaybeLocal<Value>();
1241
1242
  // Last certificate should be self-signed.
1243
901
  if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK &&
1244

1351
      !Set<Object>(env->context(),
1245
           issuer_chain,
1246
           env->issuercert_string(),
1247
           issuer_chain)) {
1248
    return MaybeLocal<Value>();
1249
  }
1250
1251
451
  return result;
1252
}
1253
1254
1238
MaybeLocal<Object> X509ToObject(
1255
    Environment* env,
1256
    X509* cert) {
1257
1238
  EscapableHandleScope scope(env->isolate());
1258
1238
  Local<Context> context = env->context();
1259
1238
  Local<Object> info = Object::New(env->isolate());
1260
1261
2476
  BIOPointer bio(BIO_new(BIO_s_mem()));
1262
1238
  CHECK(bio);
1263
1264
  // X509_check_ca() returns a range of values. Only 1 means "is a CA"
1265
1238
  auto is_ca = Boolean::New(env->isolate(), 1 == X509_check_ca(cert));
1266
2476
  if (!Set<Value>(context,
1267
                  info,
1268
                  env->subject_string(),
1269
1238
                  GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1270
2476
      !Set<Value>(context,
1271
                  info,
1272
                  env->issuer_string(),
1273
1238
                  GetX509NameObject<X509_get_issuer_name>(env, cert)) ||
1274
2476
      !Set<Value>(context,
1275
                  info,
1276
                  env->subjectaltname_string(),
1277
1238
                  GetSubjectAltNameString(env, bio, cert)) ||
1278
2476
      !Set<Value>(context,
1279
                  info,
1280
                  env->infoaccess_string(),
1281
2476
                  GetInfoAccessString(env, bio, cert)) ||
1282

3714
      !Set<Boolean>(context, info, env->ca_string(), is_ca)) {
1283
    return MaybeLocal<Object>();
1284
  }
1285
1286
2476
  EVPKeyPointer pkey(X509_get_pubkey(cert));
1287
1238
  RSAPointer rsa;
1288
1238
  ECPointer ec;
1289
1238
  if (pkey) {
1290
1238
    switch (EVP_PKEY_id(pkey.get())) {
1291
1191
      case EVP_PKEY_RSA:
1292
1191
        rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1293
1191
        break;
1294
47
      case EVP_PKEY_EC:
1295
47
        ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1296
47
        break;
1297
    }
1298
  }
1299
1300
1238
  if (rsa) {
1301
    const BIGNUM* n;
1302
    const BIGNUM* e;
1303
1191
    RSA_get0_key(rsa.get(), &n, &e, nullptr);
1304
2382
    if (!Set<Value>(context,
1305
                    info,
1306
                    env->modulus_string(),
1307
1191
                    GetModulusString(env, bio, n)) ||
1308
3573
        !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1309
2382
        !Set<Value>(context,
1310
                    info,
1311
                    env->exponent_string(),
1312
2382
                    GetExponentString(env, bio, e)) ||
1313

3573
        !Set<Object>(context,
1314
                     info,
1315
                     env->pubkey_string(),
1316
                     GetPubKey(env, rsa))) {
1317
      return MaybeLocal<Object>();
1318
    }
1319
47
  } else if (ec) {
1320
47
    const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1321
1322
94
    if (!Set<Value>(context,
1323
                    info,
1324
                    env->bits_string(),
1325
94
                    GetECGroup(env, group, ec)) ||
1326

141
        !Set<Value>(context,
1327
                    info,
1328
                    env->pubkey_string(),
1329
                    GetECPubKey(env, group, ec))) {
1330
      return MaybeLocal<Object>();
1331
    }
1332
1333
47
    const int nid = EC_GROUP_get_curve_name(group);
1334
47
    if (nid != 0) {
1335
      // Curve is well-known, get its OID and NIST nick-name (if it has one).
1336
1337
94
      if (!Set<Value>(context,
1338
                      info,
1339
                      env->asn1curve_string(),
1340
94
                      GetCurveName<OBJ_nid2sn>(env, nid)) ||
1341

141
          !Set<Value>(context,
1342
                      info,
1343
                      env->nistcurve_string(),
1344
                      GetCurveName<EC_curve_nid2nist>(env, nid))) {
1345
        return MaybeLocal<Object>();
1346
      }
1347
    } else {
1348
      // Unnamed curves can be described by their mathematical properties,
1349
      // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1350
    }
1351
  }
1352
1353
  // pkey, rsa, and ec pointers are no longer needed.
1354
1238
  pkey.reset();
1355
1238
  rsa.reset();
1356
1238
  ec.reset();
1357
1358
2476
  if (!Set<Value>(context,
1359
                  info,
1360
                  env->valid_from_string(),
1361
2476
                  GetValidFrom(env, cert, bio)) ||
1362

3714
      !Set<Value>(context,
1363
                  info,
1364
                  env->valid_to_string(),
1365
                  GetValidTo(env, cert, bio))) {
1366
    return MaybeLocal<Object>();
1367
  }
1368
1369
  // bio is no longer needed
1370
1238
  bio.reset();
1371
1372
2476
  if (!Set<Value>(context,
1373
                  info,
1374
                  env->fingerprint_string(),
1375
1238
                  GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1376
2476
      !Set<Value>(context,
1377
                  info,
1378
                  env->fingerprint256_string(),
1379
1238
                  GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1380
2476
      !Set<Value>(context,
1381
                  info,
1382
                  env->fingerprint512_string(),
1383
1238
                  GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1384
2476
      !Set<Value>(context,
1385
                  info,
1386
                  env->ext_key_usage_string(),
1387
1238
                  GetKeyUsage(env, cert)) ||
1388
2476
      !Set<Value>(context,
1389
                  info,
1390
                  env->serial_number_string(),
1391
2476
                  GetSerialNumber(env, cert)) ||
1392

3714
      !Set<Object>(context,
1393
                   info,
1394
                   env->raw_string(),
1395
                   GetRawDERCertificate(env, cert))) {
1396
    return MaybeLocal<Object>();
1397
  }
1398
1399
1238
  return scope.Escape(info);
1400
}
1401
1402
}  // namespace crypto
1403
}  // namespace node