Skip to content

Commit

Permalink
Add automatic seed generation and replication
Browse files Browse the repository at this point in the history
  • Loading branch information
ssantos21 committed May 20, 2024
1 parent e5249e0 commit a800f63
Show file tree
Hide file tree
Showing 24 changed files with 12,024 additions and 241 deletions.
2 changes: 2 additions & 0 deletions docker-compose-hw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ services:
- db_enclave
environment:
- ENCLAVE_DATABASE_URL=postgres://postgres:postgres@db_enclave:5432/enclave
- ENCLAVE_PORT=18080
- SEED_DIR=./seed
devices:
- /dev/isgx
volumes:
Expand Down
3 changes: 2 additions & 1 deletion docker-compose-sim.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ services:
- db_enclave
environment:
- ENCLAVE_DATABASE_URL=postgres://postgres:postgres@db_enclave:5432/enclave

- ENCLAVE_PORT=18080
- SEED_DIR=./seed
mercury-server:
build:
context: .
Expand Down
304 changes: 105 additions & 199 deletions enclave/App/App.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "App.h"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
#pragma GCC diagnostic ignored "-Wcast-qual"
Expand All @@ -7,11 +9,11 @@
#include <lib/crow_all.h>
#include <lib/toml.hpp>
#pragma GCC diagnostic pop
#include <lib/CLI11.hpp>

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <pqxx/pqxx>
#include <stdio.h>
#include <string.h>
#include <sstream>
Expand All @@ -21,12 +23,14 @@
#include "../utils/strencodings.h"
#include "utilities/utilities.h"
#include "database/db_manager.h"
#include "statechain/deposit.h"
#include "statechain/sign.h"
#include "statechain/transfer_receiver.h"
#include "sealing_key_manager/sealing_key_manager.h"

#include "App.h"
#include "endpoints/deposit.h"
#include "endpoints/secret.h"
#include "endpoints/sign.h"
#include "endpoints/transfer_receiver.h"
#include "endpoints/withdraw.h"

#include "Enclave_u.h"
#include "sgx_urts.h"
#include "sgx_tcrypto.h"
Expand All @@ -49,243 +53,145 @@ void ocall_print_hex(const unsigned char** key, const int *keylen)
printf("%s\n", key_to_string(*key, *keylen).c_str());
}

// TODO: duplicated. Remove this.
std::string getDatabaseConnectionString() {
const char* value = std::getenv("ENCLAVE_DATABASE_URL");

if (value == nullptr) {
auto config = toml::parse_file("Settings.toml");
return config["intel_sgx"]["database_connection_string"].as_string()->get();
} else {
return std::string(value);
}
}

int SGX_CDECL main(int argc, char *argv[])
bool start_server(sgx_enclave_id_t& enclave_id, std::mutex& mutex_enclave_id, sealing_key_manager::SealingKeyManager& sealing_key_manager)
{
(void)(argc);
(void)(argv);

crow::SimpleApp app;

sgx_enclave_id_t enclave_id = 0;
std::mutex mutex_enclave_id; // protects map_aggregate_key_data

{
const std::lock_guard<std::mutex> lock(mutex_enclave_id);

// initialize enclave
sgx_status_t enclave_created = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &enclave_id, NULL);
if (enclave_created != SGX_SUCCESS) {
printf("Enclave init error\n");
return -1;
}
}

sealing_key_manager::SealingKeyManager sealing_key_manager;
if (sealing_key_manager.readSeedFromFile()) {
std::cout << "Seed loaded" << std::endl;
} else {
std::cout << "Seed not loaded" << std::endl;
}

CROW_ROUTE(app, "/get_public_key")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {

if (sealing_key_manager.isSeedEmpty()) {
return crow::response(500, "Sealing key is empty.");
}

auto req_body = crow::json::load(req.body);
if (!req_body)
return crow::response(400);

if (req_body.count("statechain_id") == 0)
return crow::response(400, "Invalid parameter. It must be 'statechain_id'.");

std::string statechain_id = req_body["statechain_id"].s();

const std::lock_guard<std::mutex> lock(mutex_enclave_id);

return deposit::get_public_key(enclave_id, statechain_id, sealing_key_manager);
return endpoinDeposit::handleGetPublicKey(req, enclave_id, mutex_enclave_id, sealing_key_manager);
});

