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