Prevent unauthorized access to the HTTPS server
This commit is contained in:
@@ -5,6 +5,29 @@
|
|||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
namespace crypto {
|
namespace crypto {
|
||||||
|
cert_chain_t::cert_chain_t() : _certs {}, _cert_store {X509_STORE_new() }, _cert_ctx {X509_STORE_CTX_new() } {}
|
||||||
|
void cert_chain_t::add(x509_t &&cert) {
|
||||||
|
_certs.emplace_back(std::move(cert));
|
||||||
|
|
||||||
|
X509_STORE_add_cert(_cert_store.get(), _certs.back().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cert_chain_t::verify(x509_t::element_type *cert) {
|
||||||
|
util::fail_guard([this]() {
|
||||||
|
X509_STORE_CTX_cleanup(_cert_ctx.get());
|
||||||
|
});
|
||||||
|
|
||||||
|
X509_STORE_CTX_init(_cert_ctx.get(), _cert_store.get(), nullptr, nullptr);
|
||||||
|
X509_STORE_CTX_set_cert(_cert_ctx.get(), cert);
|
||||||
|
|
||||||
|
auto err = X509_verify_cert(_cert_ctx.get());
|
||||||
|
if(err != 1) {
|
||||||
|
return X509_verify_cert_error_string(X509_STORE_CTX_get_error(_cert_ctx.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
cipher_t::cipher_t(const crypto::aes_t &key) : ctx { EVP_CIPHER_CTX_new() }, key { key }, padding { true } {}
|
cipher_t::cipher_t(const crypto::aes_t &key) : ctx { EVP_CIPHER_CTX_new() }, key { key }, padding { true } {}
|
||||||
int cipher_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext) {
|
int cipher_t::decrypt(const std::string_view &cipher, std::vector<std::uint8_t> &plaintext) {
|
||||||
int len;
|
int len;
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ using sha256_t = std::array<std::uint8_t, SHA256_DIGEST_LENGTH>;
|
|||||||
|
|
||||||
using aes_t = std::array<std::uint8_t, 16>;
|
using aes_t = std::array<std::uint8_t, 16>;
|
||||||
using x509_t = util::safe_ptr<X509, X509_free>;
|
using x509_t = util::safe_ptr<X509, X509_free>;
|
||||||
|
using x509_store_t = util::safe_ptr<X509_STORE, X509_STORE_free>;
|
||||||
|
using x509_store_ctx_t = util::safe_ptr<X509_STORE_CTX, X509_STORE_CTX_free>;
|
||||||
using cipher_ctx_t = util::safe_ptr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
|
using cipher_ctx_t = util::safe_ptr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free>;
|
||||||
using md_ctx_t = util::safe_ptr<EVP_MD_CTX, md_ctx_destroy>;
|
using md_ctx_t = util::safe_ptr<EVP_MD_CTX, md_ctx_destroy>;
|
||||||
using bio_t = util::safe_ptr<BIO, BIO_free_all>;
|
using bio_t = util::safe_ptr<BIO, BIO_free_all>;
|
||||||
@@ -42,6 +44,19 @@ std::string_view signature(const x509_t &x);
|
|||||||
|
|
||||||
std::string rand(std::size_t bytes);
|
std::string rand(std::size_t bytes);
|
||||||
|
|
||||||
|
class cert_chain_t {
|
||||||
|
public:
|
||||||
|
KITTY_DECL_CONSTR(cert_chain_t)
|
||||||
|
|
||||||
|
void add(x509_t &&cert);
|
||||||
|
|
||||||
|
const char *verify(x509_t::element_type *cert);
|
||||||
|
private:
|
||||||
|
std::vector<x509_t> _certs;
|
||||||
|
x509_store_t _cert_store;
|
||||||
|
x509_store_ctx_t _cert_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
class cipher_t {
|
class cipher_t {
|
||||||
public:
|
public:
|
||||||
cipher_t(const aes_t &key);
|
cipher_t(const aes_t &key);
|
||||||
|
|||||||
+49
-6
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <Simple-Web-Server/server_http.hpp>
|
#include <Simple-Web-Server/server_http.hpp>
|
||||||
#include <Simple-Web-Server/server_https.hpp>
|
#include <Simple-Web-Server/server_https.hpp>
|
||||||
|
#include <boost/asio/ssl/context_base.hpp>
|
||||||
|
|
||||||
#include "uuid.h"
|
#include "uuid.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@@ -211,7 +212,7 @@ void clientchallenge(pair_session_t &sess, pt::ptree &tree, const args_t &args)
|
|||||||
tree.put("root.<xmlattr>.status_code", 200);
|
tree.put("root.<xmlattr>.status_code", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clientpairingsecret(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
void clientpairingsecret(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, pair_session_t &sess, pt::ptree &tree, const args_t &args) {
|
||||||
auto &client = sess.client;
|
auto &client = sess.client;
|
||||||
|
|
||||||
auto pairingsecret = util::from_hex_vec(args.at("clientpairingsecret"), true);
|
auto pairingsecret = util::from_hex_vec(args.at("clientpairingsecret"), true);
|
||||||
@@ -243,6 +244,7 @@ void clientpairingsecret(pair_session_t &sess, pt::ptree &tree, const args_t &ar
|
|||||||
|
|
||||||
if(crypto::verify256(crypto::x509(client.cert), secret, sign)) {
|
if(crypto::verify256(crypto::x509(client.cert), secret, sign)) {
|
||||||
tree.put("root.paired", 1);
|
tree.put("root.paired", 1);
|
||||||
|
add_cert->raise(crypto::x509(client.cert));
|
||||||
|
|
||||||
auto it = map_id_sess.find(client.uniqueID);
|
auto it = map_id_sess.find(client.uniqueID);
|
||||||
|
|
||||||
@@ -307,7 +309,7 @@ void not_found(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> resp
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void pair(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
void pair(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response, std::shared_ptr<typename SimpleWeb::ServerBase<T>::Request> request) {
|
||||||
print_req<T>(request);
|
print_req<T>(request);
|
||||||
|
|
||||||
auto args = request->parse_query_string();
|
auto args = request->parse_query_string();
|
||||||
@@ -343,7 +345,7 @@ void pair(std::shared_ptr<typename SimpleWeb::ServerBase<T>::Response> response,
|
|||||||
serverchallengeresp(sess_it->second, tree, args);
|
serverchallengeresp(sess_it->second, tree, args);
|
||||||
}
|
}
|
||||||
else if(it = args.find("clientpairingsecret"); it != std::end(args)) {
|
else if(it = args.find("clientpairingsecret"); it != std::end(args)) {
|
||||||
clientpairingsecret(sess_it->second, tree, args);
|
clientpairingsecret(add_cert, sess_it->second, tree, args);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tree.put("root.<xmlattr>.status_code", 404);
|
tree.put("root.<xmlattr>.status_code", 404);
|
||||||
@@ -627,12 +629,53 @@ void start() {
|
|||||||
conf_intern.pkey = read_file(config::nvhttp.pkey.c_str());
|
conf_intern.pkey = read_file(config::nvhttp.pkey.c_str());
|
||||||
conf_intern.servercert = read_file(config::nvhttp.cert.c_str());
|
conf_intern.servercert = read_file(config::nvhttp.cert.c_str());
|
||||||
|
|
||||||
https_server_t https_server { config::nvhttp.cert, config::nvhttp.pkey };
|
auto ctx = std::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tls);
|
||||||
|
ctx->use_certificate_chain_file(config::nvhttp.cert);
|
||||||
|
ctx->use_private_key_file(config::nvhttp.pkey, boost::asio::ssl::context::pem);
|
||||||
|
for(auto &[_,client] : map_id_client) {
|
||||||
|
ctx->add_certificate_authority(boost::asio::buffer(client.cert));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto add_cert = std::make_shared<safe::queue_t<crypto::x509_t>>();
|
||||||
|
crypto::cert_chain_t cert_chain;
|
||||||
|
|
||||||
|
// When Moonlight has recently paired, the certificate has not yet been added to ctx
|
||||||
|
// Thus it needs to be verified manually
|
||||||
|
ctx->set_verify_callback([&cert_chain, add_cert](int verified, boost::asio::ssl::verify_context &ctx) {
|
||||||
|
util::fail_guard([&]() {
|
||||||
|
char subject_name[256];
|
||||||
|
|
||||||
|
auto x509 = ctx.native_handle();
|
||||||
|
X509_NAME_oneline(X509_get_subject_name(X509_STORE_CTX_get_current_cert(x509)), subject_name, sizeof(subject_name));
|
||||||
|
|
||||||
|
std::cout << subject_name << " -- "sv << (verified ? "verfied"sv : "denied"sv) << std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(verified) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(add_cert->peek()) {
|
||||||
|
cert_chain.add(add_cert->pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto err_str = cert_chain.verify(X509_STORE_CTX_get_current_cert(ctx.native_handle()));
|
||||||
|
if(err_str) {
|
||||||
|
std::cout << "SSL Verification error :: "sv << err_str << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
verified = true;
|
||||||
|
return 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
https_server_t https_server { ctx, boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert | boost::asio::ssl::verify_client_once };
|
||||||
http_server_t http_server;
|
http_server_t http_server;
|
||||||
|
|
||||||
https_server.default_resource = not_found<SimpleWeb::HTTPS>;
|
https_server.default_resource = not_found<SimpleWeb::HTTPS>;
|
||||||
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTPS>;
|
https_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTPS>;
|
||||||
https_server.resource["^/pair$"]["GET"] = pair<SimpleWeb::HTTPS>;
|
https_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SimpleWeb::HTTPS>(add_cert, resp, req); };
|
||||||
https_server.resource["^/applist$"]["GET"] = applist;
|
https_server.resource["^/applist$"]["GET"] = applist;
|
||||||
https_server.resource["^/appasset$"]["GET"] = appasset;
|
https_server.resource["^/appasset$"]["GET"] = appasset;
|
||||||
https_server.resource["^/launch$"]["GET"] = launch;
|
https_server.resource["^/launch$"]["GET"] = launch;
|
||||||
@@ -646,7 +689,7 @@ void start() {
|
|||||||
|
|
||||||
http_server.default_resource = not_found<SimpleWeb::HTTP>;
|
http_server.default_resource = not_found<SimpleWeb::HTTP>;
|
||||||
http_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTP>;
|
http_server.resource["^/serverinfo$"]["GET"] = serverinfo<SimpleWeb::HTTP>;
|
||||||
http_server.resource["^/pair$"]["GET"] = pair<SimpleWeb::HTTP>;
|
http_server.resource["^/pair$"]["GET"] = [&add_cert](auto resp, auto req) { pair<SimpleWeb::HTTP>(add_cert, resp, req); };
|
||||||
http_server.resource["^/pin/([0-9]+)$"]["GET"] = pin<SimpleWeb::HTTP>;
|
http_server.resource["^/pin/([0-9]+)$"]["GET"] = pin<SimpleWeb::HTTP>;
|
||||||
|
|
||||||
http_server.config.reuse_address = true;
|
http_server.config.reuse_address = true;
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#define KITTY_DECL_CONSTR(x)\
|
||||||
|
x(x&&) noexcept = default;\
|
||||||
|
x&operator=(x&&) noexcept = default;\
|
||||||
|
x();
|
||||||
|
|
||||||
#define KITTY_DEFAULT_CONSTR(x)\
|
#define KITTY_DEFAULT_CONSTR(x)\
|
||||||
x(x&&) noexcept = default;\
|
x(x&&) noexcept = default;\
|
||||||
|
|||||||
Reference in New Issue
Block a user