CROW_ROUTE(app, "/get_public_nonce")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {

if (sealing_key_manager.isSeedEmpty()) {
return crow::response(500, "Sealing key is empty.");
}

auto req_body = crow::json::load(req.body);
if (!req_body)
return crow::response(400);

if (req_body.count("statechain_id") == 0) {
return crow::response(400, "Invalid parameters. They must be 'statechain_id'.");
}

std::string statechain_id = req_body["statechain_id"].s();

const std::lock_guard<std::mutex> lock(mutex_enclave_id);

return signature::get_public_nonce(enclave_id, statechain_id, sealing_key_manager);
return endpointSignature::handleGetPublicNonce(req, enclave_id, mutex_enclave_id, sealing_key_manager);
});

CROW_ROUTE(app, "/get_partial_signature")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {

if (sealing_key_manager.isSeedEmpty()) {
return crow::response(500, "Sealing key is empty.");
}

auto req_body = crow::json::load(req.body);
if (!req_body)
return crow::response(400);

if (req_body.count("statechain_id") == 0 ||
req_body.count("negate_seckey") == 0 ||
req_body.count("session") == 0) {
return crow::response(400, "Invalid parameters. They must be 'statechain_id', 'negate_seckey' and 'session'.");
}

std::string statechain_id = req_body["statechain_id"].s();
int64_t negate_seckey = req_body["negate_seckey"].i();
std::string session_hex = req_body["session"].s();


if (session_hex.substr(0, 2) == "0x") {
session_hex = session_hex.substr(2);
}

std::vector<unsigned char> serialized_session = ParseHex(session_hex);

if (serialized_session.size() != 133) {
return crow::response(400, "Invalid session length. Must be 133 bytes!");
}

const std::lock_guard<std::mutex> lock(mutex_enclave_id);

return signature::get_partial_signature(enclave_id, statechain_id, negate_seckey, serialized_session, sealing_key_manager);
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {
return endpointSignature::handleGetPartialSignature(req, enclave_id, mutex_enclave_id, sealing_key_manager);
});

CROW_ROUTE(app,"/signature_count/<string>")
([](std::string statechain_id){

return signature::signature_count(statechain_id);

return endpointSignature::signatureCount(statechain_id);
});

CROW_ROUTE(app, "/keyupdate")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {
return endpointTransferReceiver::handleKeyUpdate(req, enclave_id, mutex_enclave_id, sealing_key_manager);
});

if (sealing_key_manager.isSeedEmpty()) {
return crow::response(500, "Sealing key is empty.");
}

auto req_body = crow::json::load(req.body);
if (!req_body)
return crow::response(400);

if (req_body.count("statechain_id") == 0 ||
req_body.count("t2") == 0 ||
req_body.count("x1") == 0) {
return crow::response(400, "Invalid parameters. They must be 'statechain_id', 't2' and 'x1'.");
}

std::string statechain_id = req_body["statechain_id"].s();
std::string t2_hex = req_body["t2"].s();
std::string x1_hex = req_body["x1"].s();

if (t2_hex.substr(0, 2) == "0x") {
t2_hex = t2_hex.substr(2);
}
CROW_ROUTE(app,"/delete_statechain/<string>")
.methods("DELETE"_method)([](std::string statechain_id){
return endpointWithdraw::handleWithdraw(statechain_id);
});

std::vector<unsigned char> serialized_t2 = ParseHex(t2_hex);
CROW_ROUTE(app, "/add_mnemonic")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {
return endpointSecret::handleAddMnemonic(req, enclave_id, mutex_enclave_id, sealing_key_manager);
});

if (serialized_t2.size() != 32) {
return crow::response(400, "Invalid t2 length. Must be 32 bytes!");
}
CROW_ROUTE(app, "/get_ephemeral_public_key")
([&sealing_key_manager](){
return endpointSecret::getEphemeralPublicKey(sealing_key_manager);
});

if (x1_hex.substr(0, 2) == "0x") {
x1_hex = x1_hex.substr(2);
}
CROW_ROUTE(app, "/add_secret")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {
return endpointSecret::handleAddSecret(req, enclave_id, mutex_enclave_id, sealing_key_manager);
});

std::vector<unsigned char> serialized_x1 = ParseHex(x1_hex);
uint16_t server_port = 0;

if (serialized_x1.size() != 32) {
return crow::response(400, "Invalid x1 length. Must be 32 bytes!");
}
try {
server_port = utils::getEnclavePort();
} catch (const std::exception& e) {
std::cerr << "Error enclave port: " << e.what() << std::endl;
return false;
}

