Skip to content

Commit

Permalink
partially fixed digest auth (websockets don't work), explicitly inclu…
Browse files Browse the repository at this point in the history
…de needed modules from boost
  • Loading branch information
catink123 committed Jan 28, 2024
1 parent 03b6285 commit afed5f1
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 100 deletions.
11 changes: 9 additions & 2 deletions src/arduino_messenger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@
#define ARDUINO_MESSENGER_HPP

#include "common.hpp"

#include <queue>
#include <thread>

#include <boost/asio/serial_port.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/post.hpp>

#include <boost/beast/core/bind_handler.hpp>

#include "json_message.hpp"
#include <queue>
#include <thread>

class arduino_messenger : public std::enable_shared_from_this<arduino_messenger> {
static constexpr std::size_t MAX_MESSAGE_LENGTH = 100;
Expand Down
49 changes: 39 additions & 10 deletions src/auth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@ std::string to_hex(const std::string& input, bool uppercase) {
return output;
}

std::string md5_hash(const std::string& input) {
std::string sha256_hash(const std::string& input) {
std::string output;

CryptoPP::Weak::MD5 hash;
CryptoPP::SHA256 hash;

CryptoPP::StringSource(input, true,
new CryptoPP::HashFilter(hash,
Expand Down Expand Up @@ -169,23 +169,39 @@ bool digest_auth::check_password(
std::string_view password,
std::string_view method,
std::string_view nonce,
std::string_view opaque,
const auth_table_t& auth_table
) const {
if (auth_table.find(username) == auth_table.end()) {
if (
// there's no user with the specified name
auth_table.find(username) == auth_table.end() ||
// no qop parameter
!qop ||
// no opaque parameter
!this->opaque ||
// specified opaque isn't the same as stored opaque
this->opaque != opaque
) {
return false;
}

const auto& data = auth_table.at(username);

std::string A1 =
username + ':' + realm + ':' + std::string(password);
std::string A1_hash = md5_hash(A1);
std::string A1_hash = sha256_hash(A1);

std::string A2 = std::string(method) + ':' + uri;
std::string A2_hash = md5_hash(A2);
std::string A2_hash = sha256_hash(A2);

std::string A1_nonce_A2 = A1_hash + ':' + std::string(nonce) + ':' + A2_hash;
std::string KD = md5_hash(A1_nonce_A2);
std::string KD_unhashed =
A1_hash + ':' +
std::string(nonce) + ':' +
nc.value() + ':' +
cnonce.value() + ':' +
qop.value() + ':' +
A2_hash;
std::string KD = sha256_hash(KD_unhashed);

return response == KD;
}
Expand Down Expand Up @@ -233,15 +249,28 @@ std::optional<digest_auth> parse_digest_auth_field(
}
}

std::string generate_nonce() {
std::string generate_base64_str(unsigned int size) {
std::string output;

CryptoPP::AutoSeededRandomPool rng;
CryptoPP::RandomNumberSource(rng, NONCE_SIZE, true,
CryptoPP::RandomNumberSource _(rng, size, true,
new CryptoPP::Base64URLEncoder(
new CryptoPP::StringSink(output)
)
);

return output;
}
}

std::string generate_digest_response(
const std::string& nonce,
const std::string& opaque
) {
return
R"(Digest )"
R"(realm="viewcontrol", )"
R"(nonce=")" + nonce + R"(", )"
R"(algorithm=SHA-256, )"
R"(qop="auth", )"
R"(opaque=")" + opaque + '"';
}
69 changes: 21 additions & 48 deletions src/auth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,22 @@
#define AUTH_HPP

#include "common.hpp"

#include <optional>
#include <array>
#include <utility>
#include <vector>
#include <filesystem>
#include <fstream>
#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1
#include <cryptopp/md5.h>
#include <regex>

#include <boost/beast/http/verb.hpp>
#include <boost/beast/http/message.hpp>

#include <cryptopp/sha.h>
#include <cryptopp/base64.h>
#include <cryptopp/osrng.h>
#include <cryptopp/hex.h>
#include <regex>

namespace fs = std::filesystem;

Expand Down Expand Up @@ -51,10 +55,11 @@ std::optional<std::unordered_map<std::string, auth_data>>
open_auth_table_from_file(fs::path file_path);

const std::size_t NONCE_SIZE = 32;
std::string generate_nonce();
const std::size_t OPAQUE_SIZE = 32;
std::string generate_base64_str(unsigned int size);

std::string to_hex(const std::string& input, bool uppercase = false);
std::string md5_hash(const std::string& input);
std::string sha256_hash(const std::string& input);

struct digest_auth {
std::string username;
Expand All @@ -72,9 +77,10 @@ struct digest_auth {

// MD5 hashing and no qop is assumed
bool check_password(
std::string_view password,
std::string_view password,
std::string_view method,
std::string_view nonce,
std::string_view nonce,
std::string_view opaque,
const auth_table_t& auth_table
) const;
};
Expand All @@ -89,7 +95,8 @@ template <class Body, class Allocator>
std::optional<AuthorizationType> get_auth(
const http::request<Body, http::basic_fields<Allocator>>& req,
const std::unordered_map<std::string, auth_data>& auth_table,
std::string_view nonce
const std::string& nonce,
const std::string& opaque
) {
if (req.find(http::field::authorization) == req.end()) {
return std::nullopt;
Expand All @@ -110,51 +117,17 @@ std::optional<AuthorizationType> get_auth(
const auth_data& stored_auth_data = auth_table.at(digest.username);
const std::string method = http_method_to_str(req.base().method());

if (digest.check_password(stored_auth_data.password, method, nonce, auth_table)) {
if (digest.check_password(stored_auth_data.password, method, nonce, opaque, auth_table)) {
return stored_auth_data.permissions;
}
else {
return std::nullopt;
}

//// get the authorization field and separate the base64 encoded user-pass combination
//const std::string authorization = req.at(http::field::authorization);
//const std::string user_pass = authorization.substr(authorization.find(' ') + 1);

//// decode the base64 combination
//const std::size_t decoded_size = base64::decoded_size(user_pass.size());
////char* user_pass_decoded = new char[decoded_size];
//std::vector<char> user_pass_decoded(decoded_size, '\0');

//auto decode_result =
// beast::detail::base64::decode(
// reinterpret_cast<void*>(&user_pass_decoded[0]),
// user_pass.c_str(),
// user_pass.size()
// );

//const std::string user_pass_str(user_pass_decoded, decode_result.first);

////delete[] user_pass_decoded;

//// separate the user-id and password (if the user exists in the auth_table)
//const std::size_t user_pass_delimeter_loc = user_pass_str.find(':');
//const std::string user_id = user_pass_str.substr(0, user_pass_delimeter_loc);

//if (auth_table.find(user_id) == auth_table.end()) {
// return std::nullopt;
//}

//const std::string password = user_pass_str.substr(user_pass_delimeter_loc + 1);

//// compare the sent password with the stored hash to validate
//const auth_data& data = auth_table.at(user_id);
//if (bcrypt::validatePassword(password, data.password)) {
// return data.permissions;
//}
//else {
// return std::nullopt;
//}
}

std::string generate_digest_response(
const std::string& nonce,
const std::string& opaque
);

#endif
16 changes: 9 additions & 7 deletions src/common.hpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
#ifndef COMMON_HPP
#define COMMON_HPP

#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/strand.hpp>
#include <boost/config.hpp>
namespace boost {
namespace asio {}
namespace beast {
namespace http {}
namespace net = ::boost::asio;
namespace websocket {}
}
}

#include <iostream>
#include "version.hpp"

namespace beast = boost::beast;
namespace http = beast::http;
namespace net = boost::beast::net;
using tcp = net::ip::tcp;
namespace websocket = beast::websocket;

#endif
8 changes: 7 additions & 1 deletion src/common_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@

#include <memory>
#include <vector>
#include "websocket_session.hpp"

#include "common.hpp"

#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/io_context.hpp>

#include "websocket_session.hpp"
#include "arduino_messenger.hpp"

class common_state : public std::enable_shared_from_this<common_state> {
Expand Down
7 changes: 5 additions & 2 deletions src/http_listener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
http_listener::http_listener(
net::io_context& ioc,
tcp::endpoint endpoint,
const std::shared_ptr<const std::string>& doc_root,
std::shared_ptr<const std::string> doc_root,
std::shared_ptr<common_state> comstate,
std::shared_ptr<arduino_messenger> arduino_connection,
std::shared_ptr<auth_table_t> auth_table
Expand Down Expand Up @@ -41,6 +41,8 @@ http_listener::http_listener(
std::cerr << "Couldn't start listening: " << ec.message() << std::endl;
return;
}

opaque = make_shared<std::string>(generate_base64_str(OPAQUE_SIZE));
}

void http_listener::run() {
Expand Down Expand Up @@ -68,7 +70,8 @@ void http_listener::on_accept(beast::error_code ec, tcp::socket socket) {
doc_root,
comstate,
arduino_connection,
auth_table
auth_table,
opaque
)->run();

do_accept();
Expand Down
18 changes: 15 additions & 3 deletions src/http_listener.hpp
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
#ifndef HTTP_LISTENER_HPP
#define HTTP_LISTENER_HPP

#include <nlohmann/json.hpp>
#include "common.hpp"

#include <memory>
#include <string>
#include "common.hpp"

#include <boost/asio/strand.hpp>

#include <boost/beast/core/error.hpp>
#include <boost/beast/core/bind_handler.hpp>

#include <nlohmann/json.hpp>

#include "http_session.hpp"
#include "common_state.hpp"

using tcp = net::ip::tcp;

class http_listener : public std::enable_shared_from_this<http_listener> {
net::io_context& ioc;
tcp::acceptor acceptor;
std::shared_ptr<const std::string> doc_root;
std::shared_ptr<common_state> comstate;
std::shared_ptr<arduino_messenger> arduino_connection;
std::shared_ptr<auth_table_t> auth_table;

std::shared_ptr<std::string> opaque;

public:
http_listener(
net::io_context& ioc,
tcp::endpoint endpoint,
const std::shared_ptr<const std::string>& doc_root,
std::shared_ptr<const std::string> doc_root,
std::shared_ptr<common_state> comstate,
std::shared_ptr<arduino_messenger> arduino_connection,
std::shared_ptr<auth_table_t> auth_table
Expand Down

0 comments on commit afed5f1

Please sign in to comment.