Coverage Report

Created: 2025-08-28 09:57

/src/node/src/crypto/crypto_common.cc
Line
Count
Source (jump to first uncovered line)
1
#include "crypto/crypto_common.h"
2
#include "base_object-inl.h"
3
#include "env-inl.h"
4
#include "memory_tracker-inl.h"
5
#include "node.h"
6
#include "node_buffer.h"
7
#include "node_crypto.h"
8
#include "node_internals.h"
9
#include "string_bytes.h"
10
#include "v8.h"
11
12
#include <openssl/ec.h>
13
#include <openssl/ecdh.h>
14
#include <openssl/evp.h>
15
#include <openssl/pem.h>
16
#include <openssl/x509v3.h>
17
#include <openssl/hmac.h>
18
#include <openssl/rand.h>
19
#include <openssl/pkcs12.h>
20
21
#include <string>
22
#include <unordered_map>
23
24
namespace node {
25
26
using v8::Array;
27
using v8::ArrayBuffer;
28
using v8::BackingStore;
29
using v8::Boolean;
30
using v8::Context;
31
using v8::EscapableHandleScope;
32
using v8::Integer;
33
using v8::Local;
34
using v8::MaybeLocal;
35
using v8::NewStringType;
36
using v8::Object;
37
using v8::String;
38
using v8::Undefined;
39
using v8::Value;
40
41
namespace crypto {
42
static constexpr int kX509NameFlagsMultiline =
43
    ASN1_STRFLGS_ESC_2253 |
44
    ASN1_STRFLGS_ESC_CTRL |
45
    ASN1_STRFLGS_UTF8_CONVERT |
46
    XN_FLAG_SEP_MULTILINE |
47
    XN_FLAG_FN_SN;
48
49
static constexpr int kX509NameFlagsRFC2253WithinUtf8JSON =
50
    XN_FLAG_RFC2253 &
51
    ~ASN1_STRFLGS_ESC_MSB &
52
    ~ASN1_STRFLGS_ESC_CTRL;
53
54
757
X509Pointer SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert) {
55
757
  X509_STORE* store = SSL_CTX_get_cert_store(ctx);
56
757
  DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx(
57
757
      X509_STORE_CTX_new());
58
757
  X509Pointer result;
59
757
  X509* issuer;
60
757
  if (store_ctx.get() != nullptr &&
61
757
      X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 &&
62
757
      X509_STORE_CTX_get1_issuer(&issuer, store_ctx.get(), cert) == 1) {
63
0
    result.reset(issuer);
64
0
  }
65
757
  return result;
66
757
}
67
68
void LogSecret(
69
    const SSLPointer& ssl,
70
    const char* name,
71
    const unsigned char* secret,
72
0
    size_t secretlen) {
73
0
  auto keylog_cb = SSL_CTX_get_keylog_callback(SSL_get_SSL_CTX(ssl.get()));
74
  // All supported versions of TLS/SSL fix the client random to the same size.
75
0
  constexpr size_t kTlsClientRandomSize = SSL3_RANDOM_SIZE;
76
0
  unsigned char crandom[kTlsClientRandomSize];
77
78
0
  if (keylog_cb == nullptr ||
79
0
      SSL_get_client_random(ssl.get(), crandom, kTlsClientRandomSize) !=
80
0
          kTlsClientRandomSize) {
81
0
    return;
82
0
  }
83
84
0
  std::string line = name;
85
0
  line += " " + StringBytes::hex_encode(reinterpret_cast<const char*>(crandom),
86
0
                                        kTlsClientRandomSize);
87
0
  line += " " + StringBytes::hex_encode(
88
0
      reinterpret_cast<const char*>(secret), secretlen);
89
0
  keylog_cb(ssl.get(), line.c_str());
90
0
}
91
92
MaybeLocal<Value> GetSSLOCSPResponse(
93
    Environment* env,
94
    SSL* ssl,
95
0
    Local<Value> default_value) {
96
0
  const unsigned char* resp;
97
0
  int len = SSL_get_tlsext_status_ocsp_resp(ssl, &resp);
98
0
  if (resp == nullptr)
99
0
    return default_value;
100
101
0
  Local<Value> ret;
102
0
  MaybeLocal<Object> maybe_buffer =
103
0
      Buffer::Copy(env, reinterpret_cast<const char*>(resp), len);
104
105
0
  if (!maybe_buffer.ToLocal(&ret))
106
0
    return MaybeLocal<Value>();
107
108
0
  return ret;
109
0
}
110
111
bool SetTLSSession(
112
    const SSLPointer& ssl,
113
0
    const SSLSessionPointer& session) {
114
0
  return session != nullptr && SSL_set_session(ssl.get(), session.get()) == 1;
115
0
}
116
117
0
SSLSessionPointer GetTLSSession(const unsigned char* buf, size_t length) {
118
0
  return SSLSessionPointer(d2i_SSL_SESSION(nullptr, &buf, length));
119
0
}
120
121
long VerifyPeerCertificate(  // NOLINT(runtime/int)
122
    const SSLPointer& ssl,
123
0
    long def) {  // NOLINT(runtime/int)
124
0
  long err = def;  // NOLINT(runtime/int)
125
0
  if (X509* peer_cert = SSL_get_peer_certificate(ssl.get())) {
126
0
    X509_free(peer_cert);
127
0
    err = SSL_get_verify_result(ssl.get());
128
0
  } else {
129
0
    const SSL_CIPHER* curr_cipher = SSL_get_current_cipher(ssl.get());
130
0
    const SSL_SESSION* sess = SSL_get_session(ssl.get());
131
    // Allow no-cert for PSK authentication in TLS1.2 and lower.
132
    // In TLS1.3 check that session was reused because TLS1.3 PSK
133
    // looks like session resumption.
134
0
    if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk ||
135
0
        (SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION &&
136
0
         SSL_session_reused(ssl.get()))) {
137
0
      return X509_V_OK;
138
0
    }
139
0
  }
140
0
  return err;
141
0
}
142
143
bool UseSNIContext(
144
0
    const SSLPointer& ssl, BaseObjectPtr<SecureContext> context) {
145
0
  SSL_CTX* ctx = context->ctx().get();
146
0
  X509* x509 = SSL_CTX_get0_certificate(ctx);
147
0
  EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx);
148
0
  STACK_OF(X509)* chain;
149
150
0
  int err = SSL_CTX_get0_chain_certs(ctx, &chain);
151
0
  if (err == 1) err = SSL_use_certificate(ssl.get(), x509);
152
0
  if (err == 1) err = SSL_use_PrivateKey(ssl.get(), pkey);
153
0
  if (err == 1 && chain != nullptr) err = SSL_set1_chain(ssl.get(), chain);
154
0
  return err == 1;
