all Ref to support uprefable types
This commit is contained in:
parent
f5b49ebf66
commit
5801a5404a
@ -47,7 +47,7 @@ add_executable(xbot
|
|||||||
client.cpp
|
client.cpp
|
||||||
connection.cpp
|
connection.cpp
|
||||||
ircmsg.cpp
|
ircmsg.cpp
|
||||||
openssl_errors.cpp
|
openssl_utils.cpp
|
||||||
registration.cpp
|
registration.cpp
|
||||||
sasl_mechanism.cpp
|
sasl_mechanism.cpp
|
||||||
settings.cpp
|
settings.cpp
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "challenge.hpp"
|
#include "challenge.hpp"
|
||||||
|
|
||||||
#include "openssl_errors.hpp"
|
#include "openssl_utils.hpp"
|
||||||
|
|
||||||
#include <mybase64.hpp>
|
#include <mybase64.hpp>
|
||||||
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
|
||||||
@ -16,13 +17,6 @@ Challenge::Challenge(EVP_PKEY_Ref key, Connection & connection)
|
|||||||
, connection_{connection}
|
, connection_{connection}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
auto Challenge::stop() -> void
|
|
||||||
{
|
|
||||||
slot_.disconnect();
|
|
||||||
buffer_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
default: break;
|
default: break;
|
||||||
@ -30,42 +24,56 @@ auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
|||||||
buffer_ += msg.args[1];
|
buffer_ += msg.args[1];
|
||||||
break;
|
break;
|
||||||
case IrcCommand::ERR_NOOPERHOST:
|
case IrcCommand::ERR_NOOPERHOST:
|
||||||
|
slot_.disconnect();
|
||||||
BOOST_LOG_TRIVIAL(error) << "Challenge: No oper host";
|
BOOST_LOG_TRIVIAL(error) << "Challenge: No oper host";
|
||||||
stop();
|
|
||||||
break;
|
break;
|
||||||
case IrcCommand::RPL_YOUREOPER:
|
case IrcCommand::RPL_YOUREOPER:
|
||||||
|
slot_.disconnect();
|
||||||
BOOST_LOG_TRIVIAL(error) << "Challenge: Already oper";
|
BOOST_LOG_TRIVIAL(error) << "Challenge: Already oper";
|
||||||
stop();
|
|
||||||
break;
|
break;
|
||||||
case IrcCommand::RPL_ENDOFRSACHALLENGE2:
|
case IrcCommand::RPL_ENDOFRSACHALLENGE2:
|
||||||
{
|
|
||||||
slot_.disconnect();
|
slot_.disconnect();
|
||||||
|
finish_challenge();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Challenge::finish_challenge() -> void
|
||||||
|
{
|
||||||
EVP_PKEY_CTX_Ref ctx;
|
EVP_PKEY_CTX_Ref ctx;
|
||||||
unsigned int digestlen = EVP_MAX_MD_SIZE;
|
unsigned int digestlen = EVP_MAX_MD_SIZE;
|
||||||
unsigned char digest[EVP_MAX_MD_SIZE];
|
unsigned char digest[EVP_MAX_MD_SIZE];
|
||||||
size_t len = mybase64::decoded_size(buffer_.size());
|
size_t len = mybase64::decoded_size(buffer_.size());
|
||||||
std::vector<unsigned char> ciphertext(len, 0);
|
std::vector<unsigned char> ciphertext(len, 0);
|
||||||
|
|
||||||
if (not mybase64::decode(buffer_, reinterpret_cast<char*>(ciphertext.data()), &len)) goto error;
|
if (not mybase64::decode(buffer_, reinterpret_cast<char*>(ciphertext.data()), &len))
|
||||||
|
return log_openssl_errors("Challenge base64::decode: ");
|
||||||
ciphertext.resize(len);
|
ciphertext.resize(len);
|
||||||
|
|
||||||
// Setup decryption context
|
// Setup decryption context
|
||||||
ctx.reset(EVP_PKEY_CTX_new(key_.get(), nullptr));
|
ctx.reset(EVP_PKEY_CTX_new(key_.get(), nullptr));
|
||||||
if (ctx.get() == nullptr) goto error;
|
if (ctx.get() == nullptr)
|
||||||
if (1 != EVP_PKEY_decrypt_init(ctx.get())) goto error;
|
return log_openssl_errors("Challenge EVP_PKEY_CTX_new: ");
|
||||||
if (0 >= EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING)) goto error;
|
|
||||||
|
if (1 != EVP_PKEY_decrypt_init(ctx.get()))
|
||||||
|
return log_openssl_errors("Challenge EVP_PKEY_decrypt_init: ");
|
||||||
|
|
||||||
|
if (0 >= EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING))
|
||||||
|
return log_openssl_errors("Challenge EVP_PKEY_CTX_set_rsa_padding: ");
|
||||||
|
|
||||||
// Determine output size
|
// Determine output size
|
||||||
if (1 != EVP_PKEY_decrypt(ctx.get(), nullptr, &len, ciphertext.data(), ciphertext.size())) goto error;
|
if (1 != EVP_PKEY_decrypt(ctx.get(), nullptr, &len, ciphertext.data(), ciphertext.size()))
|
||||||
|
return log_openssl_errors("Challenge EVP_PKEY_decrypt (size): ");
|
||||||
buffer_.resize(len);
|
buffer_.resize(len);
|
||||||
|
|
||||||
// Decrypt ciphertext
|
// Decrypt ciphertext
|
||||||
if (1 != EVP_PKEY_decrypt(ctx.get(), reinterpret_cast<unsigned char*>(buffer_.data()), &len, ciphertext.data(), ciphertext.size())) goto error;
|
if (1 != EVP_PKEY_decrypt(ctx.get(), reinterpret_cast<unsigned char*>(buffer_.data()), &len, ciphertext.data(), ciphertext.size()))
|
||||||
|
return log_openssl_errors("Challenge EVP_PKEY_decrypt: ");
|
||||||
buffer_.resize(len);
|
buffer_.resize(len);
|
||||||
|
|
||||||
// Hash the decrypted message
|
// Hash the decrypted message
|
||||||
if (1 != EVP_Digest(buffer_.data(), buffer_.size(), digest, &digestlen, EVP_sha1(), nullptr)) goto error;
|
if (1 != EVP_Digest(buffer_.data(), buffer_.size(), digest, &digestlen, EVP_sha1(), nullptr))
|
||||||
|
return log_openssl_errors("Challenge EVP_Digest: ");
|
||||||
|
|
||||||
// Construct reply as '+' and base64 encoded digest
|
// Construct reply as '+' and base64 encoded digest
|
||||||
buffer_.resize(mybase64::encoded_size(digestlen) + 1);
|
buffer_.resize(mybase64::encoded_size(digestlen) + 1);
|
||||||
@ -73,13 +81,8 @@ auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
|
|||||||
mybase64::encode(std::string_view{(char*)digest, digestlen}, buffer_.data() + 1);
|
mybase64::encode(std::string_view{(char*)digest, digestlen}, buffer_.data() + 1);
|
||||||
|
|
||||||
connection_.send_challenge(buffer_);
|
connection_.send_challenge(buffer_);
|
||||||
return;
|
connection_.send_ping("oper_up mitigation");
|
||||||
|
}
|
||||||
error:
|
|
||||||
log_openssl_errors("Challenge: ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Challenge::start(Connection &connection, const std::string_view user, EVP_PKEY_Ref ref) -> std::shared_ptr<Challenge>
|
auto Challenge::start(Connection &connection, const std::string_view user, EVP_PKEY_Ref ref) -> std::shared_ptr<Challenge>
|
||||||
{
|
{
|
||||||
|
@ -16,9 +16,9 @@ class Challenge : std::enable_shared_from_this<Challenge>
|
|||||||
std::string buffer_;
|
std::string buffer_;
|
||||||
|
|
||||||
auto on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void;
|
auto on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void;
|
||||||
|
auto finish_challenge() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Challenge(EVP_PKEY_Ref, Connection &);
|
Challenge(EVP_PKEY_Ref, Connection &);
|
||||||
auto stop() -> void;
|
|
||||||
static auto start(Connection &, std::string_view user, EVP_PKEY_Ref) -> std::shared_ptr<Challenge>;
|
static auto start(Connection &, std::string_view user, EVP_PKEY_Ref) -> std::shared_ptr<Challenge>;
|
||||||
};
|
};
|
||||||
|
76
main.cpp
76
main.cpp
@ -1,9 +1,8 @@
|
|||||||
#include "bot.hpp"
|
#include "bot.hpp"
|
||||||
#include "c_callback.hpp"
|
|
||||||
#include "challenge.hpp"
|
#include "challenge.hpp"
|
||||||
#include "client.hpp"
|
#include "client.hpp"
|
||||||
#include "connection.hpp"
|
#include "connection.hpp"
|
||||||
#include "openssl_errors.hpp"
|
#include "openssl_utils.hpp"
|
||||||
#include "registration.hpp"
|
#include "registration.hpp"
|
||||||
#include "settings.hpp"
|
#include "settings.hpp"
|
||||||
#include "irc_coroutine.hpp"
|
#include "irc_coroutine.hpp"
|
||||||
@ -13,58 +12,12 @@
|
|||||||
|
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
static auto cert_from_file(const std::string &filename) -> X509_Ref
|
|
||||||
{
|
|
||||||
X509_Ref cert;
|
|
||||||
if (const auto fp = fopen(filename.c_str(), "r"))
|
|
||||||
{
|
|
||||||
cert.reset(PEM_read_X509(fp, nullptr, nullptr, nullptr));
|
|
||||||
if (cert.get() == nullptr)
|
|
||||||
{
|
|
||||||
log_openssl_errors("Reading certificate: "sv);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto err = strerror(errno);
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Opening certificate: " << err;
|
|
||||||
}
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto key_from_file(const std::string &filename, const std::string_view password) -> EVP_PKEY_Ref
|
|
||||||
{
|
|
||||||
EVP_PKEY_Ref key;
|
|
||||||
if (const auto fp = fopen(filename.c_str(), "r"))
|
|
||||||
{
|
|
||||||
auto cb = [password](char * const buf, int const size, int) -> int {
|
|
||||||
if (size < password.size()) { return -1; }
|
|
||||||
std::copy(password.begin(), password.end(), buf);
|
|
||||||
return password.size();
|
|
||||||
};
|
|
||||||
|
|
||||||
key.reset(PEM_read_PrivateKey(fp, nullptr, CCallback<decltype(cb)>::invoke, &cb));
|
|
||||||
if (key.get() == nullptr)
|
|
||||||
{
|
|
||||||
log_openssl_errors("Reading private key: "sv);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto err = strerror(errno);
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Opening private key: " << err;
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto start(boost::asio::io_context &io, const Settings &settings) -> void
|
static auto start(boost::asio::io_context &io, const Settings &settings) -> void
|
||||||
{
|
{
|
||||||
@ -86,30 +39,13 @@ static auto start(boost::asio::io_context &io, const Settings &settings) -> void
|
|||||||
|
|
||||||
const auto bot = Bot::start(client);
|
const auto bot = Bot::start(client);
|
||||||
|
|
||||||
/*
|
if (not settings.challenge_username.empty() && not settings.challenge_key_file.empty()) {
|
||||||
connection->sig_snote.connect([](auto &match) {
|
if (auto key = key_from_file(settings.challenge_key_file, settings.challenge_key_password)) {
|
||||||
std::cout << "SNOTE " << static_cast<int>(match.get_tag()) << std::endl;
|
client->sig_registered.connect([&settings, connection, key = std::move(key)]() {
|
||||||
for (auto c : match.get_results())
|
Challenge::start(*connection, settings.challenge_username, key);
|
||||||
{
|
|
||||||
std::cout << " " << std::string_view{c.first, c.second} << std::endl;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
client->sig_registered.connect([&settings, connection, client]() {
|
|
||||||
connection->send_join("##glguy"sv);
|
|
||||||
connection->send_whois(client->get_my_nick());
|
|
||||||
|
|
||||||
if (not settings.challenge_username.empty() &&
|
|
||||||
not settings.challenge_key_file.empty()) {
|
|
||||||
auto key = key_from_file(settings.challenge_key_file, settings.challenge_key_password);
|
|
||||||
Challenge::start(*connection, settings.challenge_username, std::move(key));
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
client->sig_chat.connect([client, connection](const Chat &chat){
|
|
||||||
if (chat.source.starts_with("glguy!") && client->is_my_nick(chat.target)) {
|
|
||||||
connection->send_notice("glguy", chat.message);
|
|
||||||
}});
|
|
||||||
|
|
||||||
connection->sig_disconnect.connect(
|
connection->sig_disconnect.connect(
|
||||||
[&io, &settings, client, bot]() {
|
[&io, &settings, client, bot]() {
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
#include "openssl_errors.hpp"
|
|
||||||
|
|
||||||
#include "c_callback.hpp"
|
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
|
||||||
|
|
||||||
auto log_openssl_errors(const std::string_view prefix) -> void
|
|
||||||
{
|
|
||||||
auto err_cb = [prefix](const char *str, size_t len) -> int {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << prefix << std::string_view{str, len};
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
ERR_print_errors_cb(CCallback<decltype(err_cb)>::invoke, &err_cb);
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <openssl/err.h>
|
|
||||||
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
auto log_openssl_errors(const std::string_view prefix) -> void;
|
|
42
ref.hpp
42
ref.hpp
@ -5,14 +5,40 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
template <typename T, void Free(T*)>
|
template <typename> struct RefTraits {};
|
||||||
struct FnDeleter {
|
|
||||||
auto operator()(T *ptr) const -> void { Free(ptr); }
|
template <> struct RefTraits<EVP_PKEY> {
|
||||||
|
static constexpr void (*Free)(EVP_PKEY*) = EVP_PKEY_free;
|
||||||
|
static constexpr int (*UpRef)(EVP_PKEY*) = EVP_PKEY_up_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, void(Free)(T*)>
|
template <> struct RefTraits<X509> {
|
||||||
using Ref = std::unique_ptr<T, FnDeleter<T, Free>>;
|
static constexpr void (*Free)(X509*) = X509_free;
|
||||||
|
static constexpr int (*UpRef)(X509*) = X509_up_ref;
|
||||||
|
};
|
||||||
|
|
||||||
using EVP_PKEY_CTX_Ref = Ref<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
template <> struct RefTraits<EVP_PKEY_CTX> {
|
||||||
using X509_Ref = Ref<X509, X509_free>;
|
static constexpr void (*Free)(EVP_PKEY_CTX*) = EVP_PKEY_CTX_free;
|
||||||
using EVP_PKEY_Ref = Ref<EVP_PKEY, EVP_PKEY_free>;
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct FnDeleter {
|
||||||
|
auto operator()(T *ptr) const -> void { RefTraits<T>::Free(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct Ref : std::unique_ptr<T, FnDeleter<T>> {
|
||||||
|
using std::unique_ptr<T, FnDeleter<T>>::unique_ptr;
|
||||||
|
Ref(const Ref &ref) {
|
||||||
|
*this = ref;
|
||||||
|
}
|
||||||
|
Ref &operator=(const Ref &ref) {
|
||||||
|
RefTraits<T>::UpRef(ref.get());
|
||||||
|
this->reset(ref.get());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using EVP_PKEY_CTX_Ref = Ref<EVP_PKEY_CTX>;
|
||||||
|
using X509_Ref = Ref<X509>;
|
||||||
|
using EVP_PKEY_Ref = Ref<EVP_PKEY>;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user