From 6e022b3c123287da50a56341849625f47830606c Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Thu, 4 Apr 2024 21:54:51 -0700 Subject: [PATCH 1/2] create msr checkpoints --- sdk/include/host/Enclave.hpp | 19 ++++++- sdk/src/host/Enclave.cpp | 107 ++++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index bcb7a5b45..367d9dfcc 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -59,7 +59,6 @@ class Enclave { and their pointers into the enclave bundle in epm. */ Error materializeResourceInfo(resource_ptr_t residentResPtrs[], ElfFile* allElfFiles[], std::vector resInfos); - static Error measureResidentArr(hash_ctx_t& hash_ctx, std::vector resident); static bool resourceInfoCompare(const resource_info_t& a, const resource_info_t& b); static bool resourceHashCompare(const resource_hash_t& a, const resource_hash_t& b); void sortAllResources(); @@ -83,6 +82,24 @@ class Enclave { // Call after adding all needed resources to fully create the enclave. Error finalize(); Error finalize(const char* filepath, const char* runtime, const char* loaderpath, Params _params); + + class Checkpoint { + public: + Checkpoint(Params& params, std::vector& identityResident, + std::vector& identityAbsent, std::vector& resident, + std::vector& absent) : params(params), identityResident(identityResident), + resident(resident), absent(absent) {}; + Params params; + std::vector identityResident; + std::vector identityAbsent; + std::vector resident; + std::vector absent; + void measurement(char* hash); + void sortAllResources(); + private: + void assertSorted(); + }; + Checkpoint makeCheckpoint(); }; } // namespace Keystone diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index 87eb71978..7b6c9ff8a 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -54,50 +54,41 @@ Enclave::calculateEpmPages(std::vector allElfFiles, size_t freeMemSize return pages; } -Error -Enclave::measureResidentArr(hash_ctx_t& hash_ctx, std::vector resident) { - char sub_hash[MDSIZE]; +Enclave::Checkpoint +Enclave::makeCheckpoint() { + std::vector emptyVec; + Checkpoint checkpoint(params, emptyVec, identityAbsent, emptyVec, absent); + + // hash files to convert resource_info_t to resource_hash_t hash_ctx_t file_hash_ctx; - for (resource_info_t& rInfo : resident) { - hash_extend(&hash_ctx, &rInfo.name, sizeof(rInfo.name)); - hash_extend(&hash_ctx, &rInfo.type, sizeof(rInfo.type)); - - // hash file - ElfFile elfFile(rInfo.filepath); - hash_init(&file_hash_ctx); - hash_extend(&file_hash_ctx, elfFile.getPtr(), elfFile.getFileSize()); - hash_finalize(sub_hash, &file_hash_ctx); - - // hash(file hash) - hash_extend(&hash_ctx, sub_hash, sizeof(sub_hash)); + for (int i = 0; i < 2; i++) { + std::vector* vectIn = &identityResident; + std::vector* vectOut = &checkpoint.identityResident; + if (i == 1) { + vectIn = &resident; + vectOut = &checkpoint.resident; + } + for (resource_info_t& rInfo : *vectIn) { + vectOut->push_back({}); + resource_hash_t& rOut = vectOut->back(); + strcpy(rOut.name, rInfo.name); + rOut.type = rInfo.type; + + // hash file + ElfFile elfFile(rInfo.filepath); + hash_init(&file_hash_ctx); + hash_extend(&file_hash_ctx, elfFile.getPtr(), elfFile.getFileSize()); + hash_finalize(rOut.hash, &file_hash_ctx); + } } - return Error::Success; + + checkpoint.sortAllResources(); + return checkpoint; } Error Enclave::measureSelf(char* hash) { - sortAllResources(); - - hash_ctx_t hash_ctx; - hash_init(&hash_ctx); - - // runtime vals - runtime_val_t runtime_val = {.name = MSR_FREE_MEM, .val = params.getFreeMemSize()}; - hash_extend(&hash_ctx, &runtime_val, sizeof(runtime_val)); - runtime_val = {.name = MSR_UT_MEM, .val = params.getUntrustedSize()}; - hash_extend(&hash_ctx, &runtime_val, sizeof(runtime_val)); - - measureResidentArr(hash_ctx, identityResident); - for (resource_hash_t& rHash : identityAbsent) { - hash_extend(&hash_ctx, &rHash, sizeof(rHash)); - } - measureResidentArr(hash_ctx, resident); - for (resource_hash_t& rHash : absent) { - hash_extend(&hash_ctx, &rHash, sizeof(rHash)); - } - - hash_finalize(hash, &hash_ctx); - + makeCheckpoint().measurement(hash); return Error::Success; } @@ -372,4 +363,44 @@ Enclave::registerOcallDispatch(OcallFunc func) { return Error::Success; } +void +Enclave::Checkpoint::measurement(char* hash) { + assertSorted(); + hash_ctx_t hash_ctx; + hash_init(&hash_ctx); + + // runtime vals + runtime_val_t runtimeVal = {.name = MSR_FREE_MEM, .val = params.getFreeMemSize()}; + hash_extend(&hash_ctx, &runtimeVal, sizeof(runtimeVal)); + runtimeVal = {.name = MSR_UT_MEM, .val = params.getUntrustedSize()}; + hash_extend(&hash_ctx, &runtimeVal, sizeof(runtimeVal)); + + // resources + for (const std::vector& vect : {identityResident, identityAbsent, resident, absent}) { + for (const resource_hash_t& rHash : vect) { + hash_extend(&hash_ctx, &rHash, sizeof(rHash)); + } + } + + hash_finalize(hash, &hash_ctx); +} + +void +Enclave::Checkpoint::sortAllResources() { + // sort by filename + std::sort(identityResident.begin(), identityResident.end(), resourceHashCompare); + std::sort(identityAbsent.begin(), identityAbsent.end(), resourceHashCompare); + std::sort(resident.begin(), resident.end(), resourceHashCompare); + std::sort(absent.begin(), absent.end(), resourceHashCompare); +} + +void +Enclave::Checkpoint::assertSorted() { + for (const std::vector& vect : {identityResident, identityAbsent, resident, absent}) { + for (int i = 1; i < vect.size(); i++) { + assert(resourceHashCompare(vect[i-1], vect[i])); + } + } +} + } // namespace Keystone From 3191a8f7dde916a577c89cd01142e0b77dca3b3d Mon Sep 17 00:00:00 2001 From: Evgeny P Date: Thu, 4 Apr 2024 23:03:25 -0700 Subject: [PATCH 2/2] make attestor use dynamic msr --- examples/attestation/host/host.cpp | 4 +- examples/attestation/host/host.h | 44 +++++++++---------- examples/attestation/host/verifier.cpp | 59 ++++++++++++++++++++++---- examples/attestation/host/verifier.h | 29 +++++++------ sdk/include/host/Enclave.hpp | 7 ++- sdk/src/host/Enclave.cpp | 35 +++++++++++++++ 6 files changed, 130 insertions(+), 48 deletions(-) diff --git a/examples/attestation/host/host.cpp b/examples/attestation/host/host.cpp index 8acc4c57d..d100d449b 100644 --- a/examples/attestation/host/host.cpp +++ b/examples/attestation/host/host.cpp @@ -234,9 +234,7 @@ Host::dispatch_ocall(RunData& run_data) { Report Host::run(const std::string& nonce) { - Keystone::Enclave enclave; - enclave.finalize(eapp_file_.c_str(), rt_file_.c_str(), ld_file_.c_str(), params_); - + enclave.finalize(); RunData run_data{ SharedBuffer{enclave.getSharedBuffer(), enclave.getSharedBufferSize()}, nonce, nullptr}; diff --git a/examples/attestation/host/host.h b/examples/attestation/host/host.h index 470eb8929..d4504c058 100644 --- a/examples/attestation/host/host.h +++ b/examples/attestation/host/host.h @@ -56,31 +56,31 @@ class SharedBuffer { // and the remote verifier. class Host { public: -Host( + Host( const Keystone::Params& params, const std::string& eapp_file, - const std::string& rt_file, const std::string& ld_file) - : params_(params), eapp_file_(eapp_file), rt_file_(rt_file), - ld_file_(ld_file) {} - // Given a random nonce from the remote verifier, this method leaves - // it for the enclave to fetch, and returns the attestation report - // from the enclave to the verifier. - Report run(const std::string& nonce); + const std::string& rt_file, const std::string& ld_file) { + enclave = Keystone::Enclave(params); + enclave.addStandard( + eapp_file.c_str(), rt_file.c_str(), ld_file.c_str()); + } + // Given a random nonce from the remote verifier, this method leaves + // it for the enclave to fetch, and returns the attestation report + // from the enclave to the verifier. + Report run(const std::string& nonce); + Keystone::Enclave& getEnclave() { return enclave; } private: - struct RunData { - SharedBuffer shared_buffer; - const std::string& nonce; - std::unique_ptr report; - }; - static void dispatch_ocall(RunData& run_data); - static void print_buffer_wrapper(RunData& run_data); - static void print_value_wrapper(RunData& run_data); - static void copy_report_wrapper(RunData& run_data); - static void get_host_string_wrapper(RunData& run_data); - const Keystone::Params params_; - const std::string eapp_file_; - const std::string rt_file_; - const std::string ld_file_; + struct RunData { + SharedBuffer shared_buffer; + const std::string& nonce; + std::unique_ptr report; + }; + static void dispatch_ocall(RunData& run_data); + static void print_buffer_wrapper(RunData& run_data); + static void print_value_wrapper(RunData& run_data); + static void copy_report_wrapper(RunData& run_data); + static void get_host_string_wrapper(RunData& run_data); + Keystone::Enclave enclave; }; #endif /* _ATTESTATION_HOST_H_ */ diff --git a/examples/attestation/host/verifier.cpp b/examples/attestation/host/verifier.cpp index ec5574cc4..a82dee624 100644 --- a/examples/attestation/host/verifier.cpp +++ b/examples/attestation/host/verifier.cpp @@ -23,17 +23,49 @@ void Verifier::run() { const std::string nonce = std::to_string(random() % 0x100000000); - Host host(params_, eapp_file_, rt_file_, ld_file_); + Host host(params, eapp_file, rt_file, ld_file); + Keystone::Enclave::Checkpoint checkpoint_additions; + { + // create a random file, not used by enclave + const std::string extra_filename = "extra_file.txt"; + // random contents + std::string extra_contents; + int extra_contents_length = 10; + extra_contents.reserve(extra_contents_length); + for (int i = 0; i < extra_contents_length; i++) { + extra_contents += (char) (random() % 128); + } + // write to file + FILE* extra_file = fopen(extra_filename.c_str(), "w"); + if (!extra_file) + throw std::runtime_error( + "Error opening extra_file: " + extra_filename + ", " + + std::strerror(errno)); + if (fwrite(extra_contents.data(), 1, extra_contents.size(), extra_file) + != extra_contents.size()) { + throw std::runtime_error( + "Error writing extra_file: " + extra_filename + ", " + + std::strerror(errno)); + } + fclose(extra_file); + // use Keystone::Enclave to create the delta, and add to existing enclave + Keystone::Enclave& enclave = host.getEnclave(); + enclave.startDelta(); + enclave.addResidentResource(extra_filename.c_str(), 0, + extra_filename.c_str(), 1); + checkpoint_additions = enclave.makeDeltaCheckpoint(); + } Report report = host.run(nonce); - verify_report(report, nonce); + verify_report(report, nonce, checkpoint_additions); } void -Verifier::verify_report(Report& report, const std::string& nonce) { +Verifier::verify_report(Report& report, const std::string& nonce, + Keystone::Enclave::Checkpoint checkpoint_additions) { debug_verify(report, _sanctum_dev_public_key); byte expected_enclave_hash[MDSIZE]; - compute_expected_enclave_hash(expected_enclave_hash); + compute_expected_enclave_hash(expected_enclave_hash, checkpoint_additions); byte expected_sm_hash[MDSIZE]; compute_expected_sm_hash(expected_sm_hash); @@ -77,8 +109,17 @@ Verifier::verify_data(Report& report, const std::string& nonce) { } void -Verifier::compute_expected_enclave_hash(byte* expected_enclave_hash) { - Keystone::Enclave::measure((char*) expected_enclave_hash, eapp_file_.c_str(), rt_file_.c_str(), ld_file_.c_str(), params_); +Verifier::compute_expected_enclave_hash(byte* expected_enclave_hash, + Keystone::Enclave::Checkpoint checkpoint_additions) { + // create base + Keystone::Enclave enclave(params); + enclave.addStandard( + eapp_file.c_str(), rt_file.c_str(), ld_file.c_str()); + Keystone::Enclave::Checkpoint checkpoint = enclave.makeCheckpoint(); + // add additions & calculate hash + // in reality, would also validate checkpoint_additions is allowed + checkpoint.addFromCheckpoint(checkpoint_additions); + checkpoint.measurement((char *) expected_enclave_hash); } void @@ -92,14 +133,14 @@ Verifier::compute_expected_sm_hash(byte* expected_sm_hash) { { // Reading SM content from file. - FILE* sm_bin = fopen(sm_bin_file_.c_str(), "rb"); + FILE* sm_bin = fopen(sm_bin_file.c_str(), "rb"); if (!sm_bin) throw std::runtime_error( - "Error opening sm_bin_file_: " + sm_bin_file_ + ", " + + "Error opening sm_bin_file: " + sm_bin_file + ", " + std::strerror(errno)); if (fread(sm_content.data(), 1, sm_content.size(), sm_bin) <= 0) throw std::runtime_error( - "Error reading sm_bin_file_: " + sm_bin_file_ + ", " + + "Error reading sm_bin_file: " + sm_bin_file + ", " + std::strerror(errno)); fclose(sm_bin); } diff --git a/examples/attestation/host/verifier.h b/examples/attestation/host/verifier.h index b85ba0fad..c296112b7 100644 --- a/examples/attestation/host/verifier.h +++ b/examples/attestation/host/verifier.h @@ -22,12 +22,13 @@ class Verifier { public: Verifier( const Keystone::Params& params, const std::string& eapp_file, - const std::string& rt_file, const std::string& ld_file, const std::string& sm_bin_file) - : params_(params), - eapp_file_(eapp_file), - rt_file_(rt_file), - ld_file_(ld_file), - sm_bin_file_(sm_bin_file) {} + const std::string& rt_file, const std::string& ld_file, + const std::string& sm_bin_file) + : params(params), + eapp_file(eapp_file), + rt_file(rt_file), + ld_file(ld_file), + sm_bin_file(sm_bin_file) {} // This method generates a random nonce, invokes the run() method // of the Host, and verifies that the returned attestation report // is valid. @@ -49,17 +50,19 @@ class Verifier { static void verify_data(Report& report, const std::string& nonce); // Verifies the hashes and the nonce in the attestation report. - void verify_report(Report& report, const std::string& nonce); + void verify_report(Report& report, const std::string& nonce, + Keystone::Enclave::Checkpoint checkpoint_additions); // Computes the hash of the expected EApp running in the enclave. - void compute_expected_enclave_hash(byte* expected_enclave_hash); + void compute_expected_enclave_hash(byte* expected_enclave_hash, + Keystone::Enclave::Checkpoint checkpoint_additions); // Computes the hash of the expected Security Monitor (SM). void compute_expected_sm_hash(byte* expected_sm_hash); - const Keystone::Params params_; - const std::string eapp_file_; - const std::string rt_file_; - const std::string ld_file_; - const std::string sm_bin_file_; + const Keystone::Params params; + const std::string eapp_file; + const std::string rt_file; + const std::string ld_file; + const std::string sm_bin_file; }; diff --git a/sdk/include/host/Enclave.hpp b/sdk/include/host/Enclave.hpp index 367d9dfcc..f1b5701ca 100644 --- a/sdk/include/host/Enclave.hpp +++ b/sdk/include/host/Enclave.hpp @@ -36,6 +36,7 @@ class Enclave { Params params; KeystoneDevice pDevice; OcallFunc oFuncDispatch; + Enclave* deltaEnclave = nullptr; // track added resources typedef struct { @@ -85,10 +86,11 @@ class Enclave { class Checkpoint { public: + Checkpoint() {} Checkpoint(Params& params, std::vector& identityResident, std::vector& identityAbsent, std::vector& resident, std::vector& absent) : params(params), identityResident(identityResident), - resident(resident), absent(absent) {}; + resident(resident), absent(absent) {} Params params; std::vector identityResident; std::vector identityAbsent; @@ -96,9 +98,12 @@ class Enclave { std::vector absent; void measurement(char* hash); void sortAllResources(); + void addFromCheckpoint(Checkpoint other); private: void assertSorted(); }; + void startDelta(); + Checkpoint makeDeltaCheckpoint(); Checkpoint makeCheckpoint(); }; diff --git a/sdk/src/host/Enclave.cpp b/sdk/src/host/Enclave.cpp index 7b6c9ff8a..de1962239 100644 --- a/sdk/src/host/Enclave.cpp +++ b/sdk/src/host/Enclave.cpp @@ -86,6 +86,18 @@ Enclave::makeCheckpoint() { return checkpoint; } +void +Enclave::startDelta() { + assert(deltaEnclave == nullptr); + deltaEnclave = new Enclave(); +} + +Enclave::Checkpoint +Enclave::makeDeltaCheckpoint() { + assert(deltaEnclave); + return deltaEnclave->makeCheckpoint(); +} + Error Enclave::measureSelf(char* hash) { makeCheckpoint().measurement(hash); @@ -109,6 +121,9 @@ Enclave::addResidentResource(const char* name, uintptr_t type, const char* filep if (strlen(name) >= MSR_NAME_LEN) { return Error::BadArgument; } + if (deltaEnclave) { + deltaEnclave->addResidentResource(name, type, filepath, identity); + } resource_info_t* resInfo = 0; if (identity) { identityResident.push_back({}); @@ -128,6 +143,9 @@ Enclave::addAbsentResource(const char* name, uintptr_t type, const char* hash, b if (strlen(name) >= MSR_NAME_LEN) { return Error::BadArgument; } + if (deltaEnclave) { + deltaEnclave->addAbsentResource(name, type, hash, identity); + } resource_hash_t* resHash = 0; if (identity) { identityAbsent.push_back({}); @@ -322,6 +340,10 @@ Enclave::destroy() { delete elfFile; } allElfFiles.clear(); + if (deltaEnclave) { + delete deltaEnclave; + deltaEnclave = nullptr; + } return pDevice.destroy(); } @@ -403,4 +425,17 @@ Enclave::Checkpoint::assertSorted() { } } +void +Enclave::Checkpoint::addFromCheckpoint(Checkpoint other) { + auto add_resources = [](std::vector& base, + std::vector& additions) -> void { + base.insert(base.end(), additions.begin(), additions.end()); + }; + add_resources(identityResident, other.identityResident); + add_resources(identityAbsent, other.identityAbsent); + add_resources(resident, other.resident); + add_resources(absent, other.absent); + sortAllResources(); +} + } // namespace Keystone