155
0
}
156
157
0
const char* GetClientHelloALPN(const SSLPointer& ssl) {
158
0
  const unsigned char* buf;
159
0
  size_t len;
160
0
  size_t rem;
161
162
0
  if (!SSL_client_hello_get0_ext(
163
0
          ssl.get(),
164
0
          TLSEXT_TYPE_application_layer_protocol_negotiation,
165
0
          &buf,
166
0
          &rem) ||
167
0
      rem < 2) {
168
0
    return nullptr;
169
0
  }
170
171
0
  len = (buf[0] << 8) | buf[1];
172
0
  if (len + 2 != rem) return nullptr;
173
0
  return reinterpret_cast<const char*>(buf + 3);
174
0
}
175
176
0
const char* GetClientHelloServerName(const SSLPointer& ssl) {
177
0
  const unsigned char* buf;
178
0
  size_t len;
179
0
  size_t rem;
180
181
0
  if (!SSL_client_hello_get0_ext(
182
0
          ssl.get(),
183
0
          TLSEXT_TYPE_server_name,
184
0
          &buf,
185
0
          &rem) || rem <= 2) {
186
0
    return nullptr;
187
0
  }
188
189
0
  len = (*buf << 8) | *(buf + 1);
190
0
  if (len + 2 != rem)
191
0
    return nullptr;
192
0
  rem = len;
193
194
0
  if (rem == 0 || *(buf + 2) != TLSEXT_NAMETYPE_host_name) return nullptr;
195
0
  rem--;
196
0
  if (rem <= 2)
197
0
    return nullptr;
198
0
  len = (*(buf + 3) << 8) | *(buf + 4);
199
0
  if (len + 2 > rem)
200
0
    return nullptr;
201
0
  return reinterpret_cast<const char*>(buf + 5);
202
0
}
203
204
0
const char* GetServerName(SSL* ssl) {
205
0
  return SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
206
0
}
207
208
0
bool SetGroups(SecureContext* sc, const char* groups) {
209
0
  return SSL_CTX_set1_groups_list(sc->ctx().get(), groups) == 1;
210
0
}
211
212
0
const char* X509ErrorCode(long err) {  // NOLINT(runtime/int)
213
0
  const char* code = "UNSPECIFIED";
214
0
#define CASE_X509_ERR(CODE) case X509_V_ERR_##CODE: code = #CODE; break;
215
0
  switch (err) {
216
    // if you modify anything in here, *please* update the respective section in
217
    // doc/api/tls.md as well
218
0
    CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT)
219
0
    CASE_X509_ERR(UNABLE_TO_GET_CRL)
220
0
    CASE_X509_ERR(UNABLE_TO_DECRYPT_CERT_SIGNATURE)
221
0
    CASE_X509_ERR(UNABLE_TO_DECRYPT_CRL_SIGNATURE)
222
0
    CASE_X509_ERR(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY)
223
0
    CASE_X509_ERR(CERT_SIGNATURE_FAILURE)
224
0
    CASE_X509_ERR(CRL_SIGNATURE_FAILURE)
225
0
    CASE_X509_ERR(CERT_NOT_YET_VALID)
226
0
    CASE_X509_ERR(CERT_HAS_EXPIRED)
227
0
    CASE_X509_ERR(CRL_NOT_YET_VALID)
228
0
    CASE_X509_ERR(CRL_HAS_EXPIRED)
229
0
    CASE_X509_ERR(ERROR_IN_CERT_NOT_BEFORE_FIELD)
230
0
    CASE_X509_ERR(ERROR_IN_CERT_NOT_AFTER_FIELD)
231
0
    CASE_X509_ERR(ERROR_IN_CRL_LAST_UPDATE_FIELD)
232
0
    CASE_X509_ERR(ERROR_IN_CRL_NEXT_UPDATE_FIELD)
233
0
    CASE_X509_ERR(OUT_OF_MEM)
234
0
    CASE_X509_ERR(DEPTH_ZERO_SELF_SIGNED_CERT)
235
0
    CASE_X509_ERR(SELF_SIGNED_CERT_IN_CHAIN)
236
0
    CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
237
0
    CASE_X509_ERR(UNABLE_TO_VERIFY_LEAF_SIGNATURE)
238
0
    CASE_X509_ERR(CERT_CHAIN_TOO_LONG)
239
0
    CASE_X509_ERR(CERT_REVOKED)
240
0
    CASE_X509_ERR(INVALID_CA)
241
0
    CASE_X509_ERR(PATH_LENGTH_EXCEEDED)
242
0
    CASE_X509_ERR(INVALID_PURPOSE)
243
0
    CASE_X509_ERR(CERT_UNTRUSTED)
244
0
    CASE_X509_ERR(CERT_REJECTED)
245
0
    CASE_X509_ERR(HOSTNAME_MISMATCH)
246
0
  }
247
0
#undef CASE_X509_ERR
248
0
  return code;
249
0
}
250
251
0
MaybeLocal<Value> GetValidationErrorReason(Environment* env, int err) {
252
0
  if (err == 0)
253
0
    return Undefined(env->isolate());
254
0
  const char* reason = X509_verify_cert_error_string(err);
255
0
  return OneByteString(env->isolate(), reason);
256
0
}
257
258
0
MaybeLocal<Value> GetValidationErrorCode(Environment* env, int err) {
259
0
  if (err == 0)
260
0
    return Undefined(env->isolate());
261
0
  return OneByteString(env->isolate(), X509ErrorCode(err));
262
0
}
263
264
0
MaybeLocal<Value> GetCert(Environment* env, const SSLPointer& ssl) {
265
0
  ClearErrorOnReturn clear_error_on_return;
266
0
  X509* cert = SSL_get_certificate(ssl.get());
267
0
  if (cert == nullptr)
268
0
    return Undefined(env->isolate());
269
270
0
  MaybeLocal<Object> maybe_cert = X509ToObject(env, cert);
271
0
  return maybe_cert.FromMaybe<Value>(Local<Value>());
272
0
}
273
274
0
Local<Value> ToV8Value(Environment* env, const BIOPointer& bio) {
275
0
  BUF_MEM* mem;
276
0
  BIO_get_mem_ptr(bio.get(), &mem);
277
0
  MaybeLocal<String> ret =
278
0
      String::NewFromUtf8(
279
0
          env->isolate(),
280
0
          mem->data,
281
0
          NewStringType::kNormal,
282
0
          mem->length);
283
0
  CHECK_EQ(BIO_reset(bio.get()), 1);
284
0
  return ret.FromMaybe(Local<Value>());
285
0
}
286
287
namespace {
288
template <typename T>
289
bool Set(
290
    Local<Context> context,
291
    Local<Object> target,
292
    Local<Value> name,
293
0
    MaybeLocal<T> maybe_value) {
294
0
  Local<Value> value;
295
0
  if (!maybe_value.ToLocal(&value))
296
0
    return false;
297
298
  // Undefined is ignored, but still considered successful
299
0
  if (value->IsUndefined())
300
0
    return true;
301
302
0
  return !target->Set(context, name, value).IsNothing();
303
0
}
Unexecuted instantiation: crypto_common.cc:bool node::crypto::(anonymous namespace)::Set<v8::Object>(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>, v8::MaybeLocal<v8::Object>)
Unexecuted instantiation: crypto_common.cc:bool node::crypto::(anonymous namespace)::Set<v8::Value>(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>, v8::MaybeLocal<v8::Value>)
Unexecuted instantiation: crypto_common.cc:bool node::crypto::(anonymous namespace)::Set<v8::String>(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>, v8::MaybeLocal<v8::String>)
Unexecuted instantiation: crypto_common.cc:bool node::crypto::(anonymous namespace)::Set<v8::Integer>(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>, v8::MaybeLocal<v8::Integer>)
Unexecuted instantiation: crypto_common.cc:bool node::crypto::(anonymous namespace)::Set<v8::Boolean>(v8::Local<v8::Context>, v8::Local<v8::Object>, v8::Local<v8::Value>, v8::MaybeLocal<v8::Boolean>)
304
305
template <const char* (*getstr)(const SSL_CIPHER* cipher)>
306
0
MaybeLocal<Value> GetCipherValue(Environment* env, const SSL_CIPHER* cipher) {
307
0
  if (cipher == nullptr)
308
0
    return Undefined(env->isolate());
309
310
0
  return OneByteString(env->isolate(), getstr(cipher));
311
0
}
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCipherValue<&SSL_CIPHER_get_name>(node::Environment*, ssl_cipher_st const*)
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCipherValue<&SSL_CIPHER_standard_name>(node::Environment*, ssl_cipher_st const*)
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCipherValue<&SSL_CIPHER_get_version>(node::Environment*, ssl_cipher_st const*)
312
313
constexpr auto GetCipherName = GetCipherValue<SSL_CIPHER_get_name>;
314
constexpr auto GetCipherStandardName = GetCipherValue<SSL_CIPHER_standard_name>;
315
constexpr auto GetCipherVersion = GetCipherValue<SSL_CIPHER_get_version>;
316
317
StackOfX509 CloneSSLCerts(X509Pointer&& cert,
318
0
                          const STACK_OF(X509)* const ssl_certs) {
319
0
  StackOfX509 peer_certs(sk_X509_new(nullptr));
320
0
  if (!peer_certs) return StackOfX509();
321
0
  if (cert && !sk_X509_push(peer_certs.get(), cert.release()))
322
0
    return StackOfX509();
323
0
  for (int i = 0; i < sk_X509_num(ssl_certs); i++) {
324
0
    X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i)));
325
0
    if (!cert || !sk_X509_push(peer_certs.get(), cert.get()))
326
0
      return StackOfX509();
