Fixed a possible crash when resetting the crypto handler

This commit is contained in:
WolverinDEV 2021-06-09 14:35:24 +02:00
parent 1eaca0236b
commit a0b765146a
5 changed files with 91 additions and 53 deletions

View File

@ -57,10 +57,10 @@ void ProtocolHandler::reset() {
this->crypto.initiv_command = "";
this->crypto.beta_length = 0;
if(this->crypto.identity.k) {
ecc_free(&this->crypto.identity);
if(this->crypto.identity.has_value()) {
ecc_free(&*this->crypto.identity);
this->crypto.identity = std::nullopt;
}
memset(&this->crypto.identity, 0, sizeof(this->crypto.identity));
}
@ -77,6 +77,36 @@ void ProtocolHandler::reset() {
this->statistics_.voice_bytes_received = 0;
}
bool ProtocolHandler::initialize_identity(const std::optional<std::string_view> &identity) {
this->reset_identity();
assert(!this->crypto.identity.has_value());
this->crypto.identity.emplace();
if(identity.has_value()) {
auto result = ecc_import((u_char*) identity.data(), (unsigned long) identity.length(), &*this->crypto.identity);
if(result == CRYPT_OK) {
return true;
} else {
this->crypto.identity.reset();
log_error(category::connection, tr("Failed to initialize crypto identity from given parameter: {}"), result);
return false;
}
} else {
prng_state rng_state{};
memset(&rng_state, 0, sizeof(prng_state));
int err;
auto result = ecc_make_key_ex(&rng_state, find_prng("sprng"), &*this->crypto.identity, &ltc_ecc_sets[5]);
if(result == CRYPT_OK) {
return true;
} else {
this->crypto.identity.reset();
log_error(category::connection, tr("Failed to generate ephemeral crypto identity: {}"), result);
return false;
}
}
}
void ProtocolHandler::connect() {
this->connection_state = connection_state::INIT_LOW;
this->connect_timestamp = system_clock::now();

View File

@ -76,7 +76,9 @@ namespace tc::connection {
void disconnect(const std::string& /* message */);
void send_acknowledge(uint16_t /* packet id */, bool /* low */);
ecc_key& get_identity_key() { return this->crypto.identity; }
/* Initialize a new crypto identity from the given string */
bool initialize_identity(const std::optional<std::string_view>& identity);
void reset_identity();
inline std::chrono::microseconds current_ping() const { return this->ping.value; }
@ -124,7 +126,7 @@ namespace tc::connection {
uint8_t beta[54];
uint8_t beta_length; /* 10 or 54 */
ecc_key identity{};
std::optional<ecc_key> identity{};
std::string initiv_command;
} crypto;

View File

@ -43,7 +43,7 @@ std::string ProtocolHandler::generate_client_initiv() {
{
size_t buffer_length = 265;
char buffer[265];
auto result = ecc_export((unsigned char *) buffer, (unsigned long*) &buffer_length, PK_PUBLIC, &this->crypto.identity);
auto result = ecc_export((unsigned char *) buffer, (unsigned long*) &buffer_length, PK_PUBLIC, &*this->crypto.identity);
if(result == CRYPT_OK) {
command["omega"] = base64::encode(buffer, (unsigned long) buffer_length);
} else {
@ -80,7 +80,7 @@ void ProtocolHandler::handleCommandInitIVExpend(ts::Command &cmd) {
}
string error;
if(!this->crypt_handler.setupSharedSecret(alpha, beta, &server_key, &this->crypto.identity, error)) {
if(!this->crypt_handler.setupSharedSecret(alpha, beta, &server_key, &*this->crypto.identity, error)) {
this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to setup encryption")), true);
this->handle->close_connection();
@ -191,7 +191,7 @@ void ProtocolHandler::handleCommandInitIVExpend2(ts::Command &cmd) {
memset(&prng_state, 0, sizeof(prng_state));
auto proof_data = digest::sha256(string((char*) public_key, 32) + beta);
if(ecc_sign_hash((uint8_t*) proof_data.data(), (unsigned long) proof_data.length(), (uint8_t*) sign_buffer, (unsigned long*) &sign_buffer_length, &prng_state, find_prng("sprng"), &this->crypto.identity) != CRYPT_OK) {
if(ecc_sign_hash((uint8_t*) proof_data.data(), (unsigned long) proof_data.length(), (uint8_t*) sign_buffer, (unsigned long*) &sign_buffer_length, &prng_state, find_prng("sprng"), &*this->crypto.identity) != CRYPT_OK) {
this->handle->call_connect_result.call(this->handle->errors.register_error(tr("failed to generate proof of identity")), true);
this->handle->close_connection();
return;

View File

@ -23,17 +23,18 @@ using namespace std;
using namespace std::chrono;
using namespace tc::connection;
string ErrorHandler::get_message(ErrorHandler::error_id id) {
if(id == 0)
return "success";
string ErrorHandler::get_error_message(ErrorHandler::ErrorId id) const {
if(id == 0) {
return "success";
}
auto index = (-id - 1) % this->error_varianz;
assert(index >= 0 && index < this->error_varianz);
auto index = (-id - 1) % this->kErrorBacklog;
assert(index >= 0 && index < this->kErrorBacklog);
return this->error_messages[index];
}
ErrorHandler::error_id ErrorHandler::register_error(const string &message) {
auto index = this->error_index++ % this->error_varianz;
ErrorHandler::ErrorId ErrorHandler::register_error(const string &message) {
auto index = this->error_index++ % this->kErrorBacklog;
this->error_messages[index] = message;
return -index - 1;
}
@ -44,8 +45,9 @@ ServerConnection::ServerConnection() {
ServerConnection::~ServerConnection() {
logger::debug(category::connection, tr("Begin deallocating ServerConnection {}."), (void*) this);
if(this->protocol_handler && this->protocol_handler->connection_state == connection_state::CONNECTED)
this->protocol_handler->disconnect("server connection has been destoryed");
if(this->protocol_handler && this->protocol_handler->connection_state == connection_state::CONNECTED) {
this->protocol_handler->disconnect("server connection has been destoryed");
}
this->close_connection();
this->finalize();
@ -114,7 +116,7 @@ void ServerConnection::initialize() {
});
this->call_connect_result = Nan::async_callback([&](ErrorHandler::error_id error_id) {
this->call_connect_result = Nan::async_callback([&](ErrorHandler::ErrorId error_id) {
Nan::HandleScope scope;
/* lets update the server type */
{
@ -134,7 +136,7 @@ void ServerConnection::initialize() {
});
this->call_disconnect_result = Nan::async_callback([&](ErrorHandler::error_id error_id) {
this->call_disconnect_result = Nan::async_callback([&](ErrorHandler::ErrorId error_id) {
Nan::HandleScope scope;
v8::Local<v8::Value> argv[1];
argv[0] = Nan::New<v8::Number>(error_id);
@ -274,26 +276,21 @@ NAN_METHOD(ServerConnection::connect) {
this->voice_connection->reset();
this->protocol_handler->reset();
if(identity_key->IsString()) {
auto& identity = this->protocol_handler->get_identity_key();
std::string identity_decoded{*Nan::Utf8String(identity_key->ToString(Nan::GetCurrentContext()).ToLocalChecked())};
auto key = base64::decode(identity_decoded);
if(ecc_import((u_char*) key.data(), (unsigned long) key.length(), &identity) != CRYPT_OK) {
Nan::ThrowError(tr("failed to import identity"));
return;
}
} else {
auto& identity = this->protocol_handler->get_identity_key();
prng_state rndState{};
memset(&rndState, 0, sizeof(prng_state));
int err;
if((err = ecc_make_key_ex(&rndState, find_prng("sprng"), &identity, &ltc_ecc_sets[5])) != CRYPT_OK) {
Nan::ThrowError(tr("failed to generate ephemeral identity"));
return;
}
std::optional<std::string> identity{std::nullopt};
if(identity_key->IsString()) {
auto identity_encoded = Nan::Utf8String{identity_key->ToString(Nan::GetCurrentContext()).ToLocalChecked()};
identity = std::make_optional(
base64::decode(std::string_view{*identity_encoded, (size_t) identity_encoded.length()})
);
}
if(!this->protocol_handler->initialize_identity(identity)) {
Nan::ThrowError(tr("failed to initialize crypto identity"));
return;
}
sockaddr_storage remote_address{};
/* resolve address */
{
@ -302,8 +299,8 @@ NAN_METHOD(ServerConnection::connect) {
hints.ai_family = AF_UNSPEC;
auto _remote_host = Nan::Utf8String(remote_host->ToString(Nan::GetCurrentContext()).ToLocalChecked());
if(getaddrinfo(*_remote_host, nullptr, &hints, &result) != 0 || !result) {
auto remote_host_ = Nan::Utf8String{remote_host->ToString(Nan::GetCurrentContext()).ToLocalChecked()};
if(getaddrinfo(*remote_host_, nullptr, &hints, &result) != 0 || !result) {
this->call_connect_result(this->errors.register_error(tr("failed to resolve hostname")));
return;
}
@ -311,15 +308,21 @@ NAN_METHOD(ServerConnection::connect) {
memcpy(&remote_address, result->ai_addr, result->ai_addrlen);
freeaddrinfo(result);
}
switch(remote_address.ss_family) {
case AF_INET:
((sockaddr_in*) &remote_address)->sin_port = htons(remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0));
break;
case AF_INET6:
((sockaddr_in6*) &remote_address)->sin6_port = htons(remote_port->Int32Value(Nan::GetCurrentContext()).FromMaybe(0));
default:break;
break;
default:
break;
}
logger::info(category::connection, tr("Connecting to {}."), net::to_string(remote_address));
log_info(category::connection, tr("Connecting to {}."), net::to_string(remote_address));
this->socket = make_shared<UDPSocket>(remote_address);
if(!this->socket->initialize()) {
this->call_connect_result(this->errors.register_error("failed to initialize socket"));
@ -338,8 +341,9 @@ NAN_METHOD(ServerConnection::connect) {
this->close_connection();
};
if(teamspeak->IsBoolean() && teamspeak->BooleanValue(info.GetIsolate()))
this->protocol_handler->server_type = server_type::TEAMSPEAK;
if(teamspeak->IsBoolean() && teamspeak->BooleanValue(info.GetIsolate())) {
this->protocol_handler->server_type = server_type::TEAMSPEAK;
}
this->protocol_handler->connect();
}
@ -390,7 +394,9 @@ NAN_METHOD(ServerConnection::error_message) {
return;
}
auto error = this->errors.get_message((ErrorHandler::error_id) info[0]->IntegerValue(Nan::GetCurrentContext()).FromMaybe(0));
auto error = this->errors.get_error_message(
(ErrorHandler::ErrorId) info[0]->IntegerValue(Nan::GetCurrentContext()).FromMaybe(0)
);
info.GetReturnValue().Set(Nan::New<v8::String>(error).ToLocalChecked());
}

View File

@ -28,16 +28,16 @@ namespace tc {
class ErrorHandler {
public:
typedef int16_t error_id;
static constexpr error_id error_success = 0;
static constexpr error_id error_varianz = 5;
typedef int16_t ErrorId;
static constexpr ErrorId kErrorCodeSuccess = 0;
static constexpr ErrorId kErrorBacklog = 5;
[[nodiscard]] std::string get_error_message(ErrorId) const;
[[nodiscard]] ErrorId register_error(const std::string& /* message */);
std::array<std::string, error_varianz> error_messages;
error_id error_index = 0;
std::string get_message(error_id);
error_id register_error(const std::string& /* message */);
private:
std::array<std::string, kErrorBacklog> error_messages{};
ErrorId error_index{0};
};
class ServerConnection : public Nan::ObjectWrap {
@ -90,8 +90,8 @@ namespace tc {
std::unique_ptr<Nan::Callback> callback_connect;
std::unique_ptr<Nan::Callback> callback_disconnect;
Nan::callback_t<ErrorHandler::error_id> call_connect_result;
Nan::callback_t<ErrorHandler::error_id> call_disconnect_result;
Nan::callback_t<ErrorHandler::ErrorId> call_connect_result;
Nan::callback_t<ErrorHandler::ErrorId> call_disconnect_result;
Nan::callback_t<> execute_pending_commands;
Nan::callback_t<> execute_pending_voice;
Nan::callback_t<std::string> execute_callback_disconnect;