11cb0ef41Sopenharmony_ci#if HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci#include "tlscontext.h"
41cb0ef41Sopenharmony_ci#include "bindingdata.h"
51cb0ef41Sopenharmony_ci#include "defs.h"
61cb0ef41Sopenharmony_ci#include "transportparams.h"
71cb0ef41Sopenharmony_ci#include <base_object-inl.h>
81cb0ef41Sopenharmony_ci#include <env-inl.h>
91cb0ef41Sopenharmony_ci#include <memory_tracker-inl.h>
101cb0ef41Sopenharmony_ci#include <ngtcp2/ngtcp2.h>
111cb0ef41Sopenharmony_ci#include <ngtcp2/ngtcp2_crypto.h>
121cb0ef41Sopenharmony_ci#include <ngtcp2/ngtcp2_crypto_openssl.h>
131cb0ef41Sopenharmony_ci#include <openssl/ssl.h>
141cb0ef41Sopenharmony_ci#include <v8.h>
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cinamespace node {
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciusing v8::ArrayBuffer;
191cb0ef41Sopenharmony_ciusing v8::BackingStore;
201cb0ef41Sopenharmony_ciusing v8::Just;
211cb0ef41Sopenharmony_ciusing v8::Local;
221cb0ef41Sopenharmony_ciusing v8::Maybe;
231cb0ef41Sopenharmony_ciusing v8::MaybeLocal;
241cb0ef41Sopenharmony_ciusing v8::Nothing;
251cb0ef41Sopenharmony_ciusing v8::Object;
261cb0ef41Sopenharmony_ciusing v8::Value;
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_cinamespace quic {
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci// TODO(@jasnell): This session class is just a placeholder.
311cb0ef41Sopenharmony_ci// The real session impl will be added in a separate commit.
321cb0ef41Sopenharmony_ciclass Session {
331cb0ef41Sopenharmony_ci public:
341cb0ef41Sopenharmony_ci  operator ngtcp2_conn*() { return nullptr; }
351cb0ef41Sopenharmony_ci  void EmitKeylog(const char* line) const {}
361cb0ef41Sopenharmony_ci  void EmitSessionTicket(Store&& store) {}
371cb0ef41Sopenharmony_ci  void SetStreamOpenAllowed() {}
381cb0ef41Sopenharmony_ci  bool is_destroyed() const { return false; }
391cb0ef41Sopenharmony_ci  bool wants_session_ticket() const { return false; }
401cb0ef41Sopenharmony_ci};
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_cinamespace {
431cb0ef41Sopenharmony_ciconstexpr size_t kMaxAlpnLen = 255;
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ciint AllowEarlyDataCallback(SSL* ssl, void* arg) {
461cb0ef41Sopenharmony_ci  // Currently, we always allow early data. Later we might make
471cb0ef41Sopenharmony_ci  // it configurable.
481cb0ef41Sopenharmony_ci  return 1;
491cb0ef41Sopenharmony_ci}
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ciint NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
521cb0ef41Sopenharmony_ci  // We use this event to trigger generation of the SessionTicket
531cb0ef41Sopenharmony_ci  // if the user has requested to receive it.
541cb0ef41Sopenharmony_ci  return TLSContext::From(ssl).OnNewSession(session);
551cb0ef41Sopenharmony_ci}
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_civoid KeylogCallback(const SSL* ssl, const char* line) {
581cb0ef41Sopenharmony_ci  TLSContext::From(ssl).Keylog(line);
591cb0ef41Sopenharmony_ci}
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ciint AlpnSelectionCallback(SSL* ssl,
621cb0ef41Sopenharmony_ci                          const unsigned char** out,
631cb0ef41Sopenharmony_ci                          unsigned char* outlen,
641cb0ef41Sopenharmony_ci                          const unsigned char* in,
651cb0ef41Sopenharmony_ci                          unsigned int inlen,
661cb0ef41Sopenharmony_ci                          void* arg) {
671cb0ef41Sopenharmony_ci  auto& context = TLSContext::From(ssl);
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  auto requested = context.options().alpn;
701cb0ef41Sopenharmony_ci  if (requested.length() > kMaxAlpnLen) return SSL_TLSEXT_ERR_NOACK;
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  // The Session supports exactly one ALPN identifier. If that does not match
731cb0ef41Sopenharmony_ci  // any of the ALPN identifiers provided in the client request, then we fail
741cb0ef41Sopenharmony_ci  // here. Note that this will not fail the TLS handshake, so we have to check
751cb0ef41Sopenharmony_ci  // later if the ALPN matches the expected identifier or not.
761cb0ef41Sopenharmony_ci  //
771cb0ef41Sopenharmony_ci  // We might eventually want to support the ability to negotiate multiple
781cb0ef41Sopenharmony_ci  // possible ALPN's on a single endpoint/session but for now, we only support
791cb0ef41Sopenharmony_ci  // one.
801cb0ef41Sopenharmony_ci  if (SSL_select_next_proto(
811cb0ef41Sopenharmony_ci          const_cast<unsigned char**>(out),
821cb0ef41Sopenharmony_ci          outlen,
831cb0ef41Sopenharmony_ci          reinterpret_cast<const unsigned char*>(requested.c_str()),
841cb0ef41Sopenharmony_ci          requested.length(),
851cb0ef41Sopenharmony_ci          in,
861cb0ef41Sopenharmony_ci          inlen) == OPENSSL_NPN_NO_OVERLAP) {
871cb0ef41Sopenharmony_ci    return SSL_TLSEXT_ERR_NOACK;
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci  return SSL_TLSEXT_ERR_OK;
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ciBaseObjectPtr<crypto::SecureContext> InitializeSecureContext(
941cb0ef41Sopenharmony_ci    Side side, Environment* env, const TLSContext::Options& options) {
951cb0ef41Sopenharmony_ci  auto context = crypto::SecureContext::Create(env);
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  auto& ctx = context->ctx();
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  switch (side) {
1001cb0ef41Sopenharmony_ci    case Side::SERVER: {
1011cb0ef41Sopenharmony_ci      ctx.reset(SSL_CTX_new(TLS_server_method()));
1021cb0ef41Sopenharmony_ci      SSL_CTX_set_app_data(ctx.get(), context);
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci      if (ngtcp2_crypto_openssl_configure_server_context(ctx.get()) != 0) {
1051cb0ef41Sopenharmony_ci        return BaseObjectPtr<crypto::SecureContext>();
1061cb0ef41Sopenharmony_ci      }
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci      SSL_CTX_set_max_early_data(ctx.get(), UINT32_MAX);
1091cb0ef41Sopenharmony_ci      SSL_CTX_set_allow_early_data_cb(
1101cb0ef41Sopenharmony_ci          ctx.get(), AllowEarlyDataCallback, nullptr);
1111cb0ef41Sopenharmony_ci      SSL_CTX_set_options(ctx.get(),
1121cb0ef41Sopenharmony_ci                          (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
1131cb0ef41Sopenharmony_ci                              SSL_OP_SINGLE_ECDH_USE |
1141cb0ef41Sopenharmony_ci                              SSL_OP_CIPHER_SERVER_PREFERENCE |
1151cb0ef41Sopenharmony_ci                              SSL_OP_NO_ANTI_REPLAY);
1161cb0ef41Sopenharmony_ci      SSL_CTX_set_mode(ctx.get(), SSL_MODE_RELEASE_BUFFERS);
1171cb0ef41Sopenharmony_ci      SSL_CTX_set_alpn_select_cb(ctx.get(), AlpnSelectionCallback, nullptr);
1181cb0ef41Sopenharmony_ci      SSL_CTX_set_session_ticket_cb(ctx.get(),
1191cb0ef41Sopenharmony_ci                                    SessionTicket::GenerateCallback,
1201cb0ef41Sopenharmony_ci                                    SessionTicket::DecryptedCallback,
1211cb0ef41Sopenharmony_ci                                    nullptr);
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci      const unsigned char* sid_ctx = reinterpret_cast<const unsigned char*>(
1241cb0ef41Sopenharmony_ci          options.session_id_ctx.c_str());
1251cb0ef41Sopenharmony_ci      SSL_CTX_set_session_id_context(
1261cb0ef41Sopenharmony_ci          ctx.get(), sid_ctx, options.session_id_ctx.length());
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci      break;
1291cb0ef41Sopenharmony_ci    }
1301cb0ef41Sopenharmony_ci    case Side::CLIENT: {
1311cb0ef41Sopenharmony_ci      ctx.reset(SSL_CTX_new(TLS_client_method()));
1321cb0ef41Sopenharmony_ci      SSL_CTX_set_app_data(ctx.get(), context);
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci      if (ngtcp2_crypto_openssl_configure_client_context(ctx.get()) != 0) {
1351cb0ef41Sopenharmony_ci        return BaseObjectPtr<crypto::SecureContext>();
1361cb0ef41Sopenharmony_ci      }
1371cb0ef41Sopenharmony_ci
1381cb0ef41Sopenharmony_ci      SSL_CTX_set_session_cache_mode(
1391cb0ef41Sopenharmony_ci          ctx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE);
1401cb0ef41Sopenharmony_ci      SSL_CTX_sess_set_new_cb(ctx.get(), NewSessionCallback);
1411cb0ef41Sopenharmony_ci      break;
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci    default:
1441cb0ef41Sopenharmony_ci      UNREACHABLE();
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  SSL_CTX_set_default_verify_paths(ctx.get());
1481cb0ef41Sopenharmony_ci
1491cb0ef41Sopenharmony_ci  if (options.keylog) SSL_CTX_set_keylog_callback(ctx.get(), KeylogCallback);
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  if (SSL_CTX_set_ciphersuites(ctx.get(), options.ciphers.c_str()) != 1) {
1521cb0ef41Sopenharmony_ci    return BaseObjectPtr<crypto::SecureContext>();
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  if (SSL_CTX_set1_groups_list(ctx.get(), options.groups.c_str()) != 1) {
1561cb0ef41Sopenharmony_ci    return BaseObjectPtr<crypto::SecureContext>();
1571cb0ef41Sopenharmony_ci  }
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  // Handle CA certificates...
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci  const auto addCACert = [&](uv_buf_t ca) {
1621cb0ef41Sopenharmony_ci    crypto::ClearErrorOnReturn clear_error_on_return;
1631cb0ef41Sopenharmony_ci    crypto::BIOPointer bio = crypto::NodeBIO::NewFixed(ca.base, ca.len);
1641cb0ef41Sopenharmony_ci    if (!bio) return false;
1651cb0ef41Sopenharmony_ci    context->SetCACert(bio);
1661cb0ef41Sopenharmony_ci    return true;
1671cb0ef41Sopenharmony_ci  };
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci  const auto addRootCerts = [&] {
1701cb0ef41Sopenharmony_ci    crypto::ClearErrorOnReturn clear_error_on_return;
1711cb0ef41Sopenharmony_ci    context->SetRootCerts();
1721cb0ef41Sopenharmony_ci  };
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  if (!options.ca.empty()) {
1751cb0ef41Sopenharmony_ci    for (auto& ca : options.ca) {
1761cb0ef41Sopenharmony_ci      if (!addCACert(ca)) {
1771cb0ef41Sopenharmony_ci        return BaseObjectPtr<crypto::SecureContext>();
1781cb0ef41Sopenharmony_ci      }
1791cb0ef41Sopenharmony_ci    }
1801cb0ef41Sopenharmony_ci  } else {
1811cb0ef41Sopenharmony_ci    addRootCerts();
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_ci  // Handle Certs
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  const auto addCert = [&](uv_buf_t cert) {
1871cb0ef41Sopenharmony_ci    crypto::ClearErrorOnReturn clear_error_on_return;
1881cb0ef41Sopenharmony_ci    crypto::BIOPointer bio = crypto::NodeBIO::NewFixed(cert.base, cert.len);
1891cb0ef41Sopenharmony_ci    if (!bio) return Just(false);
1901cb0ef41Sopenharmony_ci    auto ret = context->AddCert(env, std::move(bio));
1911cb0ef41Sopenharmony_ci    return ret;
1921cb0ef41Sopenharmony_ci  };
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  for (auto& cert : options.certs) {
1951cb0ef41Sopenharmony_ci    if (!addCert(cert).IsJust()) {
1961cb0ef41Sopenharmony_ci      return BaseObjectPtr<crypto::SecureContext>();
1971cb0ef41Sopenharmony_ci    }
1981cb0ef41Sopenharmony_ci  }
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  // Handle keys
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  const auto addKey = [&](auto& key) {
2031cb0ef41Sopenharmony_ci    crypto::ClearErrorOnReturn clear_error_on_return;
2041cb0ef41Sopenharmony_ci    return context->UseKey(env, key);
2051cb0ef41Sopenharmony_ci    // TODO(@jasnell): Maybe SSL_CTX_check_private_key also?
2061cb0ef41Sopenharmony_ci  };
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  for (auto& key : options.keys) {
2091cb0ef41Sopenharmony_ci    if (!addKey(key).IsJust()) {
2101cb0ef41Sopenharmony_ci      return BaseObjectPtr<crypto::SecureContext>();
2111cb0ef41Sopenharmony_ci    }
2121cb0ef41Sopenharmony_ci  }
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci  // Handle CRL
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  const auto addCRL = [&](uv_buf_t crl) {
2171cb0ef41Sopenharmony_ci    crypto::ClearErrorOnReturn clear_error_on_return;
2181cb0ef41Sopenharmony_ci    crypto::BIOPointer bio = crypto::NodeBIO::NewFixed(crl.base, crl.len);
2191cb0ef41Sopenharmony_ci    if (!bio) return Just(false);
2201cb0ef41Sopenharmony_ci    return context->SetCRL(env, bio);
2211cb0ef41Sopenharmony_ci  };
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_ci  for (auto& crl : options.crl) {
2241cb0ef41Sopenharmony_ci    if (!addCRL(crl).IsJust()) {
2251cb0ef41Sopenharmony_ci      return BaseObjectPtr<crypto::SecureContext>();
2261cb0ef41Sopenharmony_ci    }
2271cb0ef41Sopenharmony_ci  }
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci  // TODO(@jasnell): Possibly handle other bits. Such a pfx, client cert engine,
2301cb0ef41Sopenharmony_ci  // and session timeout.
2311cb0ef41Sopenharmony_ci  return BaseObjectPtr<crypto::SecureContext>(context);
2321cb0ef41Sopenharmony_ci}
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_civoid EnableTrace(Environment* env, crypto::BIOPointer* bio, SSL* ssl) {
2351cb0ef41Sopenharmony_ci#if HAVE_SSL_TRACE
2361cb0ef41Sopenharmony_ci  static bool warn_trace_tls = true;
2371cb0ef41Sopenharmony_ci  if (warn_trace_tls) {
2381cb0ef41Sopenharmony_ci    warn_trace_tls = false;
2391cb0ef41Sopenharmony_ci    ProcessEmitWarning(env,
2401cb0ef41Sopenharmony_ci                       "Enabling --trace-tls can expose sensitive data in "
2411cb0ef41Sopenharmony_ci                       "the resulting log");
2421cb0ef41Sopenharmony_ci  }
2431cb0ef41Sopenharmony_ci  if (!*bio) {
2441cb0ef41Sopenharmony_ci    bio->reset(BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT));
2451cb0ef41Sopenharmony_ci    SSL_set_msg_callback(
2461cb0ef41Sopenharmony_ci        ssl,
2471cb0ef41Sopenharmony_ci        [](int write_p,
2481cb0ef41Sopenharmony_ci           int version,
2491cb0ef41Sopenharmony_ci           int content_type,
2501cb0ef41Sopenharmony_ci           const void* buf,
2511cb0ef41Sopenharmony_ci           size_t len,
2521cb0ef41Sopenharmony_ci           SSL* ssl,
2531cb0ef41Sopenharmony_ci           void* arg) -> void {
2541cb0ef41Sopenharmony_ci          crypto::MarkPopErrorOnReturn mark_pop_error_on_return;
2551cb0ef41Sopenharmony_ci          SSL_trace(write_p, version, content_type, buf, len, ssl, arg);
2561cb0ef41Sopenharmony_ci        });
2571cb0ef41Sopenharmony_ci    SSL_set_msg_callback_arg(ssl, bio->get());
2581cb0ef41Sopenharmony_ci  }
2591cb0ef41Sopenharmony_ci#endif
2601cb0ef41Sopenharmony_ci}
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_citemplate <typename T, typename Opt, std::vector<T> Opt::*member>
2631cb0ef41Sopenharmony_cibool SetOption(Environment* env,
2641cb0ef41Sopenharmony_ci               Opt* options,
2651cb0ef41Sopenharmony_ci               const v8::Local<v8::Object>& object,
2661cb0ef41Sopenharmony_ci               const v8::Local<v8::String>& name) {
2671cb0ef41Sopenharmony_ci  v8::Local<v8::Value> value;
2681cb0ef41Sopenharmony_ci  if (!object->Get(env->context(), name).ToLocal(&value)) return false;
2691cb0ef41Sopenharmony_ci
2701cb0ef41Sopenharmony_ci  // The value can be either a single item or an array of items.
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  if (value->IsArray()) {
2731cb0ef41Sopenharmony_ci    auto context = env->context();
2741cb0ef41Sopenharmony_ci    auto values = value.As<v8::Array>();
2751cb0ef41Sopenharmony_ci    uint32_t count = values->Length();
2761cb0ef41Sopenharmony_ci    for (uint32_t n = 0; n < count; n++) {
2771cb0ef41Sopenharmony_ci      v8::Local<v8::Value> item;
2781cb0ef41Sopenharmony_ci      if (!values->Get(context, n).ToLocal(&item)) {
2791cb0ef41Sopenharmony_ci        return false;
2801cb0ef41Sopenharmony_ci      }
2811cb0ef41Sopenharmony_ci      if constexpr (std::is_same<T, std::shared_ptr<crypto::KeyObjectData>>::
2821cb0ef41Sopenharmony_ci                        value) {
2831cb0ef41Sopenharmony_ci        if (crypto::KeyObjectHandle::HasInstance(env, item)) {
2841cb0ef41Sopenharmony_ci          crypto::KeyObjectHandle* handle;
2851cb0ef41Sopenharmony_ci          ASSIGN_OR_RETURN_UNWRAP(&handle, item, false);
2861cb0ef41Sopenharmony_ci          (options->*member).push_back(handle->Data());
2871cb0ef41Sopenharmony_ci        } else {
2881cb0ef41Sopenharmony_ci          return false;
2891cb0ef41Sopenharmony_ci        }
2901cb0ef41Sopenharmony_ci      } else if constexpr (std::is_same<T, Store>::value) {
2911cb0ef41Sopenharmony_ci        if (item->IsArrayBufferView()) {
2921cb0ef41Sopenharmony_ci          (options->*member).emplace_back(item.As<v8::ArrayBufferView>());
2931cb0ef41Sopenharmony_ci        } else if (item->IsArrayBuffer()) {
2941cb0ef41Sopenharmony_ci          (options->*member).emplace_back(item.As<v8::ArrayBuffer>());
2951cb0ef41Sopenharmony_ci        } else {
2961cb0ef41Sopenharmony_ci          return false;
2971cb0ef41Sopenharmony_ci        }
2981cb0ef41Sopenharmony_ci      }
2991cb0ef41Sopenharmony_ci    }
3001cb0ef41Sopenharmony_ci  } else {
3011cb0ef41Sopenharmony_ci    if constexpr (std::is_same<T,
3021cb0ef41Sopenharmony_ci                               std::shared_ptr<crypto::KeyObjectData>>::value) {
3031cb0ef41Sopenharmony_ci      if (crypto::KeyObjectHandle::HasInstance(env, value)) {
3041cb0ef41Sopenharmony_ci        crypto::KeyObjectHandle* handle;
3051cb0ef41Sopenharmony_ci        ASSIGN_OR_RETURN_UNWRAP(&handle, value, false);
3061cb0ef41Sopenharmony_ci        (options->*member).push_back(handle->Data());
3071cb0ef41Sopenharmony_ci      } else {
3081cb0ef41Sopenharmony_ci        return false;
3091cb0ef41Sopenharmony_ci      }
3101cb0ef41Sopenharmony_ci    } else if constexpr (std::is_same<T, Store>::value) {
3111cb0ef41Sopenharmony_ci      if (value->IsArrayBufferView()) {
3121cb0ef41Sopenharmony_ci        (options->*member).emplace_back(value.As<v8::ArrayBufferView>());
3131cb0ef41Sopenharmony_ci      } else if (value->IsArrayBuffer()) {
3141cb0ef41Sopenharmony_ci        (options->*member).emplace_back(value.As<v8::ArrayBuffer>());
3151cb0ef41Sopenharmony_ci      } else {
3161cb0ef41Sopenharmony_ci        return false;
3171cb0ef41Sopenharmony_ci      }
3181cb0ef41Sopenharmony_ci    }
3191cb0ef41Sopenharmony_ci  }
3201cb0ef41Sopenharmony_ci  return true;
3211cb0ef41Sopenharmony_ci}
3221cb0ef41Sopenharmony_ci}  // namespace
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_ciSide TLSContext::side() const {
3251cb0ef41Sopenharmony_ci  return side_;
3261cb0ef41Sopenharmony_ci}
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ciconst TLSContext::Options& TLSContext::options() const {
3291cb0ef41Sopenharmony_ci  return options_;
3301cb0ef41Sopenharmony_ci}
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ciinline const TLSContext& TLSContext::From(const SSL* ssl) {
3331cb0ef41Sopenharmony_ci  auto ref = static_cast<ngtcp2_crypto_conn_ref*>(SSL_get_app_data(ssl));
3341cb0ef41Sopenharmony_ci  TLSContext* context = ContainerOf(&TLSContext::conn_ref_, ref);
3351cb0ef41Sopenharmony_ci  return *context;
3361cb0ef41Sopenharmony_ci}
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ciinline TLSContext& TLSContext::From(SSL* ssl) {
3391cb0ef41Sopenharmony_ci  auto ref = static_cast<ngtcp2_crypto_conn_ref*>(SSL_get_app_data(ssl));
3401cb0ef41Sopenharmony_ci  TLSContext* context = ContainerOf(&TLSContext::conn_ref_, ref);
3411cb0ef41Sopenharmony_ci  return *context;
3421cb0ef41Sopenharmony_ci}
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ciTLSContext::TLSContext(Environment* env,
3451cb0ef41Sopenharmony_ci                       Side side,
3461cb0ef41Sopenharmony_ci                       Session* session,
3471cb0ef41Sopenharmony_ci                       const Options& options)
3481cb0ef41Sopenharmony_ci    : conn_ref_({getConnection, this}),
3491cb0ef41Sopenharmony_ci      side_(side),
3501cb0ef41Sopenharmony_ci      env_(env),
3511cb0ef41Sopenharmony_ci      session_(session),
3521cb0ef41Sopenharmony_ci      options_(options),
3531cb0ef41Sopenharmony_ci      secure_context_(InitializeSecureContext(side, env, options)) {
3541cb0ef41Sopenharmony_ci  CHECK(secure_context_);
3551cb0ef41Sopenharmony_ci  ssl_.reset(SSL_new(secure_context_->ctx().get()));
3561cb0ef41Sopenharmony_ci  CHECK(ssl_ && SSL_is_quic(ssl_.get()));
3571cb0ef41Sopenharmony_ci
3581cb0ef41Sopenharmony_ci  SSL_set_app_data(ssl_.get(), &conn_ref_);
3591cb0ef41Sopenharmony_ci  SSL_set_verify(ssl_.get(), SSL_VERIFY_NONE, crypto::VerifyCallback);
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  // Enable tracing if the `--trace-tls` command line flag is used.
3621cb0ef41Sopenharmony_ci  if (UNLIKELY(env->options()->trace_tls || options.enable_tls_trace))
3631cb0ef41Sopenharmony_ci    EnableTrace(env, &bio_trace_, ssl_.get());
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  switch (side) {
3661cb0ef41Sopenharmony_ci    case Side::CLIENT: {
3671cb0ef41Sopenharmony_ci      SSL_set_connect_state(ssl_.get());
3681cb0ef41Sopenharmony_ci      CHECK_EQ(0,
3691cb0ef41Sopenharmony_ci               SSL_set_alpn_protos(ssl_.get(),
3701cb0ef41Sopenharmony_ci                                   reinterpret_cast<const unsigned char*>(
3711cb0ef41Sopenharmony_ci                                       options_.alpn.c_str()),
3721cb0ef41Sopenharmony_ci                                   options_.alpn.length()));
3731cb0ef41Sopenharmony_ci      CHECK_EQ(0,
3741cb0ef41Sopenharmony_ci               SSL_set_tlsext_host_name(ssl_.get(), options_.hostname.c_str()));
3751cb0ef41Sopenharmony_ci      break;
3761cb0ef41Sopenharmony_ci    }
3771cb0ef41Sopenharmony_ci    case Side::SERVER: {
3781cb0ef41Sopenharmony_ci      SSL_set_accept_state(ssl_.get());
3791cb0ef41Sopenharmony_ci      if (options.request_peer_certificate) {
3801cb0ef41Sopenharmony_ci        int verify_mode = SSL_VERIFY_PEER;
3811cb0ef41Sopenharmony_ci        if (options.reject_unauthorized)
3821cb0ef41Sopenharmony_ci          verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
3831cb0ef41Sopenharmony_ci        SSL_set_verify(ssl_.get(), verify_mode, crypto::VerifyCallback);
3841cb0ef41Sopenharmony_ci      }
3851cb0ef41Sopenharmony_ci      break;
3861cb0ef41Sopenharmony_ci    }
3871cb0ef41Sopenharmony_ci    default:
3881cb0ef41Sopenharmony_ci      UNREACHABLE();
3891cb0ef41Sopenharmony_ci  }
3901cb0ef41Sopenharmony_ci}
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_civoid TLSContext::Start() {
3931cb0ef41Sopenharmony_ci  ngtcp2_conn_set_tls_native_handle(*session_, ssl_.get());
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ci  TransportParams tp(TransportParams::Type::ENCRYPTED_EXTENSIONS,
3961cb0ef41Sopenharmony_ci                     ngtcp2_conn_get_local_transport_params(*session_));
3971cb0ef41Sopenharmony_ci  Store store = tp.Encode(env_);
3981cb0ef41Sopenharmony_ci  if (store && store.length() > 0) {
3991cb0ef41Sopenharmony_ci    ngtcp2_vec vec = store;
4001cb0ef41Sopenharmony_ci    SSL_set_quic_transport_params(ssl_.get(), vec.base, vec.len);
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci}
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_civoid TLSContext::Keylog(const char* line) const {
4051cb0ef41Sopenharmony_ci  session_->EmitKeylog(line);
4061cb0ef41Sopenharmony_ci}
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ciint TLSContext::Receive(ngtcp2_crypto_level crypto_level,
4091cb0ef41Sopenharmony_ci                        uint64_t offset,
4101cb0ef41Sopenharmony_ci                        const ngtcp2_vec& vec) {
4111cb0ef41Sopenharmony_ci  // ngtcp2 provides an implementation of this in
4121cb0ef41Sopenharmony_ci  // ngtcp2_crypto_recv_crypto_data_cb but given that we are using the
4131cb0ef41Sopenharmony_ci  // implementation specific error codes below, we can't use it.
4141cb0ef41Sopenharmony_ci
4151cb0ef41Sopenharmony_ci  if (UNLIKELY(session_->is_destroyed())) return NGTCP2_ERR_CALLBACK_FAILURE;
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_ci  // Internally, this passes the handshake data off to openssl for processing.
4181cb0ef41Sopenharmony_ci  // The handshake may or may not complete.
4191cb0ef41Sopenharmony_ci  int ret = ngtcp2_crypto_read_write_crypto_data(
4201cb0ef41Sopenharmony_ci      *session_, crypto_level, vec.base, vec.len);
4211cb0ef41Sopenharmony_ci
4221cb0ef41Sopenharmony_ci  switch (ret) {
4231cb0ef41Sopenharmony_ci    case 0:
4241cb0ef41Sopenharmony_ci    // Fall-through
4251cb0ef41Sopenharmony_ci
4261cb0ef41Sopenharmony_ci    // In either of following cases, the handshake is being paused waiting for
4271cb0ef41Sopenharmony_ci    // user code to take action (for instance OCSP requests or client hello
4281cb0ef41Sopenharmony_ci    // modification)
4291cb0ef41Sopenharmony_ci    case NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_X509_LOOKUP:
4301cb0ef41Sopenharmony_ci      [[fallthrough]];
4311cb0ef41Sopenharmony_ci    case NGTCP2_CRYPTO_OPENSSL_ERR_TLS_WANT_CLIENT_HELLO_CB:
4321cb0ef41Sopenharmony_ci      return 0;
4331cb0ef41Sopenharmony_ci  }
4341cb0ef41Sopenharmony_ci  return ret;
4351cb0ef41Sopenharmony_ci}
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ciint TLSContext::OnNewSession(SSL_SESSION* session) {
4381cb0ef41Sopenharmony_ci  // Used to generate and emit a SessionTicket for TLS session resumption.
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  // If there is nothing listening for the session ticket, don't both emitting.
4411cb0ef41Sopenharmony_ci  if (!session_->wants_session_ticket()) return 0;
4421cb0ef41Sopenharmony_ci
4431cb0ef41Sopenharmony_ci  // Pre-fight to see how much space we need to allocate for the session ticket.
4441cb0ef41Sopenharmony_ci  size_t size = i2d_SSL_SESSION(session, nullptr);
4451cb0ef41Sopenharmony_ci
4461cb0ef41Sopenharmony_ci  if (size > 0 && size < crypto::SecureContext::kMaxSessionSize) {
4471cb0ef41Sopenharmony_ci    // Generate the actual ticket. If this fails, we'll simply carry on without
4481cb0ef41Sopenharmony_ci    // emitting the ticket.
4491cb0ef41Sopenharmony_ci    std::shared_ptr<BackingStore> ticket =
4501cb0ef41Sopenharmony_ci        ArrayBuffer::NewBackingStore(env_->isolate(), size);
4511cb0ef41Sopenharmony_ci    unsigned char* data = reinterpret_cast<unsigned char*>(ticket->Data());
4521cb0ef41Sopenharmony_ci    if (i2d_SSL_SESSION(session, &data) <= 0) return 0;
4531cb0ef41Sopenharmony_ci    session_->EmitSessionTicket(Store(std::move(ticket), size));
4541cb0ef41Sopenharmony_ci  }
4551cb0ef41Sopenharmony_ci  // If size == 0, there's no session ticket data to emit. Let's ignore it
4561cb0ef41Sopenharmony_ci  // and continue without emitting the sessionticket event.
4571cb0ef41Sopenharmony_ci
4581cb0ef41Sopenharmony_ci  return 0;
4591cb0ef41Sopenharmony_ci}
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_cibool TLSContext::InitiateKeyUpdate() {
4621cb0ef41Sopenharmony_ci  if (session_->is_destroyed() || in_key_update_) return false;
4631cb0ef41Sopenharmony_ci  auto leave = OnScopeLeave([this] { in_key_update_ = false; });
4641cb0ef41Sopenharmony_ci  in_key_update_ = true;
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci  return ngtcp2_conn_initiate_key_update(*session_, uv_hrtime()) == 0;
4671cb0ef41Sopenharmony_ci}
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ciint TLSContext::VerifyPeerIdentity() {
4701cb0ef41Sopenharmony_ci  return crypto::VerifyPeerCertificate(ssl_);
4711cb0ef41Sopenharmony_ci}
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_civoid TLSContext::MaybeSetEarlySession(const SessionTicket& sessionTicket) {
4741cb0ef41Sopenharmony_ci  TransportParams rtp(TransportParams::Type::ENCRYPTED_EXTENSIONS,
4751cb0ef41Sopenharmony_ci                      sessionTicket.transport_params());
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_ci  // Ignore invalid remote transport parameters.
4781cb0ef41Sopenharmony_ci  if (!rtp) return;
4791cb0ef41Sopenharmony_ci
4801cb0ef41Sopenharmony_ci  uv_buf_t buf = sessionTicket.ticket();
4811cb0ef41Sopenharmony_ci  crypto::SSLSessionPointer ticket = crypto::GetTLSSession(
4821cb0ef41Sopenharmony_ci      reinterpret_cast<unsigned char*>(buf.base), buf.len);
4831cb0ef41Sopenharmony_ci
4841cb0ef41Sopenharmony_ci  // Silently ignore invalid TLS session
4851cb0ef41Sopenharmony_ci  if (!ticket || !SSL_SESSION_get_max_early_data(ticket.get())) return;
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci  // The early data will just be ignored if it's invalid.
4881cb0ef41Sopenharmony_ci  if (crypto::SetTLSSession(ssl_, ticket)) {
4891cb0ef41Sopenharmony_ci    ngtcp2_conn_set_early_remote_transport_params(*session_, rtp);
4901cb0ef41Sopenharmony_ci    session_->SetStreamOpenAllowed();
4911cb0ef41Sopenharmony_ci  }
4921cb0ef41Sopenharmony_ci}
4931cb0ef41Sopenharmony_ci
4941cb0ef41Sopenharmony_civoid TLSContext::MemoryInfo(MemoryTracker* tracker) const {
4951cb0ef41Sopenharmony_ci  tracker->TrackField("options", options_);
4961cb0ef41Sopenharmony_ci  tracker->TrackField("secure_context", secure_context_);
4971cb0ef41Sopenharmony_ci}
4981cb0ef41Sopenharmony_ci
4991cb0ef41Sopenharmony_ciMaybeLocal<Object> TLSContext::cert(Environment* env) const {
5001cb0ef41Sopenharmony_ci  return crypto::X509Certificate::GetCert(env, ssl_);
5011cb0ef41Sopenharmony_ci}
5021cb0ef41Sopenharmony_ci
5031cb0ef41Sopenharmony_ciMaybeLocal<Object> TLSContext::peer_cert(Environment* env) const {
5041cb0ef41Sopenharmony_ci  crypto::X509Certificate::GetPeerCertificateFlag flag =
5051cb0ef41Sopenharmony_ci      side_ == Side::SERVER
5061cb0ef41Sopenharmony_ci          ? crypto::X509Certificate::GetPeerCertificateFlag::SERVER
5071cb0ef41Sopenharmony_ci          : crypto::X509Certificate::GetPeerCertificateFlag::NONE;
5081cb0ef41Sopenharmony_ci  return crypto::X509Certificate::GetPeerCert(env, ssl_, flag);
5091cb0ef41Sopenharmony_ci}
5101cb0ef41Sopenharmony_ci
5111cb0ef41Sopenharmony_ciMaybeLocal<Value> TLSContext::cipher_name(Environment* env) const {
5121cb0ef41Sopenharmony_ci  return crypto::GetCurrentCipherName(env, ssl_);
5131cb0ef41Sopenharmony_ci}
5141cb0ef41Sopenharmony_ci
5151cb0ef41Sopenharmony_ciMaybeLocal<Value> TLSContext::cipher_version(Environment* env) const {
5161cb0ef41Sopenharmony_ci  return crypto::GetCurrentCipherVersion(env, ssl_);
5171cb0ef41Sopenharmony_ci}
5181cb0ef41Sopenharmony_ci
5191cb0ef41Sopenharmony_ciMaybeLocal<Object> TLSContext::ephemeral_key(Environment* env) const {
5201cb0ef41Sopenharmony_ci  return crypto::GetEphemeralKey(env, ssl_);
5211cb0ef41Sopenharmony_ci}
5221cb0ef41Sopenharmony_ci
5231cb0ef41Sopenharmony_ciconst std::string_view TLSContext::servername() const {
5241cb0ef41Sopenharmony_ci  const char* servername = crypto::GetServerName(ssl_.get());
5251cb0ef41Sopenharmony_ci  return servername != nullptr ? std::string_view(servername)
5261cb0ef41Sopenharmony_ci                               : std::string_view();
5271cb0ef41Sopenharmony_ci}
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ciconst std::string_view TLSContext::alpn() const {
5301cb0ef41Sopenharmony_ci  const unsigned char* alpn_buf = nullptr;
5311cb0ef41Sopenharmony_ci  unsigned int alpnlen;
5321cb0ef41Sopenharmony_ci  SSL_get0_alpn_selected(ssl_.get(), &alpn_buf, &alpnlen);
5331cb0ef41Sopenharmony_ci  return alpnlen ? std::string_view(reinterpret_cast<const char*>(alpn_buf),
5341cb0ef41Sopenharmony_ci                                    alpnlen)
5351cb0ef41Sopenharmony_ci                 : std::string_view();
5361cb0ef41Sopenharmony_ci}
5371cb0ef41Sopenharmony_ci
5381cb0ef41Sopenharmony_cibool TLSContext::early_data_was_accepted() const {
5391cb0ef41Sopenharmony_ci  return (early_data_ &&
5401cb0ef41Sopenharmony_ci          SSL_get_early_data_status(ssl_.get()) == SSL_EARLY_DATA_ACCEPTED);
5411cb0ef41Sopenharmony_ci}
5421cb0ef41Sopenharmony_ci
5431cb0ef41Sopenharmony_civoid TLSContext::Options::MemoryInfo(MemoryTracker* tracker) const {
5441cb0ef41Sopenharmony_ci  tracker->TrackField("keys", keys);
5451cb0ef41Sopenharmony_ci  tracker->TrackField("certs", certs);
5461cb0ef41Sopenharmony_ci  tracker->TrackField("ca", ca);
5471cb0ef41Sopenharmony_ci  tracker->TrackField("crl", crl);
5481cb0ef41Sopenharmony_ci}
5491cb0ef41Sopenharmony_ci
5501cb0ef41Sopenharmony_cingtcp2_conn* TLSContext::getConnection(ngtcp2_crypto_conn_ref* ref) {
5511cb0ef41Sopenharmony_ci  TLSContext* context = ContainerOf(&TLSContext::conn_ref_, ref);
5521cb0ef41Sopenharmony_ci  return *context->session_;
5531cb0ef41Sopenharmony_ci}
5541cb0ef41Sopenharmony_ci
5551cb0ef41Sopenharmony_ciMaybe<const TLSContext::Options> TLSContext::Options::From(Environment* env,
5561cb0ef41Sopenharmony_ci                                                           Local<Value> value) {
5571cb0ef41Sopenharmony_ci  if (value.IsEmpty() || !value->IsObject()) {
5581cb0ef41Sopenharmony_ci    return Nothing<const Options>();
5591cb0ef41Sopenharmony_ci  }
5601cb0ef41Sopenharmony_ci
5611cb0ef41Sopenharmony_ci  auto& state = BindingData::Get(env);
5621cb0ef41Sopenharmony_ci  auto params = value.As<Object>();
5631cb0ef41Sopenharmony_ci  Options options;
5641cb0ef41Sopenharmony_ci
5651cb0ef41Sopenharmony_ci#define SET_VECTOR(Type, name)                                                 \
5661cb0ef41Sopenharmony_ci  SetOption<Type, TLSContext::Options, &TLSContext::Options::name>(            \
5671cb0ef41Sopenharmony_ci      env, &options, params, state.name##_string())
5681cb0ef41Sopenharmony_ci
5691cb0ef41Sopenharmony_ci#define SET(name)                                                              \
5701cb0ef41Sopenharmony_ci  SetOption<TLSContext::Options, &TLSContext::Options::name>(                  \
5711cb0ef41Sopenharmony_ci      env, &options, params, state.name##_string())
5721cb0ef41Sopenharmony_ci
5731cb0ef41Sopenharmony_ci  if (!SET(keylog) || !SET(reject_unauthorized) || !SET(enable_tls_trace) ||
5741cb0ef41Sopenharmony_ci      !SET(request_peer_certificate) || !SET(verify_hostname_identity) ||
5751cb0ef41Sopenharmony_ci      !SET(alpn) || !SET(hostname) || !SET(session_id_ctx) || !SET(ciphers) ||
5761cb0ef41Sopenharmony_ci      !SET(groups) ||
5771cb0ef41Sopenharmony_ci      !SET_VECTOR(std::shared_ptr<crypto::KeyObjectData>, keys) ||
5781cb0ef41Sopenharmony_ci      !SET_VECTOR(Store, certs) || !SET_VECTOR(Store, ca) ||
5791cb0ef41Sopenharmony_ci      !SET_VECTOR(Store, crl)) {
5801cb0ef41Sopenharmony_ci    return Nothing<const Options>();
5811cb0ef41Sopenharmony_ci  }
5821cb0ef41Sopenharmony_ci
5831cb0ef41Sopenharmony_ci  return Just<const Options>(options);
5841cb0ef41Sopenharmony_ci}
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci}  // namespace quic
5871cb0ef41Sopenharmony_ci}  // namespace node
5881cb0ef41Sopenharmony_ci
5891cb0ef41Sopenharmony_ci#endif  // HAVE_OPENSSL && NODE_OPENSSL_HAS_QUIC
590