327
    // `cert` is now managed by the stack.
328
0
    cert.release();
329
0
  }
330
0
  return peer_certs;
331
0
}
332
333
MaybeLocal<Object> AddIssuerChainToObject(
334
    X509Pointer* cert,
335
    Local<Object> object,
336
    StackOfX509&& peer_certs,
337
0
    Environment* const env) {
338
0
  Local<Context> context = env->isolate()->GetCurrentContext();
339
0
  cert->reset(sk_X509_delete(peer_certs.get(), 0));
340
0
  for (;;) {
341
0
    int i;
342
0
    for (i = 0; i < sk_X509_num(peer_certs.get()); i++) {
343
0
      X509* ca = sk_X509_value(peer_certs.get(), i);
344
0
      if (X509_check_issued(ca, cert->get()) != X509_V_OK)
345
0
        continue;
346
347
0
      Local<Object> ca_info;
348
0
      MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca);
349
0
      if (!maybe_ca_info.ToLocal(&ca_info))
350
0
        return MaybeLocal<Object>();
351
352
0
      if (!Set<Object>(context, object, env->issuercert_string(), ca_info))
353
0
        return MaybeLocal<Object>();
354
0
      object = ca_info;
355
356
      // NOTE: Intentionally freeing cert that is not used anymore.
357
      // Delete cert and continue aggregating issuers.
358
0
      cert->reset(sk_X509_delete(peer_certs.get(), i));
359
0
      break;
360
0
    }
361
362
    // Issuer not found, break out of the loop.
363
0
    if (i == sk_X509_num(peer_certs.get()))
364
0
      break;
365
0
  }
366
0
  return MaybeLocal<Object>(object);
367
0
}
368
369
MaybeLocal<Object> GetLastIssuedCert(
370
    X509Pointer* cert,
371
    const SSLPointer& ssl,
372
    Local<Object> issuer_chain,
373
0
    Environment* const env) {
374
0
  Local<Context> context = env->isolate()->GetCurrentContext();
375
0
  while (X509_check_issued(cert->get(), cert->get()) != X509_V_OK) {
376
0
    X509Pointer ca;
377
0
    if (!(ca = SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get())))
378
0
      break;
379
380
0
    Local<Object> ca_info;
381
0
    MaybeLocal<Object> maybe_ca_info = X509ToObject(env, ca.get());
382
0
    if (!maybe_ca_info.ToLocal(&ca_info))
383
0
      return MaybeLocal<Object>();
384
385
0
    if (!Set<Object>(context, issuer_chain, env->issuercert_string(), ca_info))
386
0
      return MaybeLocal<Object>();
387
0
    issuer_chain = ca_info;
388
389
    // For self-signed certificates whose keyUsage field does not include
390
    // keyCertSign, X509_check_issued() will return false. Avoid going into an
391
    // infinite loop by checking if SSL_CTX_get_issuer() returned the same
392
    // certificate.
393
0
    if (cert->get() == ca.get()) break;
394
395
    // Delete previous cert and continue aggregating issuers.
396
0
    *cert = std::move(ca);
397
0
  }
398
0
  return MaybeLocal<Object>(issuer_chain);
399
0
}
400
401
void AddFingerprintDigest(
402
    const unsigned char* md,
403
    unsigned int md_size,
404
0
    char fingerprint[3 * EVP_MAX_MD_SIZE]) {
405
0
  unsigned int i;
406
0
  const char hex[] = "0123456789ABCDEF";
407
408
0
  for (i = 0; i < md_size; i++) {
409
0
    fingerprint[3*i] = hex[(md[i] & 0xf0) >> 4];
410
0
    fingerprint[(3*i)+1] = hex[(md[i] & 0x0f)];
411
0
    fingerprint[(3*i)+2] = ':';
412
0
  }
413
414
0
  DCHECK_GT(md_size, 0);
415
0
  fingerprint[(3 * (md_size - 1)) + 2] = '\0';
416
0
}
417
418
template <const char* (*nid2string)(int nid)>
419
0
MaybeLocal<Value> GetCurveName(Environment* env, const int nid) {
420
0
  const char* name = nid2string(nid);
421
0
  return name != nullptr ?
422
0
      MaybeLocal<Value>(OneByteString(env->isolate(), name)) :
423
0
      MaybeLocal<Value>(Undefined(env->isolate()));
424
0
}
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCurveName<&OBJ_nid2sn>(node::Environment*, int)
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCurveName<&EC_curve_nid2nist>(node::Environment*, int)
425
426
MaybeLocal<Value> GetECPubKey(
427
    Environment* env,
428
    const EC_GROUP* group,
429
0
    const ECPointer& ec) {
430
0
  const EC_POINT* pubkey = EC_KEY_get0_public_key(ec.get());
431
0
  if (pubkey == nullptr)
432
0
    return Undefined(env->isolate());
433
434
0
  return ECPointToBuffer(
435
0
      env,
436
0
      group,
437
0
      pubkey,
438
0
      EC_KEY_get_conv_form(ec.get()),
439
0
      nullptr).FromMaybe(Local<Object>());
440
0
}
441
442
MaybeLocal<Value> GetECGroup(
443
    Environment* env,
444
    const EC_GROUP* group,
445
0
    const ECPointer& ec) {
446
0
  if (group == nullptr)
447
0
    return Undefined(env->isolate());
448
449
0
  int bits = EC_GROUP_order_bits(group);
450
0
  if (bits <= 0)
451
0
    return Undefined(env->isolate());
452
453
0
  return Integer::New(env->isolate(), bits);
454
0
}
455
456
0
MaybeLocal<Object> GetPubKey(Environment* env, const RSAPointer& rsa) {
457
0
  int size = i2d_RSA_PUBKEY(rsa.get(), nullptr);
458
0
  CHECK_GE(size, 0);
459
460
0
  std::unique_ptr<BackingStore> bs;
461
0
  {
462
0
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
463
0
    bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
464
0
  }
465
466
0
  unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
467
0
  CHECK_GE(i2d_RSA_PUBKEY(rsa.get(), &serialized), 0);
468
469
0
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
470
0
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
471
0
}
472
473
MaybeLocal<Value> GetExponentString(
474
    Environment* env,
475
    const BIOPointer& bio,
476
0
    const BIGNUM* e) {
477
0
  uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e));
478
0
  BIO_printf(bio.get(), "0x%" PRIx64, exponent_word);
479
0
  return ToV8Value(env, bio);
