11
11
12
12
// lib includes
13
13
#include < Simple-Web-Server/server_http.hpp>
14
- #include < Simple-Web-Server/server_https.hpp>
15
14
#include < boost/asio/ssl/context.hpp>
16
15
#include < boost/asio/ssl/context_base.hpp>
17
16
#include < boost/property_tree/json_parser.hpp>
21
20
22
21
// local includes
23
22
#include " config.h"
24
- #include " crypto.h"
25
23
#include " display_device.h"
26
24
#include " file_handler.h"
27
25
#include " globals.h"
@@ -45,18 +43,6 @@ namespace nvhttp {
45
43
46
44
crypto::cert_chain_t cert_chain;
47
45
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
-
60
46
class SunshineHTTPSServer : public SimpleWeb ::ServerBase<SunshineHTTPS> {
61
47
public:
62
48
SunshineHTTPSServer (const std::string &certification_file, const std::string &private_key_file):
@@ -146,28 +132,6 @@ namespace nvhttp {
146
132
std::vector<named_cert_t > named_devices;
147
133
};
148
134
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
-
171
135
// uniqueID, session
172
136
std::unordered_map<std::string, pair_session_t > map_id_sess;
173
137
client_t client_root;
@@ -367,12 +331,29 @@ namespace nvhttp {
367
331
return launch_session;
368
332
}
369
333
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
+
370
347
void
371
348
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
+
372
355
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" );
376
357
return ;
377
358
}
378
359
@@ -389,30 +370,17 @@ namespace nvhttp {
389
370
}
390
371
391
372
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;
415
379
380
+ if (!sess.cipher_key ) {
381
+ fail_pair (sess, tree, " Cipher key not set" );
382
+ return ;
383
+ }
416
384
crypto::cipher::ecb_t cipher (*sess.cipher_key , false );
417
385
418
386
std::vector<uint8_t > decrypted;
@@ -446,21 +414,58 @@ namespace nvhttp {
446
414
}
447
415
448
416
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
+
450
454
auto &client = sess.client ;
451
455
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" );
457
458
return ;
458
459
}
459
460
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 () };
462
463
463
464
auto x509 = crypto::x509 (client.cert );
465
+ if (!x509) {
466
+ fail_pair (sess, tree, " Invalid client certificate" );
467
+ return ;
468
+ }
464
469
auto x509_sign = crypto::signature (x509);
465
470
466
471
std::string data;
@@ -473,20 +478,20 @@ namespace nvhttp {
473
478
auto hash = crypto::hash (data);
474
479
475
480
// 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) {
477
484
tree.put (" root.paired" , 1 );
478
485
add_cert->raise (crypto::x509 (client.cert ));
479
486
480
487
// The client is now successfully paired and will be authorized to connect
481
- auto it = map_id_sess.find (client.uniqueID );
482
488
add_authorized_client (client.name , std::move (client.cert ));
483
- map_id_sess.erase (it);
484
489
}
485
490
else {
486
- map_id_sess.erase (client.uniqueID );
487
491
tree.put (" root.paired" , 0 );
488
492
}
489
493
494
+ remove_session (sess);
490
495
tree.put (" root.<xmlattr>.status_code" , 200 );
491
496
}
492
497
@@ -568,7 +573,6 @@ namespace nvhttp {
568
573
}
569
574
570
575
auto uniqID { get_arg (args, " uniqueid" ) };
571
- auto sess_it = map_id_sess.find (uniqID);
572
576
573
577
args_t ::const_iterator it;
574
578
if (it = args.find (" phrase" ); it != std::end (args)) {
@@ -603,16 +607,29 @@ namespace nvhttp {
603
607
else if (it->second == " pairchallenge" sv) {
604
608
tree.put (" root.paired" , 1 );
605
609
tree.put (" root.<xmlattr>.status_code" , 200 );
610
+ return ;
606
611
}
607
612
}
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);
610
625
}
611
626
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);
613
629
}
614
630
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);
616
633
}
617
634
else {
618
635
tree.put (" root.<xmlattr>.status_code" , 404 );
@@ -1030,6 +1047,12 @@ namespace nvhttp {
1030
1047
response->close_connection_after_response = true ;
1031
1048
}
1032
1049
1050
+ void
1051
+ setup (const std::string &pkey, const std::string &cert) {
1052
+ conf_intern.pkey = pkey;
1053
+ conf_intern.servercert = cert;
1054
+ }
1055
+
1033
1056
void
1034
1057
start () {
1035
1058
auto shutdown_event = mail::man->event <bool >(mail::shutdown);
@@ -1044,8 +1067,9 @@ namespace nvhttp {
1044
1067
load_state ();
1045
1068
}
1046
1069
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);
1049
1073
1050
1074
auto add_cert = std::make_shared<safe::queue_t <crypto::x509_t >>(30 );
1051
1075
0 commit comments