diff --git a/src/nvhttp.cpp b/src/nvhttp.cpp index 8ac567970eb..8b610a4c21f 100644 --- a/src/nvhttp.cpp +++ b/src/nvhttp.cpp @@ -44,19 +44,38 @@ namespace nvhttp { crypto::cert_chain_t cert_chain; - class SunshineHttpsServer: public SimpleWeb::Server { + class SunshineHTTPS: public SimpleWeb::HTTPS { public: - SunshineHttpsServer(const std::string &certification_file, const std::string &private_key_file): - SimpleWeb::Server::Server(certification_file, private_key_file) {} + SunshineHTTPS(boost::asio::io_service &io_service, boost::asio::ssl::context &ctx): + SimpleWeb::HTTPS(io_service, ctx) {} + + virtual ~SunshineHTTPS() { + // Gracefully shutdown the TLS connection + SimpleWeb::error_code ec; + shutdown(ec); + } + }; + + class SunshineHTTPSServer: public SimpleWeb::ServerBase { + public: + SunshineHTTPSServer(const std::string &certification_file, const std::string &private_key_file): + ServerBase::ServerBase(443), + context(boost::asio::ssl::context::tls_server) { + // Disabling TLS 1.0 and 1.1 (see RFC 8996) + context.set_options(boost::asio::ssl::context::no_tlsv1); + context.set_options(boost::asio::ssl::context::no_tlsv1_1); + context.use_certificate_chain_file(certification_file); + context.use_private_key_file(private_key_file, boost::asio::ssl::context::pem); + } std::function verify; std::function, std::shared_ptr)> on_verify_failed; protected: + boost::asio::ssl::context context; + void after_bind() override { - SimpleWeb::Server::after_bind(); - if (verify) { context.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_client_once); context.set_verify_callback([](int verified, boost::asio::ssl::verify_context &ctx) { @@ -108,7 +127,7 @@ namespace nvhttp { } }; - using https_server_t = SunshineHttpsServer; + using https_server_t = SunshineHTTPSServer; using http_server_t = SimpleWeb::Server; struct conf_intern_t { @@ -142,7 +161,7 @@ namespace nvhttp { struct { util::Either< std::shared_ptr::Response>, - std::shared_ptr::Response>> + std::shared_ptr::Response>> response; std::string salt; } async_insert_pin; @@ -154,8 +173,8 @@ namespace nvhttp { std::atomic session_id_counter; using args_t = SimpleWeb::CaseInsensitiveMultimap; - using resp_https_t = std::shared_ptr::Response>; - using req_https_t = std::shared_ptr::Request>; + using resp_https_t = std::shared_ptr::Response>; + using req_https_t = std::shared_ptr::Request>; using resp_http_t = std::shared_ptr::Response>; using req_http_t = std::shared_ptr::Request>; @@ -483,7 +502,7 @@ namespace nvhttp { struct tunnel; template <> - struct tunnel { + struct tunnel { static auto constexpr to_string = "HTTPS"sv; }; @@ -671,7 +690,7 @@ namespace nvhttp { print_req(request); int pair_status = 0; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { auto args = request->parse_query_string(); auto clientID = args.find("uniqueid"s); @@ -696,7 +715,7 @@ namespace nvhttp { // Only include the MAC address for requests sent from paired clients over HTTPS. // For HTTP requests, use a placeholder MAC address that Moonlight knows to ignore. - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { tree.put("root.mac", platf::get_mac_address(net::addr_to_normalized_string(local_endpoint.address()))); } else { @@ -777,7 +796,7 @@ namespace nvhttp { void applist(resp_https_t response, req_https_t request) { - print_req(request); + print_req(request); pt::ptree tree; @@ -806,7 +825,7 @@ namespace nvhttp { void launch(bool &host_audio, resp_https_t response, req_https_t request) { - print_req(request); + print_req(request); pt::ptree tree; auto g = util::fail_guard([&]() { @@ -899,7 +918,7 @@ namespace nvhttp { void resume(bool &host_audio, resp_https_t response, req_https_t request) { - print_req(request); + print_req(request); pt::ptree tree; auto g = util::fail_guard([&]() { @@ -985,7 +1004,7 @@ namespace nvhttp { void cancel(resp_https_t response, req_https_t request) { - print_req(request); + print_req(request); pt::ptree tree; auto g = util::fail_guard([&]() { @@ -1016,7 +1035,7 @@ namespace nvhttp { void appasset(resp_https_t response, req_https_t request) { - print_req(request); + print_req(request); auto args = request->parse_query_string(); auto app_image = proc::proc.get_app_image(util::from_view(get_arg(args, "appid"))); @@ -1109,9 +1128,9 @@ namespace nvhttp { tree.put("root..status_message"s, "The client is not authorized. Certificate verification failed."s); }; - https_server.default_resource["GET"] = not_found; - https_server.resource["^/serverinfo$"]["GET"] = serverinfo; - https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair(add_cert, resp, req); }; + https_server.default_resource["GET"] = not_found; + https_server.resource["^/serverinfo$"]["GET"] = serverinfo; + https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair(add_cert, resp, req); }; https_server.resource["^/applist$"]["GET"] = applist; https_server.resource["^/appasset$"]["GET"] = appasset; https_server.resource["^/launch$"]["GET"] = [&host_audio](auto resp, auto req) { launch(host_audio, resp, req); };