480
0
}
481
482
0
Local<Value> GetBits(Environment* env, const BIGNUM* n) {
483
0
  return Integer::New(env->isolate(), BN_num_bits(n));
484
0
}
485
486
MaybeLocal<Value> GetModulusString(
487
    Environment* env,
488
    const BIOPointer& bio,
489
0
    const BIGNUM* n) {
490
0
  BN_print(bio.get(), n);
491
0
  return ToV8Value(env, bio);
492
0
}
493
}  // namespace
494
495
0
MaybeLocal<Value> GetRawDERCertificate(Environment* env, X509* cert) {
496
0
  int size = i2d_X509(cert, nullptr);
497
498
0
  std::unique_ptr<BackingStore> bs;
499
0
  {
500
0
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
501
0
    bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
502
0
  }
503
504
0
  unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
505
0
  CHECK_GE(i2d_X509(cert, &serialized), 0);
506
507
0
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
508
0
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
509
0
}
510
511
0
MaybeLocal<Value> GetSerialNumber(Environment* env, X509* cert) {
512
0
  if (ASN1_INTEGER* serial_number = X509_get_serialNumber(cert)) {
513
0
    BignumPointer bn(ASN1_INTEGER_to_BN(serial_number, nullptr));
514
0
    if (bn) {
515
0
      char* data = BN_bn2hex(bn.get());
516
0
      ByteSource buf = ByteSource::Allocated(data, strlen(data));
517
0
      if (buf) return OneByteString(env->isolate(), buf.data<unsigned char>());
518
0
    }
519
0
  }
520
521
0
  return Undefined(env->isolate());
522
0
}
523
524
0
MaybeLocal<Value> GetKeyUsage(Environment* env, X509* cert) {
525
0
  StackOfASN1 eku(static_cast<STACK_OF(ASN1_OBJECT)*>(
526
0
      X509_get_ext_d2i(cert, NID_ext_key_usage, nullptr, nullptr)));
527
0
  if (eku) {
528
0
    const int count = sk_ASN1_OBJECT_num(eku.get());
529
0
    MaybeStackBuffer<Local<Value>, 16> ext_key_usage(count);
530
0
    char buf[256];
531
532
0
    int j = 0;
533
0
    for (int i = 0; i < count; i++) {
534
0
      if (OBJ_obj2txt(buf,
535
0
                      sizeof(buf),
536
0
                      sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) {
537
0
        ext_key_usage[j++] = OneByteString(env->isolate(), buf);
538
0
      }
539
0
    }
540
541
0
    return Array::New(env->isolate(), ext_key_usage.out(), count);
542
0
  }
543
544
0
  return Undefined(env->isolate());
545
0
}
546
547
MaybeLocal<Value> GetCurrentCipherName(Environment* env,
548
0
                                       const SSLPointer& ssl) {
549
0
  return GetCipherName(env, SSL_get_current_cipher(ssl.get()));
550
0
}
551
552
MaybeLocal<Value> GetCurrentCipherVersion(Environment* env,
553
0
                                          const SSLPointer& ssl) {
554
0
  return GetCipherVersion(env, SSL_get_current_cipher(ssl.get()));
555
0
}
556
557
MaybeLocal<Value> GetFingerprintDigest(
558
    Environment* env,
559
    const EVP_MD* method,
560
0
    X509* cert) {
561
0
  unsigned char md[EVP_MAX_MD_SIZE];
562
0
  unsigned int md_size;
563
0
  char fingerprint[EVP_MAX_MD_SIZE * 3];
564
565
0
  if (X509_digest(cert, method, md, &md_size)) {
566
0
    AddFingerprintDigest(md, md_size, fingerprint);
567
0
    return OneByteString(env->isolate(), fingerprint);
568
0
  }
569
0
  return Undefined(env->isolate());
570
0
}
571
572
MaybeLocal<Value> GetValidTo(
573
    Environment* env,
574
    X509* cert,
575
0
    const BIOPointer& bio) {
576
0
  ASN1_TIME_print(bio.get(), X509_get0_notAfter(cert));
577
0
  return ToV8Value(env, bio);
578
0
}
579
580
MaybeLocal<Value> GetValidFrom(
581
    Environment* env,
582
    X509* cert,
583
0
    const BIOPointer& bio) {
584
0
  ASN1_TIME_print(bio.get(), X509_get0_notBefore(cert));
585
0
  return ToV8Value(env, bio);
586
0
}
587
588
0
static inline bool IsSafeAltName(const char* name, size_t length, bool utf8) {
589
0
  for (size_t i = 0; i < length; i++) {
590
0
    char c = name[i];
591
0
    switch (c) {
592
0
    case '"':
593
0
    case '\\':
594
      // These mess with encoding rules.
595
      // Fall through.
596
0
    case ',':
597
      // Commas make it impossible to split the list of subject alternative
598
      // names unambiguously, which is why we have to escape.
599
      // Fall through.
600
0
    case '\'':
601
      // Single quotes are unlikely to appear in any legitimate values, but they
602
      // could be used to make a value look like it was escaped (i.e., enclosed
603
      // in single/double quotes).
604
0
      return false;
605
0
    default:
606
0
      if (utf8) {
607
        // In UTF8 strings, we require escaping for any ASCII control character,
608
        // but NOT for non-ASCII characters. Note that all bytes of any code
609
        // point that consists of more than a single byte have their MSB set.
610
0
        if (static_cast<unsigned char>(c) < ' ' || c == '\x7f') {
611
0
          return false;
612
0
        }
613
0
      } else {
614
        // Check if the char is a control character or non-ASCII character. Note
615
        // that char may or may not be a signed type. Regardless, non-ASCII
616
        // values will always be outside of this range.
617
0
        if (c < ' ' || c > '~') {
618
0
          return false;
619
0
        }
620
0
      }
621
0
    }
622
0
  }
623
0
  return true;
624
0
}
625
626
static inline void PrintAltName(const BIOPointer& out, const char* name,
627
                                size_t length, bool utf8,
628
0
                                const char* safe_prefix) {
629
0
  if (IsSafeAltName(name, length, utf8)) {
630
    // For backward-compatibility, append "safe" names without any
631
    // modifications.
632
0
    if (safe_prefix != nullptr) {
633
0
      BIO_printf(out.get(), "%s:", safe_prefix);
634
0
    }
635
0
    BIO_write(out.get(), name, length);
636
0
  } else {
637
    // If a name is not "safe", we cannot embed it without special
638
    // encoding. This does not usually happen, but we don't want to hide
639
    // it from the user either. We use JSON compatible escaping here.
640
0
    BIO_write(out.get(), "\"", 1);
641
0
    if (safe_prefix != nullptr) {
642
0
      BIO_printf(out.get(), "%s:", safe_prefix);
643
0
    }
644
0
    for (size_t j = 0; j < length; j++) {
645
0
      char c = static_cast<char>(name[j]);
646
0
      if (c == '\\') {
647
0
        BIO_write(out.get(), "\\\\", 2);
648
0
      } else if (c == '"') {
649
0
        BIO_write(out.get(), "\\\"", 2);
650
0
      } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) {
651
        // Note that the above condition explicitly excludes commas, which means
652
        // that those are encoded as Unicode escape sequences in the "else"
653
        // block. That is not strictly necessary, and Node.js itself would parse
654
        // it correctly either way. We only do this to account for third-party
655
        // code that might be splitting the string at commas (as Node.js itself
656
        // used to do).
657
0
        BIO_write(out.get(), &c, 1);
658
0
      } else {
659
        // Control character or non-ASCII character. We treat everything as
660
        // Latin-1, which corresponds to the first 255 Unicode code points.
661
0
        const char hex[] = "0123456789abcdef";
662
0
        char u[] = { '\\', 'u', '0', '0', hex[(c & 0xf0) >> 4], hex[c & 0x0f] };
663
0
        BIO_write(out.get(), u, sizeof(u));
664
0
      }
665
0
    }
666
0
    BIO_write(out.get(), "\"", 1);
667
0
  }
668
0
}
669
670
static inline void PrintLatin1AltName(const BIOPointer& out,
671
                                      const ASN1_IA5STRING* name,
672
0
                                      const char* safe_prefix = nullptr) {
673
0
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
674
0
               false, safe_prefix);
