Fixed a possible crash when resetting the crypto handler
This commit is contained in:
parent
1eaca0236b
commit
a0b765146a
@ -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, <c_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();
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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, <c_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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user