xbot/myirc/challenge.cpp

96 lines
3.2 KiB
C++
Raw Normal View History

2025-02-01 11:04:33 -08:00
#include "myirc/challenge.hpp"
2025-01-28 19:02:30 -08:00
2025-02-01 11:04:33 -08:00
#include "myirc/openssl_utils.hpp"
2025-01-28 19:02:30 -08:00
#include <mybase64.hpp>
2025-01-29 09:54:17 -08:00
2025-01-28 19:02:30 -08:00
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <boost/log/trivial.hpp>
#include <memory>
#include <string>
2025-02-01 11:04:33 -08:00
namespace myirc {
2025-02-05 09:24:47 -08:00
Challenge::Challenge(Ref<EVP_PKEY> key, std::shared_ptr<Client> client)
2025-01-28 19:02:30 -08:00
: key_{std::move(key)}
2025-02-05 09:24:47 -08:00
, client_{std::move(client)}
2025-01-28 19:02:30 -08:00
{}
2025-01-29 09:54:17 -08:00
auto Challenge::on_ircmsg(IrcCommand cmd, const IrcMsg &msg) -> void {
switch (cmd) {
default: break;
case IrcCommand::RPL_RSACHALLENGE2:
buffer_ += msg.args[1];
break;
case IrcCommand::ERR_NOOPERHOST:
slot_.disconnect();
BOOST_LOG_TRIVIAL(error) << "Challenge: No oper host";
break;
case IrcCommand::RPL_YOUREOPER:
slot_.disconnect();
break;
case IrcCommand::RPL_ENDOFRSACHALLENGE2:
finish_challenge();
break;
}
}
2025-01-28 19:02:30 -08:00
2025-01-29 09:54:17 -08:00
auto Challenge::finish_challenge() -> void
2025-01-28 19:02:30 -08:00
{
2025-01-29 09:54:17 -08:00
unsigned int digestlen = EVP_MAX_MD_SIZE;
unsigned char digest[EVP_MAX_MD_SIZE];
size_t len = mybase64::decoded_size(buffer_.size());
std::vector<unsigned char> ciphertext(len, 0);
2025-02-05 09:24:47 -08:00
auto decode_end = mybase64::decode(buffer_, reinterpret_cast<char*>(ciphertext.data()));
if (decode_end == nullptr )
2025-01-29 09:54:17 -08:00
return log_openssl_errors("Challenge base64::decode: ");
2025-02-05 09:24:47 -08:00
ciphertext.resize(decode_end - reinterpret_cast<char*>(ciphertext.data()));
2025-01-29 09:54:17 -08:00
// Setup decryption context
2025-01-30 11:56:03 -08:00
Ref<EVP_PKEY_CTX> ctx{EVP_PKEY_CTX_new(key_.get(), nullptr)};
if (not ctx)
2025-01-29 09:54:17 -08:00
return log_openssl_errors("Challenge EVP_PKEY_CTX_new: ");
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
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);
// Decrypt ciphertext
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);
// Hash the decrypted message
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
buffer_.resize(mybase64::encoded_size(digestlen) + 1);
buffer_[0] = '+';
mybase64::encode(std::string_view{(char*)digest, digestlen}, buffer_.data() + 1);
2025-02-05 09:24:47 -08:00
client_->send_challenge(buffer_);
2025-01-29 20:43:03 -08:00
buffer_.clear();
2025-01-28 19:02:30 -08:00
}
2025-02-05 09:24:47 -08:00
auto Challenge::start(std::shared_ptr<Client> client, const std::string_view user, Ref<EVP_PKEY> ref) -> std::shared_ptr<Challenge>
2025-01-28 19:02:30 -08:00
{
2025-02-05 09:24:47 -08:00
auto self = std::make_shared<Challenge>(std::move(ref), client);
self->slot_ = client->get_connection().sig_ircmsg.connect([self](auto cmd, auto &msg, bool) { self->on_ircmsg(cmd, msg); });
client->send_challenge(user);
2025-01-28 19:02:30 -08:00
return self;
}
2025-02-01 11:04:33 -08:00
} // namespace myirc