675
0
}
676
677
static inline void PrintUtf8AltName(const BIOPointer& out,
678
                                    const ASN1_UTF8STRING* name,
679
0
                                    const char* safe_prefix = nullptr) {
680
0
  PrintAltName(out, reinterpret_cast<const char*>(name->data), name->length,
681
0
               true, safe_prefix);
682
0
}
683
684
// This function emulates the behavior of i2v_GENERAL_NAME in a safer and less
685
// ambiguous way. "othername:" entries use the GENERAL_NAME_print format.
686
0
static bool PrintGeneralName(const BIOPointer& out, const GENERAL_NAME* gen) {
687
0
  if (gen->type == GEN_DNS) {
688
0
    ASN1_IA5STRING* name = gen->d.dNSName;
689
0
    BIO_write(out.get(), "DNS:", 4);
690
    // Note that the preferred name syntax (see RFCs 5280 and 1034) with
691
    // wildcards is a subset of what we consider "safe", so spec-compliant DNS
692
    // names will never need to be escaped.
693
0
    PrintLatin1AltName(out, name);
694
0
  } else if (gen->type == GEN_EMAIL) {
695
0
    ASN1_IA5STRING* name = gen->d.rfc822Name;
696
0
    BIO_write(out.get(), "email:", 6);
697
0
    PrintLatin1AltName(out, name);
698
0
  } else if (gen->type == GEN_URI) {
699
0
    ASN1_IA5STRING* name = gen->d.uniformResourceIdentifier;
700
0
    BIO_write(out.get(), "URI:", 4);
701
    // The set of "safe" names was designed to include just about any URI,
702
    // with a few exceptions, most notably URIs that contains commas (see
703
    // RFC 2396). In other words, most legitimate URIs will not require
704
    // escaping.
705
0
    PrintLatin1AltName(out, name);
706
0
  } else if (gen->type == GEN_DIRNAME) {
707
    // Earlier versions of Node.js used X509_NAME_oneline to print the X509_NAME
708
    // object. The format was non standard and should be avoided. The use of
709
    // X509_NAME_oneline is discouraged by OpenSSL but was required for backward
710
    // compatibility. Conveniently, X509_NAME_oneline produced ASCII and the
711
    // output was unlikely to contains commas or other characters that would
712
    // require escaping. However, it SHOULD NOT produce ASCII output since an
713
    // RFC5280 AttributeValue may be a UTF8String.
714
    // Newer versions of Node.js have since switched to X509_NAME_print_ex to
715
    // produce a better format at the cost of backward compatibility. The new
716
    // format may contain Unicode characters and it is likely to contain commas,
717
    // which require escaping. Fortunately, the recently safeguarded function
718
    // PrintAltName handles all of that safely.
719
0
    BIO_printf(out.get(), "DirName:");
720
0
    BIOPointer tmp(BIO_new(BIO_s_mem()));
721
0
    CHECK(tmp);
722
0
    if (X509_NAME_print_ex(tmp.get(),
723
0
                           gen->d.dirn,
724
0
                           0,
725
0
                           kX509NameFlagsRFC2253WithinUtf8JSON) < 0) {
726
0
      return false;
727
0
    }
728
0
    char* oline = nullptr;
729
0
    long n_bytes = BIO_get_mem_data(tmp.get(), &oline);  // NOLINT(runtime/int)
730
0
    CHECK_GE(n_bytes, 0);
731
0
    CHECK_IMPLIES(n_bytes != 0, oline != nullptr);
732
0
    PrintAltName(out, oline, static_cast<size_t>(n_bytes), true, nullptr);
733
0
  } else if (gen->type == GEN_IPADD) {
734
0
    BIO_printf(out.get(), "IP Address:");
735
0
    const ASN1_OCTET_STRING* ip = gen->d.ip;
736
0
    const unsigned char* b = ip->data;
737
0
    if (ip->length == 4) {
738
0
      BIO_printf(out.get(), "%d.%d.%d.%d", b[0], b[1], b[2], b[3]);
739
0
    } else if (ip->length == 16) {
740
0
      for (unsigned int j = 0; j < 8; j++) {
741
0
        uint16_t pair = (b[2 * j] << 8) | b[2 * j + 1];
742
0
        BIO_printf(out.get(), (j == 0) ? "%X" : ":%X", pair);
743
0
      }
744
0
    } else {
745
0
#if OPENSSL_VERSION_MAJOR >= 3
746
0
      BIO_printf(out.get(), "<invalid length=%d>", ip->length);
747
#else
748
      BIO_printf(out.get(), "<invalid>");
749
#endif
750
0
    }
751
0
  } else if (gen->type == GEN_RID) {
752
    // Unlike OpenSSL's default implementation, never print the OID as text and
753
    // instead always print its numeric representation.
754
0
    char oline[256];
755
0
    OBJ_obj2txt(oline, sizeof(oline), gen->d.rid, true);
756
0
    BIO_printf(out.get(), "Registered ID:%s", oline);
757
0
  } else if (gen->type == GEN_OTHERNAME) {
758
    // The format that is used here is based on OpenSSL's implementation of
759
    // GENERAL_NAME_print (as of OpenSSL 3.0.1). Earlier versions of Node.js
760
    // instead produced the same format as i2v_GENERAL_NAME, which was somewhat
761
    // awkward, especially when passed to translatePeerCertificate.
762
0
    bool unicode = true;
763
0
    const char* prefix = nullptr;
764
    // OpenSSL 1.1.1 does not support othername in GENERAL_NAME_print and may
765
    // not define these NIDs.
766
0
#if OPENSSL_VERSION_MAJOR >= 3
767
0
    int nid = OBJ_obj2nid(gen->d.otherName->type_id);
768
0
    switch (nid) {
769
0
      case NID_id_on_SmtpUTF8Mailbox:
770
0
        prefix = "SmtpUTF8Mailbox";
771
0
        break;
772
0
      case NID_XmppAddr:
773
0
        prefix = "XmppAddr";
774
0
        break;
775
0
      case NID_SRVName:
776
0
        prefix = "SRVName";
777
0
        unicode = false;
778
0
        break;
779
0
      case NID_ms_upn:
780
0
        prefix = "UPN";
781
0
        break;
782
0
      case NID_NAIRealm:
783
0
        prefix = "NAIRealm";
784
0
        break;
785
0
    }
786
0
#endif  // OPENSSL_VERSION_MAJOR >= 3
787
0
    int val_type = gen->d.otherName->value->type;
788
0
    if (prefix == nullptr ||
789
0
        (unicode && val_type != V_ASN1_UTF8STRING) ||
790
0
        (!unicode && val_type != V_ASN1_IA5STRING)) {
791
0
      BIO_printf(out.get(), "othername:<unsupported>");
792
0
    } else {
793
0
      BIO_printf(out.get(), "othername:");
794
0
      if (unicode) {
795
0
        PrintUtf8AltName(out, gen->d.otherName->value->value.utf8string,
796
0
                         prefix);
797
0
      } else {
798
0
        PrintLatin1AltName(out, gen->d.otherName->value->value.ia5string,
799
0
                           prefix);
800
0
      }
801
0
    }
802
0
  } else if (gen->type == GEN_X400) {
803
    // TODO(tniessen): this is what OpenSSL does, implement properly instead
804
0
    BIO_printf(out.get(), "X400Name:<unsupported>");
805
0
  } else if (gen->type == GEN_EDIPARTY) {
806
    // TODO(tniessen): this is what OpenSSL does, implement properly instead
807
0
    BIO_printf(out.get(), "EdiPartyName:<unsupported>");
808
0
  } else {
809
    // This is safe because X509V3_EXT_d2i would have returned nullptr in this
810
    // case already.
811
0
    UNREACHABLE();
812
0
  }
813
814
0
  return true;
815
0
}
816
817
0
bool SafeX509SubjectAltNamePrint(const BIOPointer& out, X509_EXTENSION* ext) {
818
0
  const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
819
0
  CHECK(method == X509V3_EXT_get_nid(NID_subject_alt_name));
820
821
0
  GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(ext));
822
0
  if (names == nullptr)
823
0
    return false;
824
825
0
  bool ok = true;
826
827
0
  for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) {
828
0
    GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i);
829
830
0
    if (i != 0)
831
0
      BIO_write(out.get(), ", ", 2);
832
833
0
    if (!(ok = PrintGeneralName(out, gen))) {
834
0
      break;
835
0
    }
836
0
  }
837
0
  sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
838
839
0
  return ok;
840
0
}
841
842
0
bool SafeX509InfoAccessPrint(const BIOPointer& out, X509_EXTENSION* ext) {
843
0
  const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext);
844
0
  CHECK(method == X509V3_EXT_get_nid(NID_info_access));
845
846
0
  AUTHORITY_INFO_ACCESS* descs =
847
0
      static_cast<AUTHORITY_INFO_ACCESS*>(X509V3_EXT_d2i(ext));
848
0
  if (descs == nullptr)
849
0
    return false;
850
851
0
  bool ok = true;
852
853
0
  for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(descs); i++) {
854
0
    ACCESS_DESCRIPTION* desc = sk_ACCESS_DESCRIPTION_value(descs, i);
855
856
0
    if (i != 0)
857
0
      BIO_write(out.get(), "\n", 1);
858
859
0
    char objtmp[80];
860
0
    i2t_ASN1_OBJECT(objtmp, sizeof(objtmp), desc->method);
861
0
    BIO_printf(out.get(), "%s - ", objtmp);
862
0
    if (!(ok = PrintGeneralName(out, desc->location))) {
863
0
      break;
864
0
    }
865
0
  }
866
0
  sk_ACCESS_DESCRIPTION_pop_free(descs, ACCESS_DESCRIPTION_free);
867
868
#if OPENSSL_VERSION_MAJOR < 3
869
  BIO_write(out.get(), "\n", 1);
870
#endif
871
872
0
  return ok;