app.port(server_port).multithreaded().run();

return transfer_receiver::keyupdate(
enclave_id,
statechain_id,
serialized_t2,
serialized_x1,
sealing_key_manager
);
});
return true;
}

CROW_ROUTE(app,"/delete_statechain/<string>")
.methods("DELETE"_method)([](std::string statechain_id){
int SGX_CDECL main(int argc, char *argv[])
{
CLI::App app{"Lockbox Server"};
app.set_version_flag("--version", std::string("0.0.1"));

auto database_connection_string = getDatabaseConnectionString();
bool replicate_key = false;
bool generate_new_secret = false;

std::string error_message;
pqxx::connection conn(database_connection_string);
if (conn.is_open()) {
// Add the options to the app
app.add_flag("-r,--replicate-key", replicate_key, "Replicate key");
app.add_flag("-g,--generate-new-secret", generate_new_secret, "Generate a new secret");

std::string delete_comm =
"DELETE FROM generated_public_key WHERE statechain_id = $1;";
pqxx::work txn2(conn);
// Parse the arguments
CLI11_PARSE(app, argc, argv);

txn2.exec_params(delete_comm, statechain_id);
txn2.commit();
sgx_enclave_id_t enclave_id = 0;
std::mutex mutex_enclave_id; // protects map_aggregate_key_data

conn.close();
{
const std::lock_guard<std::mutex> lock(mutex_enclave_id);

crow::json::wvalue result({{"message", "Statechain deleted."}});
return crow::response{result};
} else {
return crow::response(500, "Failed to connect to the database!");
// initialize enclave
sgx_status_t enclave_created = sgx_create_enclave(ENCLAVE_FILENAME, SGX_DEBUG_FLAG, NULL, NULL, &enclave_id, NULL);
if (enclave_created != SGX_SUCCESS) {
printf("Enclave init error\n");
return -1;
}
});


}

CROW_ROUTE(app, "/add_mnemonic")
.methods("POST"_method)([&enclave_id, &mutex_enclave_id, &sealing_key_manager](const crow::request& req) {
sealing_key_manager::SealingKeyManager sealing_key_manager;
if (sealing_key_manager.readSeedFromFile()) {
std::cout << "Seed loaded" << std::endl;
} else {
std::cout << "Seed not loaded" << std::endl;
}

auto req_body = crow::json::load(req.body);
if (!req_body) {
return crow::response(400);
}
try {
sealing_key_manager.generateEphemeralKeys(enclave_id);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}

if (req_body.count("mnemonic") == 0 ||
req_body.count("password") == 0 ||
req_body.count("index") == 0 ||
req_body.count("threshold") == 0) {
return crow::response(400, "Invalid parameters. They must be 'mnemonic', 'password', 'index' and 'threshold'.");
if (generate_new_secret) {
const std::lock_guard<std::mutex> lock(mutex_enclave_id);

try {
if (sealing_key_manager.generateSecret(enclave_id)) {
std::cout << "New secret sucessfully generated." << std::endl;
} else {
std::cout << "Seed already exists. A new secret won't be generated." << std::endl;
}

std::string mnemonic = req_body["mnemonic"].s();
std::string password = req_body["password"].s();
int64_t index = req_body["index"].i();
int64_t threshold = req_body["threshold"].i();

const std::lock_guard<std::mutex> lock(mutex_enclave_id);

auto ret = sealing_key_manager.addMnemonic(enclave_id, mnemonic, password, (size_t) index, (size_t) threshold);
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 2;
}
}

if (!ret.success) {
return crow::response(ret.code, ret.message);
if (replicate_key) {
try {
if (sealing_key_manager.replicateSecret(enclave_id)) {
std::cout << "Seed sucessfully replicated." << std::endl;
} else {
std::cout << "The other server refused replication. The seed must already exist." << std::endl;
}
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << std::endl;
return 3;
}
}

crow::json::wvalue result({{"message", "OK."}});
return crow::response{result};
});

app.port(18080).multithreaded().run();
if (!start_server(enclave_id, mutex_enclave_id, sealing_key_manager)) {
std::cerr << "Error starting server." << std::endl;
return 4;
}

{
const std::lock_guard<std::mutex> lock(mutex_enclave_id);
Expand Down
Loading

0 comments on commit a800f63

Please sign in to comment.