Skip to content

Commit 89f097a

Browse files
ABeltramoReenigneArchercgutman
authored
Merge commit from fork
Co-authored-by: ReenigneArcher <[email protected]> Co-authored-by: Cameron Gutman <[email protected]>
1 parent 80fa04c commit 89f097a

File tree

6 files changed

+484
-81
lines changed

6 files changed

+484
-81
lines changed

src/nvhttp.cpp

Lines changed: 105 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
// lib includes
1313
#include <Simple-Web-Server/server_http.hpp>
14-
#include <Simple-Web-Server/server_https.hpp>
1514
#include <boost/asio/ssl/context.hpp>
1615
#include <boost/asio/ssl/context_base.hpp>
1716
#include <boost/property_tree/json_parser.hpp>
@@ -21,7 +20,6 @@
2120

2221
// local includes
2322
#include "config.h"
24-
#include "crypto.h"
2523
#include "display_device.h"
2624
#include "file_handler.h"
2725
#include "globals.h"
@@ -45,18 +43,6 @@ namespace nvhttp {
4543

4644
crypto::cert_chain_t cert_chain;
4745

48-
class SunshineHTTPS: public SimpleWeb::HTTPS {
49-
public:
50-
SunshineHTTPS(boost::asio::io_context &io_context, boost::asio::ssl::context &ctx):
51-
SimpleWeb::HTTPS(io_context, ctx) {}
52-
53-
virtual ~SunshineHTTPS() {
54-
// Gracefully shutdown the TLS connection
55-
SimpleWeb::error_code ec;
56-
shutdown(ec);
57-
}
58-
};
59-
6046
class SunshineHTTPSServer: public SimpleWeb::ServerBase<SunshineHTTPS> {
6147
public:
6248
SunshineHTTPSServer(const std::string &certification_file, const std::string &private_key_file):
@@ -146,28 +132,6 @@ namespace nvhttp {
146132
std::vector<named_cert_t> named_devices;
147133
};
148134

149-
struct pair_session_t {
150-
struct {
151-
std::string uniqueID;
152-
std::string cert;
153-
std::string name;
154-
} client;
155-
156-
std::unique_ptr<crypto::aes_t> cipher_key;
157-
std::vector<uint8_t> clienthash;
158-
159-
std::string serversecret;
160-
std::string serverchallenge;
161-
162-
struct {
163-
util::Either<
164-
std::shared_ptr<typename SimpleWeb::ServerBase<SimpleWeb::HTTP>::Response>,
165-
std::shared_ptr<typename SimpleWeb::ServerBase<SunshineHTTPS>::Response>>
166-
response;
167-
std::string salt;
168-
} async_insert_pin;
169-
};
170-
171135
// uniqueID, session
172136
std::unordered_map<std::string, pair_session_t> map_id_sess;
173137
client_t client_root;
@@ -367,12 +331,29 @@ namespace nvhttp {
367331
return launch_session;
368332
}
369333

334+
void
335+
remove_session(const pair_session_t &sess) {
336+
map_id_sess.erase(sess.client.uniqueID);
337+
}
338+
339+
void
340+
fail_pair(pair_session_t &sess, pt::ptree &tree, const std::string status_msg) {
341+
tree.put("root.paired", 0);
342+
tree.put("root.<xmlattr>.status_code", 400);
343+
tree.put("root.<xmlattr>.status_message", status_msg);
344+
remove_session(sess); // Security measure, delete the session when something went wrong and force a re-pair
345+
}
346+
370347
void
371348
getservercert(pair_session_t &sess, pt::ptree &tree, const std::string &pin) {
349+
if (sess.last_phase != PAIR_PHASE::NONE) {
350+
fail_pair(sess, tree, "Out of order call to getservercert");
351+
return;
352+
}
353+
sess.last_phase = PAIR_PHASE::GETSERVERCERT;
354+
372355
if (sess.async_insert_pin.salt.size() < 32) {
373-
tree.put("root.paired", 0);
374-
tree.put("root.<xmlattr>.status_code", 400);
375-
tree.put("root.<xmlattr>.status_message", "Salt too short");
356+
fail_pair(sess, tree, "Salt too short");
376357
return;
377358
}
378359

@@ -389,30 +370,17 @@ namespace nvhttp {
389370
}
390371

391372
void
392-
serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
393-
auto encrypted_response = util::from_hex_vec(get_arg(args, "serverchallengeresp"), true);
394-
395-
std::vector<uint8_t> decrypted;
396-
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
397-
398-
cipher.decrypt(encrypted_response, decrypted);
399-
400-
sess.clienthash = std::move(decrypted);
401-
402-
auto serversecret = sess.serversecret;
403-
auto sign = crypto::sign256(crypto::pkey(conf_intern.pkey), serversecret);
404-
405-
serversecret.insert(std::end(serversecret), std::begin(sign), std::end(sign));
406-
407-
tree.put("root.pairingsecret", util::hex_vec(serversecret, true));
408-
tree.put("root.paired", 1);
409-
tree.put("root.<xmlattr>.status_code", 200);
410-
}
411-
412-
void
413-
clientchallenge(pair_session_t &sess, pt::ptree &tree, const args_t &args) {
414-
auto challenge = util::from_hex_vec(get_arg(args, "clientchallenge"), true);
373+
clientchallenge(pair_session_t &sess, pt::ptree &tree, const std::string &challenge) {
374+
if (sess.last_phase != PAIR_PHASE::GETSERVERCERT) {
375+
fail_pair(sess, tree, "Out of order call to clientchallenge");
376+
return;
377+
}
378+
sess.last_phase = PAIR_PHASE::CLIENTCHALLENGE;
415379

380+
if (!sess.cipher_key) {
381+
fail_pair(sess, tree, "Cipher key not set");
382+
return;
383+
}
416384
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
417385

418386
std::vector<uint8_t> decrypted;
@@ -446,21 +414,58 @@ namespace nvhttp {
446414
}
447415

448416
void
449-
clientpairingsecret(std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, pair_session_t &sess, pt::ptree &tree, const args_t &args) {
417+
serverchallengeresp(pair_session_t &sess, pt::ptree &tree, const std::string &encrypted_response) {
418+
if (sess.last_phase != PAIR_PHASE::CLIENTCHALLENGE) {
419+
fail_pair(sess, tree, "Out of order call to serverchallengeresp");
420+
return;
421+
}
422+
sess.last_phase = PAIR_PHASE::SERVERCHALLENGERESP;
423+
424+
if (!sess.cipher_key || sess.serversecret.empty()) {
425+
fail_pair(sess, tree, "Cipher key or serversecret not set");
426+
return;
427+
}
428+
429+
std::vector<uint8_t> decrypted;
430+
crypto::cipher::ecb_t cipher(*sess.cipher_key, false);
431+
432+
cipher.decrypt(encrypted_response, decrypted);
433+
434+
sess.clienthash = std::move(decrypted);
435+
436+
auto serversecret = sess.serversecret;
437+
auto sign = crypto::sign256(crypto::pkey(conf_intern.pkey), serversecret);
438+
439+
serversecret.insert(std::end(serversecret), std::begin(sign), std::end(sign));
440+
441+
tree.put("root.pairingsecret", util::hex_vec(serversecret, true));
442+
tree.put("root.paired", 1);
443+
tree.put("root.<xmlattr>.status_code", 200);
444+
}
445+
446+
void
447+
clientpairingsecret(pair_session_t &sess, std::shared_ptr<safe::queue_t<crypto::x509_t>> &add_cert, pt::ptree &tree, const std::string &client_pairing_secret) {
448+
if (sess.last_phase != PAIR_PHASE::SERVERCHALLENGERESP) {
449+
fail_pair(sess, tree, "Out of order call to clientpairingsecret");
450+
return;
451+
}
452+
sess.last_phase = PAIR_PHASE::CLIENTPAIRINGSECRET;
453+
450454
auto &client = sess.client;
451455

452-
auto pairingsecret = util::from_hex_vec(get_arg(args, "clientpairingsecret"), true);
453-
if (pairingsecret.size() <= 16) {
454-
tree.put("root.paired", 0);
455-
tree.put("root.<xmlattr>.status_code", 400);
456-
tree.put("root.<xmlattr>.status_message", "Clientpairingsecret too short");
456+
if (client_pairing_secret.size() <= 16) {
457+
fail_pair(sess, tree, "Client pairing secret too short");
457458
return;
458459
}
459460

460-
std::string_view secret { pairingsecret.data(), 16 };
461-
std::string_view sign { pairingsecret.data() + secret.size(), pairingsecret.size() - secret.size() };
461+
std::string_view secret { client_pairing_secret.data(), 16 };
462+
std::string_view sign { client_pairing_secret.data() + secret.size(), client_pairing_secret.size() - secret.size() };
462463

463464
auto x509 = crypto::x509(client.cert);
465+
if (!x509) {
466+
fail_pair(sess, tree, "Invalid client certificate");
467+
return;
468+
}
464469
auto x509_sign = crypto::signature(x509);
465470

466471
std::string data;
@@ -473,20 +478,20 @@ namespace nvhttp {
473478
auto hash = crypto::hash(data);
474479

475480
// if hash not correct, probably MITM
476-
if (!std::memcmp(hash.data(), sess.clienthash.data(), hash.size()) && crypto::verify256(crypto::x509(client.cert), secret, sign)) {
481+
bool same_hash = hash.size() == sess.clienthash.size() && std::equal(hash.begin(), hash.end(), sess.clienthash.begin());
482+
auto verify = crypto::verify256(crypto::x509(client.cert), secret, sign);
483+
if (same_hash && verify) {
477484
tree.put("root.paired", 1);
478485
add_cert->raise(crypto::x509(client.cert));
479486

480487
// The client is now successfully paired and will be authorized to connect
481-
auto it = map_id_sess.find(client.uniqueID);
482488
add_authorized_client(client.name, std::move(client.cert));
483-
map_id_sess.erase(it);
484489
}
485490
else {
486-
map_id_sess.erase(client.uniqueID);
487491
tree.put("root.paired", 0);
488492
}
489493

494+
remove_session(sess);
490495
tree.put("root.<xmlattr>.status_code", 200);
491496
}
492497

@@ -568,7 +573,6 @@ namespace nvhttp {
568573
}
569574

570575
auto uniqID { get_arg(args, "uniqueid") };
571-
auto sess_it = map_id_sess.find(uniqID);
572576

573577
args_t::const_iterator it;
574578
if (it = args.find("phrase"); it != std::end(args)) {
@@ -603,16 +607,29 @@ namespace nvhttp {
603607
else if (it->second == "pairchallenge"sv) {
604608
tree.put("root.paired", 1);
605609
tree.put("root.<xmlattr>.status_code", 200);
610+
return;
606611
}
607612
}
608-
else if (it = args.find("clientchallenge"); it != std::end(args)) {
609-
clientchallenge(sess_it->second, tree, args);
613+
614+
auto sess_it = map_id_sess.find(uniqID);
615+
if (sess_it == std::end(map_id_sess)) {
616+
tree.put("root.<xmlattr>.status_code", 400);
617+
tree.put("root.<xmlattr>.status_message", "Invalid uniqueid");
618+
619+
return;
620+
}
621+
622+
if (it = args.find("clientchallenge"); it != std::end(args)) {
623+
auto challenge = util::from_hex_vec(it->second, true);
624+
clientchallenge(sess_it->second, tree, challenge);
610625
}
611626
else if (it = args.find("serverchallengeresp"); it != std::end(args)) {
612-
serverchallengeresp(sess_it->second, tree, args);
627+
auto encrypted_response = util::from_hex_vec(it->second, true);
628+
serverchallengeresp(sess_it->second, tree, encrypted_response);
613629
}
614630
else if (it = args.find("clientpairingsecret"); it != std::end(args)) {
615-
clientpairingsecret(add_cert, sess_it->second, tree, args);
631+
auto pairingsecret = util::from_hex_vec(it->second, true);
632+
clientpairingsecret(sess_it->second, add_cert, tree, pairingsecret);
616633
}
617634
else {
618635
tree.put("root.<xmlattr>.status_code", 404);
@@ -1030,6 +1047,12 @@ namespace nvhttp {
10301047
response->close_connection_after_response = true;
10311048
}
10321049

1050+
void
1051+
setup(const std::string &pkey, const std::string &cert) {
1052+
conf_intern.pkey = pkey;
1053+
conf_intern.servercert = cert;
1054+
}
1055+
10331056
void
10341057
start() {
10351058
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
@@ -1044,8 +1067,9 @@ namespace nvhttp {
10441067
load_state();
10451068
}
10461069

1047-
conf_intern.pkey = file_handler::read_file(config::nvhttp.pkey.c_str());
1048-
conf_intern.servercert = file_handler::read_file(config::nvhttp.cert.c_str());
1070+
auto pkey = file_handler::read_file(config::nvhttp.pkey.c_str());
1071+
auto cert = file_handler::read_file(config::nvhttp.cert.c_str());
1072+
setup(pkey, cert);
10491073

10501074
auto add_cert = std::make_shared<safe::queue_t<crypto::x509_t>>(30);
10511075

0 commit comments

Comments
 (0)