873
0
}
874
875
v8::MaybeLocal<v8::Value> GetSubjectAltNameString(Environment* env,
876
                                                  X509* cert,
877
0
                                                  const BIOPointer& bio) {
878
0
  int index = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
879
0
  if (index < 0)
880
0
    return Undefined(env->isolate());
881
882
0
  X509_EXTENSION* ext = X509_get_ext(cert, index);
883
0
  CHECK_NOT_NULL(ext);
884
885
0
  if (!SafeX509SubjectAltNamePrint(bio, ext)) {
886
0
    CHECK_EQ(BIO_reset(bio.get()), 1);
887
0
    return v8::Null(env->isolate());
888
0
  }
889
890
0
  return ToV8Value(env, bio);
891
0
}
892
893
v8::MaybeLocal<v8::Value> GetInfoAccessString(Environment* env,
894
                                              X509* cert,
895
0
                                              const BIOPointer& bio) {
896
0
  int index = X509_get_ext_by_NID(cert, NID_info_access, -1);
897
0
  if (index < 0)
898
0
    return Undefined(env->isolate());
899
900
0
  X509_EXTENSION* ext = X509_get_ext(cert, index);
901
0
  CHECK_NOT_NULL(ext);
902
903
0
  if (!SafeX509InfoAccessPrint(bio, ext)) {
904
0
    CHECK_EQ(BIO_reset(bio.get()), 1);
905
0
    return v8::Null(env->isolate());
906
0
  }
907
908
0
  return ToV8Value(env, bio);
909
0
}
910
911
MaybeLocal<Value> GetIssuerString(Environment* env,
912
                                  X509* cert,
913
0
                                  const BIOPointer& bio) {
914
0
  X509_NAME* issuer_name = X509_get_issuer_name(cert);
915
0
  if (X509_NAME_print_ex(
916
0
          bio.get(),
917
0
          issuer_name,
918
0
          0,
919
0
          kX509NameFlagsMultiline) <= 0) {
920
0
    CHECK_EQ(BIO_reset(bio.get()), 1);
921
0
    return Undefined(env->isolate());
922
0
  }
923
924
0
  return ToV8Value(env, bio);
925
0
}
926
927
MaybeLocal<Value> GetSubject(Environment* env,
928
                             X509* cert,
929
0
                             const BIOPointer& bio) {
930
0
  if (X509_NAME_print_ex(
931
0
          bio.get(),
932
0
          X509_get_subject_name(cert),
933
0
          0,
934
0
          kX509NameFlagsMultiline) <= 0) {
935
0
    CHECK_EQ(BIO_reset(bio.get()), 1);
936
0
    return Undefined(env->isolate());
937
0
  }
938
939
0
  return ToV8Value(env, bio);
940
0
}
941
942
template <X509_NAME* get_name(const X509*)>
943
0
static MaybeLocal<Value> GetX509NameObject(Environment* env, X509* cert) {
944
0
  X509_NAME* name = get_name(cert);
945
0
  CHECK_NOT_NULL(name);
946
947
0
  int cnt = X509_NAME_entry_count(name);
948
0
  CHECK_GE(cnt, 0);
949
950
0
  Local<Object> result =
951
0
      Object::New(env->isolate(), Null(env->isolate()), nullptr, nullptr, 0);
952
0
  if (result.IsEmpty()) {
953
0
    return MaybeLocal<Value>();
954
0
  }
955
956
0
  for (int i = 0; i < cnt; i++) {
957
0
    X509_NAME_ENTRY* entry = X509_NAME_get_entry(name, i);
958
0
    CHECK_NOT_NULL(entry);
959
960
    // We intentionally ignore the value of X509_NAME_ENTRY_set because the
961
    // representation as an object does not allow grouping entries into sets
962
    // anyway, and multi-value RDNs are rare, i.e., the vast majority of
963
    // Relative Distinguished Names contains a single type-value pair only.
964
0
    const ASN1_OBJECT* type = X509_NAME_ENTRY_get_object(entry);
965
0
    const ASN1_STRING* value = X509_NAME_ENTRY_get_data(entry);
966
967
    // If OpenSSL knows the type, use the short name of the type as the key, and
968
    // the numeric representation of the type's OID otherwise.
969
0
    int type_nid = OBJ_obj2nid(type);
970
0
    char type_buf[80];
971
0
    const char* type_str;
972
0
    if (type_nid != NID_undef) {
973
0
      type_str = OBJ_nid2sn(type_nid);
974
0
      CHECK_NOT_NULL(type_str);
975
0
    } else {
976
0
      OBJ_obj2txt(type_buf, sizeof(type_buf), type, true);
977
0
      type_str = type_buf;
978
0
    }
979
980
0
    Local<String> v8_name;
981
0
    if (!String::NewFromUtf8(env->isolate(), type_str).ToLocal(&v8_name)) {
982
0
      return MaybeLocal<Value>();
983
0
    }
984
985
    // The previous implementation used X509_NAME_print_ex, which escapes some
986
    // characters in the value. The old implementation did not decode/unescape
987
    // values correctly though, leading to ambiguous and incorrect
988
    // representations. The new implementation only converts to Unicode and does
989
    // not escape anything.
990
0
    unsigned char* value_str;
991
0
    int value_str_size = ASN1_STRING_to_UTF8(&value_str, value);
992
0
    if (value_str_size < 0) {
993
0
      return Undefined(env->isolate());
994
0
    }
995
0
    auto free_value_str = OnScopeLeave([&]() { OPENSSL_free(value_str); });
Unexecuted instantiation: crypto_common.cc:node::crypto::GetX509NameObject<&X509_get_subject_name>(node::Environment*, x509_st*)::{lambda()#1}::operator()() const
Unexecuted instantiation: crypto_common.cc:node::crypto::GetX509NameObject<&X509_get_issuer_name>(node::Environment*, x509_st*)::{lambda()#1}::operator()() const
996
997
0
    Local<String> v8_value;
998
0
    if (!String::NewFromUtf8(env->isolate(),
999
0
                             reinterpret_cast<const char*>(value_str),
1000
0
                             NewStringType::kNormal,
1001
0
                             value_str_size)
1002
0
             .ToLocal(&v8_value)) {
1003
0
      return MaybeLocal<Value>();
1004
0
    }
1005
1006
    // For backward compatibility, we only create arrays if multiple values
1007
    // exist for the same key. That is not great but there is not much we can
1008
    // change here without breaking things. Note that this creates nested data
1009
    // structures, yet still does not allow representing Distinguished Names
1010
    // accurately.
1011
0
    bool multiple;
1012
0
    if (!result->HasOwnProperty(env->context(), v8_name).To(&multiple)) {
1013
0
      return MaybeLocal<Value>();
1014
0
    } else if (multiple) {
1015
0
      Local<Value> accum;
1016
0
      if (!result->Get(env->context(), v8_name).ToLocal(&accum)) {
1017
0
        return MaybeLocal<Value>();
1018
0
      }
1019
0
      if (!accum->IsArray()) {
1020
0
        accum = Array::New(env->isolate(), &accum, 1);
1021
0
        if (result->Set(env->context(), v8_name, accum).IsNothing()) {
1022
0
          return MaybeLocal<Value>();
1023
0
        }
1024
0
      }
1025
0
      Local<Array> array = accum.As<Array>();
1026
0
      if (array->Set(env->context(), array->Length(), v8_value).IsNothing()) {
1027
0
        return MaybeLocal<Value>();
1028
0
      }
1029
0
    } else if (result->Set(env->context(), v8_name, v8_value).IsNothing()) {
1030
0
      return MaybeLocal<Value>();
1031
0
    }
1032
0
  }
1033
1034
0
  return result;
1035
0
}
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::GetX509NameObject<&X509_get_subject_name>(node::Environment*, x509_st*)
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::GetX509NameObject<&X509_get_issuer_name>(node::Environment*, x509_st*)
1036
1037
template <MaybeLocal<Value> (*Get)(Environment* env, const SSL_CIPHER* cipher)>
1038
MaybeLocal<Value> GetCurrentCipherValue(Environment* env,
1039
0
                                        const SSLPointer& ssl) {
1040
0
  return Get(env, SSL_get_current_cipher(ssl.get()));
1041
0
}
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::GetCurrentCipherValue<&(v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCipherValue<&SSL_CIPHER_get_name>(node::Environment*, ssl_cipher_st const*))>(node::Environment*, std::__1::unique_ptr<ssl_st, node::FunctionDeleter<ssl_st, &SSL_free> > const&)
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::GetCurrentCipherValue<&(v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCipherValue<&SSL_CIPHER_standard_name>(node::Environment*, ssl_cipher_st const*))>(node::Environment*, std::__1::unique_ptr<ssl_st, node::FunctionDeleter<ssl_st, &SSL_free> > const&)
Unexecuted instantiation: crypto_common.cc:v8::MaybeLocal<v8::Value> node::crypto::GetCurrentCipherValue<&(v8::MaybeLocal<v8::Value> node::crypto::(anonymous namespace)::GetCipherValue<&SSL_CIPHER_get_version>(node::Environment*, ssl_cipher_st const*))>(node::Environment*, std::__1::unique_ptr<ssl_st, node::FunctionDeleter<ssl_st, &SSL_free> > const&)
1042
1043
MaybeLocal<Array> GetClientHelloCiphers(
1044
    Environment* env,
1045
0
    const SSLPointer& ssl) {
1046
0
  EscapableHandleScope scope(env->isolate());
1047
0
  const unsigned char* buf;
1048
0
  size_t len = SSL_client_hello_get0_ciphers(ssl.get(), &buf);
1049
0
  size_t count = len / 2;
1050
0
  MaybeStackBuffer<Local<Value>, 16> ciphers(count);
1051
0
  int j = 0;
1052
0
  for (size_t n = 0; n < len; n += 2) {
1053
0
    const SSL_CIPHER* cipher = SSL_CIPHER_find(ssl.get(), buf);
1054
0
    buf += 2;
1055
0
    Local<Object> obj = Object::New(env->isolate());
1056
0
    if (!Set(env->context(),
1057
0
             obj,
1058
0
             env->name_string(),
1059
0
             GetCipherName(env, cipher)) ||
1060
0
        !Set(env->context(),
1061
0
             obj,
1062
0
             env->standard_name_string(),
1063
0
             GetCipherStandardName(env, cipher)) ||
1064
0
        !Set(env->context(),
1065
0
             obj,
1066
0
             env->version_string(),
1067
0
             GetCipherVersion(env, cipher))) {
1068
0
      return MaybeLocal<Array>();
1069
0
    }
1070
0
    ciphers[j++] = obj;
1071
0
  }
1072
0
  Local<Array> ret = Array::New(env->isolate(), ciphers.out(), count);
1073
0
  return scope.Escape(ret);
1074
0
}
1075
1076
1077
0
MaybeLocal<Object> GetCipherInfo(Environment* env, const SSLPointer& ssl) {
1078
0
  if (SSL_get_current_cipher(ssl.get()) == nullptr)
1079
0
    return MaybeLocal<Object>();
1080
0
  EscapableHandleScope scope(env->isolate());
1081
0
  Local<Object> info = Object::New(env->isolate());
1082
1083
0
  if (!Set<Value>(env->context(),
1084
0
                  info,
1085
0
                  env->name_string(),
1086
0
                  GetCurrentCipherValue<GetCipherName>(env, ssl)) ||
1087
0
      !Set<Value>(env->context(),
1088
0
                  info,
1089
0
                  env->standard_name_string(),
1090
0
                  GetCurrentCipherValue<GetCipherStandardName>(env, ssl)) ||
1091
0
      !Set<Value>(env->context(),
1092
0
                  info,
1093
0
                  env->version_string(),
1094
0
                  GetCurrentCipherValue<GetCipherVersion>(env, ssl))) {
1095
0
    return MaybeLocal<Object>();
1096
0
  }
1097
1098
0
  return scope.Escape(info);
1099
0
}
1100
1101
0
MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
1102
0
  CHECK_EQ(SSL_is_server(ssl.get()), 0);
1103
0
  EVP_PKEY* raw_key;
1104
1105
0
  EscapableHandleScope scope(env->isolate());
1106
0
  Local<Object> info = Object::New(env->isolate());
1107
0
  if (!SSL_get_server_tmp_key(ssl.get(), &raw_key))
1108
0
    return scope.Escape(info);
1109
1110
0
  Local<Context> context = env->context();
1111
0
  crypto::EVPKeyPointer key(raw_key);
1112
1113
0
  int kid = EVP_PKEY_id(key.get());
1114
0
  int bits = EVP_PKEY_bits(key.get());
1115
0
  switch (kid) {
1116
0
    case EVP_PKEY_DH:
1117
0
      if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
1118
0
          !Set<Integer>(context,
1119
0
               info,
1120
0
               env->size_string(),
1121
0
               Integer::New(env->isolate(), bits))) {
1122
0
        return MaybeLocal<Object>();
1123
0
      }
1124
0
      break;
1125
0
    case EVP_PKEY_EC:
1126
0
    case EVP_PKEY_X25519:
1127
0
    case EVP_PKEY_X448:
1128
0
      {
1129
0
        const char* curve_name;
1130
0
        if (kid == EVP_PKEY_EC) {
1131
0
          ECKeyPointer ec(EVP_PKEY_get1_EC_KEY(key.get()));
1132
0
          int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
1133
0
          curve_name = OBJ_nid2sn(nid);
1134
0
        } else {
1135
0
          curve_name = OBJ_nid2sn(kid);
1136
0
        }
1137
0
        if (!Set<String>(context,
1138
0
                         info,
1139
0
                         env->type_string(),
1140
0
                         env->ecdh_string()) ||
1141
0
            !Set<String>(context,
1142
0
                info,
1143
0
                env->name_string(),
1144
0
                OneByteString(env->isolate(), curve_name)) ||
1145
0
            !Set<Integer>(context,
1146
0
                 info,
1147
0
                 env->size_string(),
1148
0
                 Integer::New(env->isolate(), bits))) {
1149
0
          return MaybeLocal<Object>();
1150
0
        }
1151
0
      }
1152
0
      break;
1153
0
  }
1154
1155
0
  return scope.Escape(info);
1156
0
}
1157
1158
MaybeLocal<Object> ECPointToBuffer(Environment* env,
1159
                                   const EC_GROUP* group,
1160
                                   const EC_POINT* point,
1161
                                   point_conversion_form_t form,
1162
9
                                   const char** error) {
1163
9
  size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
1164
9
  if (len == 0) {
1165
0
    if (error != nullptr) *error = "Failed to get public key length";
1166
0
    return MaybeLocal<Object>();
1167
0
  }
1168
1169
9
  std::unique_ptr<BackingStore> bs;
1170
9
  {
1171
9
    NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
1172
9
    bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
1173
9
  }
1174
1175
9
  len = EC_POINT_point2oct(group,
1176
9
                           point,
1177
9
                           form,
1178
9
                           reinterpret_cast<unsigned char*>(bs->Data()),
1179
9
                           bs->ByteLength(),
1180
9
                           nullptr);
1181
9
  if (len == 0) {
1182
0
    if (error != nullptr) *error = "Failed to get public key";
1183
0
    return MaybeLocal<Object>();
1184
0
  }
1185
1186
9
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), std::move(bs));
1187
9
  return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Object>());
1188
9
}
1189
1190
MaybeLocal<Value> GetPeerCert(
1191
    Environment* env,
1192
    const SSLPointer& ssl,
1193
    bool abbreviated,
1194
0
    bool is_server) {
1195
0
  ClearErrorOnReturn clear_error_on_return;
1196
0
  Local<Object> result;
1197
0
  MaybeLocal<Object> maybe_cert;
1198
1199
  // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain`
1200
  // contains the `peer_certificate`, but on server it doesn't.
1201
0
  X509Pointer cert(is_server ? SSL_get_peer_certificate(ssl.get()) : nullptr);
1202
0
  STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(ssl.get());
1203
0
  if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0))
1204
0
    return Undefined(env->isolate());
1205
1206
  // Short result requested.
1207
0
  if (abbreviated) {
1208
0
    maybe_cert =
1209
0
        X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0));
1210
0
    return maybe_cert.ToLocal(&result) ? result : MaybeLocal<Value>();
1211
0
  }
1212
1213
0
  StackOfX509 peer_certs = CloneSSLCerts(std::move(cert), ssl_certs);
1214
0
  if (peer_certs == nullptr)
1215
0
    return Undefined(env->isolate());
1216
1217
  // First and main certificate.
1218
0
  X509Pointer first_cert(sk_X509_value(peer_certs.get(), 0));
1219
0
  CHECK(first_cert);
1220
0
  maybe_cert = X509ToObject(env, first_cert.release());
1221
0
  if (!maybe_cert.ToLocal(&result))
1222
0
    return MaybeLocal<Value>();
1223
1224
0
  Local<Object> issuer_chain;
1225
0
  MaybeLocal<Object> maybe_issuer_chain;
1226
1227
0
  maybe_issuer_chain =
1228
0
      AddIssuerChainToObject(
1229
0
          &cert,
1230
0
          result,
1231
0
          std::move(peer_certs),
1232
0
          env);
1233
0
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1234
0
    return MaybeLocal<Value>();
1235
1236
0
  maybe_issuer_chain =
1237
0
      GetLastIssuedCert(
1238
0
          &cert,
1239
0
          ssl,
1240
0
          issuer_chain,
1241
0
          env);
1242
1243
0
  issuer_chain.Clear();
1244
0
  if (!maybe_issuer_chain.ToLocal(&issuer_chain))
1245
0
    return MaybeLocal<Value>();
1246
1247
  // Last certificate should be self-signed.
1248
0
  if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK &&
1249
0
      !Set<Object>(env->context(),
1250
0
           issuer_chain,
1251
0
           env->issuercert_string(),
1252
0
           issuer_chain)) {
1253
0
    return MaybeLocal<Value>();
1254
0
  }
1255
1256
0
  return result;
1257
0
}
1258
1259
MaybeLocal<Object> X509ToObject(
1260
    Environment* env,
1261
0
    X509* cert) {
1262
0
  EscapableHandleScope scope(env->isolate());
1263
0
  Local<Context> context = env->context();
1264
0
  Local<Object> info = Object::New(env->isolate());
1265
1266
0
  BIOPointer bio(BIO_new(BIO_s_mem()));
1267
0
  CHECK(bio);
1268
1269
  // X509_check_ca() returns a range of values. Only 1 means "is a CA"
1270
0
  auto is_ca = Boolean::New(env->isolate(), 1 == X509_check_ca(cert));
1271
0
  if (!Set<Value>(context,
1272
0
                  info,
1273
0
                  env->subject_string(),
1274
0
                  GetX509NameObject<X509_get_subject_name>(env, cert)) ||
1275
0
      !Set<Value>(context,
1276
0
                  info,
1277
0
                  env->issuer_string(),
1278
0
                  GetX509NameObject<X509_get_issuer_name>(env, cert)) ||
1279
0
      !Set<Value>(context,
1280
0
                  info,
1281
0
                  env->subjectaltname_string(),
1282
0
                  GetSubjectAltNameString(env, cert, bio)) ||
1283
0
      !Set<Value>(context,
1284
0
                  info,
1285
0
                  env->infoaccess_string(),
1286
0
                  GetInfoAccessString(env, cert, bio)) ||
1287
0
      !Set<Boolean>(context, info, env->ca_string(), is_ca)) {
1288
0
    return MaybeLocal<Object>();
1289
0
  }
1290
1291
0
  EVPKeyPointer pkey(X509_get_pubkey(cert));
1292
0
  RSAPointer rsa;
1293
0
  ECPointer ec;
1294
0
  if (pkey) {
1295
0
    switch (EVP_PKEY_id(pkey.get())) {
1296
0
      case EVP_PKEY_RSA:
1297
0
        rsa.reset(EVP_PKEY_get1_RSA(pkey.get()));
1298
0
        break;
1299
0
      case EVP_PKEY_EC:
1300
0
        ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get()));
1301
0
        break;
1302
0
    }
1303
0
  }
1304
1305
0
  if (rsa) {
1306
0
    const BIGNUM* n;
1307
0
    const BIGNUM* e;
1308
0
    RSA_get0_key(rsa.get(), &n, &e, nullptr);
1309
0
    if (!Set<Value>(context,
1310
0
                    info,
1311
0
                    env->modulus_string(),
1312
0
                    GetModulusString(env, bio, n)) ||
1313
0
        !Set<Value>(context, info, env->bits_string(), GetBits(env, n)) ||
1314
0
        !Set<Value>(context,
1315
0
                    info,
1316
0
                    env->exponent_string(),
1317
0
                    GetExponentString(env, bio, e)) ||
1318
0
        !Set<Object>(context,
1319
0
                     info,
1320
0
                     env->pubkey_string(),
1321
0
                     GetPubKey(env, rsa))) {
1322
0
      return MaybeLocal<Object>();
1323
0
    }
1324
0
  } else if (ec) {
1325
0
    const EC_GROUP* group = EC_KEY_get0_group(ec.get());
1326
1327
0
    if (!Set<Value>(context,
1328
0
                    info,
1329
0
                    env->bits_string(),
1330
0
                    GetECGroup(env, group, ec)) ||
1331
0
        !Set<Value>(context,
1332
0
                    info,
1333
0
                    env->pubkey_string(),
1334
0
                    GetECPubKey(env, group, ec))) {
1335
0
      return MaybeLocal<Object>();
1336
0
    }
1337
1338
0
    const int nid = EC_GROUP_get_curve_name(group);
1339
0
    if (nid != 0) {
1340
      // Curve is well-known, get its OID and NIST nick-name (if it has one).
1341
1342
0
      if (!Set<Value>(context,
1343
0
                      info,
1344
0
                      env->asn1curve_string(),
1345
0
                      GetCurveName<OBJ_nid2sn>(env, nid)) ||
1346
0
          !Set<Value>(context,
1347
0
                      info,
1348
0
                      env->nistcurve_string(),
1349
0
                      GetCurveName<EC_curve_nid2nist>(env, nid))) {
1350
0
        return MaybeLocal<Object>();
1351
0
      }
1352
0
    } else {
1353
      // Unnamed curves can be described by their mathematical properties,
1354
      // but aren't used much (at all?) with X.509/TLS. Support later if needed.
1355
0
    }
1356
0
  }
1357
1358
  // pkey, rsa, and ec pointers are no longer needed.
1359
0
  pkey.reset();
1360
0
  rsa.reset();
1361
0
  ec.reset();
1362
1363
0
  if (!Set<Value>(context,
1364
0
                  info,
1365
0
                  env->valid_from_string(),
1366
0
                  GetValidFrom(env, cert, bio)) ||
1367
0
      !Set<Value>(context,
1368
0
                  info,
1369
0
                  env->valid_to_string(),
1370
0
                  GetValidTo(env, cert, bio))) {
1371
0
    return MaybeLocal<Object>();
1372
0
  }
1373
1374
  // bio is no longer needed
1375
0
  bio.reset();
1376
1377
0
  if (!Set<Value>(context,
1378
0
                  info,
1379
0
                  env->fingerprint_string(),
1380
0
                  GetFingerprintDigest(env, EVP_sha1(), cert)) ||
1381
0
      !Set<Value>(context,
1382
0
                  info,
1383
0
                  env->fingerprint256_string(),
1384
0
                  GetFingerprintDigest(env, EVP_sha256(), cert)) ||
1385
0
      !Set<Value>(context,
1386
0
                  info,
1387
0
                  env->fingerprint512_string(),
1388
0
                  GetFingerprintDigest(env, EVP_sha512(), cert)) ||
1389
0
      !Set<Value>(
1390
0
          context, info, env->ext_key_usage_string(), GetKeyUsage(env, cert)) ||
1391
0
      !Set<Value>(context,
1392
0
                  info,
1393
0
                  env->serial_number_string(),
1394
0
                  GetSerialNumber(env, cert)) ||
1395
0
      !Set<Value>(
1396
0
          context, info, env->raw_string(), GetRawDERCertificate(env, cert))) {
1397
0
    return MaybeLocal<Object>();
1398
0
  }
1399
1400
0
  return scope.Escape(info);
1401
0
}
1402
1403
}  // namespace crypto
1404
}  // namespace node