From 841235931b2b78ad5f0cccbfc0b7c98272d24c80 Mon Sep 17 00:00:00 2001 From: Dmitrii Kuvaiskii Date: Tue, 4 Jun 2024 00:13:41 -0700 Subject: [PATCH] [common] Refactor Protected Files, part 5 This commit refactors PF code without changing functionality (part 5 in a series of commits). In particular, this commit renames variables, struct definitions, struct fields and functions for readability. This is the last commit in this series. Signed-off-by: Dmitrii Kuvaiskii --- common/src/protected_files/protected_files.c | 659 +++++++++--------- common/src/protected_files/protected_files.h | 8 +- .../protected_files/protected_files_format.h | 46 +- .../protected_files_internal.h | 22 +- tools/sgx/pf_tamper/pf_tamper.c | 219 +++--- 5 files changed, 468 insertions(+), 486 deletions(-) diff --git a/common/src/protected_files/protected_files.c b/common/src/protected_files/protected_files.c index ea8ebcc36b..582e429947 100644 --- a/common/src/protected_files/protected_files.c +++ b/common/src/protected_files/protected_files.c @@ -64,12 +64,11 @@ static const char* g_pf_error_list[] = { }; /* ipf prefix means "Intel protected files", these are functions from the SGX SDK implementation */ -static file_node_t* ipf_append_mht_node(pf_context_t* pf, uint64_t mht_node_number); +static file_node_t* ipf_append_mht_node(pf_context_t* pf, uint64_t logical_mht_node_number); static file_node_t* ipf_append_data_node(pf_context_t* pf, uint64_t offset); -static file_node_t* ipf_read_mht_node(pf_context_t* pf, uint64_t mht_node_number); +static file_node_t* ipf_read_mht_node(pf_context_t* pf, uint64_t logical_mht_node_number); static file_node_t* ipf_read_data_node(pf_context_t* pf, uint64_t offset); -// memcpy src->dest if src is not NULL, zero dest otherwise static void memcpy_or_zero_initialize(void* dest, const void* src, size_t size) { if (src) memcpy(dest, src, size); @@ -99,9 +98,9 @@ static size_t partition(file_node_t** data, size_t low, size_t high) { size_t j = high; while (true) { - while (data[i]->node_number < pivot->node_number) + while (data[i]->logical_node_number < pivot->logical_node_number) i++; - while (data[j]->node_number > pivot->node_number) + while (data[j]->logical_node_number > pivot->logical_node_number) j--; if (i >= j) return j; @@ -113,7 +112,7 @@ static size_t partition(file_node_t** data, size_t low, size_t high) { static void sort_nodes(file_node_t** data, size_t low, size_t high) { if (high - low == 1) { - if (data[low]->node_number > data[high]->node_number) + if (data[low]->logical_node_number > data[high]->logical_node_number) swap_nodes(data, low, high); return; } @@ -140,14 +139,14 @@ static bool ipf_generate_random_key(pf_context_t* pf, pf_key_t* output) { // https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-108.pdf // // This function derives a metadata key in two modes: -// - restore == false: derives a per-file random key from user_kdk_key using a random nonce, to -// encrypt the metadata block of the protected file; the nonce is stored in -// plaintext part of the metadata block so that the file can be loaded later -// and decrypted using the same key -// - restore == true: derives a key from user_kdk_key + nonce stored in plaintext part of the -// metadata block, to decrypt the encrypted part of the metadata block (and -// thus "restore" access to the whole protected file) -static bool ipf_import_metadata_key(pf_context_t* pf, bool restore, pf_key_t* output) { +// - nonce_from_pf == false: derives a per-file random key from kdk using a random nonce, to +// encrypt the metadata node of the protected file; the nonce is stored +// in plaintext header of the metadata node so that the file can be +// loaded later and decrypted using the same key +// - nonce_from_pf == true: derives a key from kdk + nonce stored in plaintext header of the +// metadata node, to decrypt the encrypted part of the metadata node +// (and thus gain access to the whole protected file) +static bool ipf_generate_metadata_key(pf_context_t* pf, bool nonce_from_pf, pf_key_t* output) { kdf_input_t buf = {0}; pf_status_t status; @@ -155,149 +154,147 @@ static bool ipf_import_metadata_key(pf_context_t* pf, bool restore, pf_key_t* ou if (!strcpy_static(buf.label, METADATA_KEY_NAME, MAX_LABEL_SIZE)) return false; - if (!restore) { + if (!nonce_from_pf) { status = g_cb_random((uint8_t*)&buf.nonce, sizeof(buf.nonce)); if (PF_FAILURE(status)) { pf->last_error = status; return false; } } else { - COPY_ARRAY(buf.nonce, pf->file_metadata.plain_part.metadata_key_id); + COPY_ARRAY(buf.nonce, pf->metadata_node.plaintext_header.metadata_key_nonce); } // length of output (128 bits) buf.output_len = 0x80; - status = g_cb_aes_cmac(&pf->user_kdk_key, &buf, sizeof(buf), output); + status = g_cb_aes_cmac(&pf->kdk, &buf, sizeof(buf), output); if (PF_FAILURE(status)) { pf->last_error = status; return false; } - if (!restore) { - COPY_ARRAY(pf->file_metadata.plain_part.metadata_key_id, buf.nonce); + if (!nonce_from_pf) { + COPY_ARRAY(pf->metadata_node.plaintext_header.metadata_key_nonce, buf.nonce); } erase_memory(&buf, sizeof(buf)); - return true; } static bool ipf_generate_random_metadata_key(pf_context_t* pf, pf_key_t* output) { - return ipf_import_metadata_key(pf, /*restore=*/false, output); + return ipf_generate_metadata_key(pf, /*nonce_from_pf=*/false, output); } -static bool ipf_restore_current_metadata_key(pf_context_t* pf, pf_key_t* output) { - return ipf_import_metadata_key(pf, /*restore=*/true, output); +static bool ipf_generate_nonced_metadata_key(pf_context_t* pf, pf_key_t* output) { + return ipf_generate_metadata_key(pf, /*nonce_from_pf=*/true, output); } -static void ipf_init_root_mht(file_node_t* mht) { - memset(mht, 0, sizeof(*mht)); +static void ipf_init_root_mht_node(file_node_t* mht_node) { + memset(mht_node, 0, sizeof(*mht_node)); - mht->type = FILE_MHT_NODE_TYPE; - mht->physical_node_number = 1; - mht->node_number = 0; - mht->need_writing = false; + mht_node->type = FILE_MHT_NODE_TYPE; + mht_node->physical_node_number = 1; + mht_node->logical_node_number = 0; + mht_node->need_writing = false; } static bool ipf_update_all_data_and_mht_nodes(pf_context_t* pf) { bool ret = false; - file_node_t** mht_array = NULL; + file_node_t** mht_nodes_array = NULL; pf_status_t status; // 1. encrypt the changed data nodes - // 2. set the key + GMAC in the parent MHT nodes + // 2. set the key + MAC in the parent MHT nodes // 3. set the need_writing flag for all the parent MHT nodes - for (void* data = lruc_get_first(pf->cache); data != NULL; data = lruc_get_next(pf->cache)) { - if (((file_node_t*)data)->type != FILE_DATA_NODE_TYPE) + for (void* node = lruc_get_first(pf->cache); node != NULL; node = lruc_get_next(pf->cache)) { + if (((file_node_t*)node)->type != FILE_DATA_NODE_TYPE) continue; - file_node_t* data_node = (file_node_t*)data; + file_node_t* data_node = (file_node_t*)node; if (!data_node->need_writing) continue; gcm_crypto_data_t* gcm_crypto_data = &data_node->parent->decrypted.mht - .data_nodes_crypto[data_node->node_number % ATTACHED_DATA_NODES_COUNT]; + .data_nodes_crypto[data_node->logical_node_number % ATTACHED_DATA_NODES_COUNT]; if (!ipf_generate_random_key(pf, &gcm_crypto_data->key)) goto out; - // encrypt data node, this also saves the gmac of the operation in the MHT node + // encrypt data node, this also saves MAC in the corresponding crypto slot of MHT node status = g_cb_aes_gcm_encrypt(&gcm_crypto_data->key, &g_empty_iv, NULL, 0, // aad - data_node->decrypted.data.data, PF_NODE_SIZE, - data_node->encrypted.cipher, &gcm_crypto_data->gmac); + &data_node->decrypted.data.bytes, PF_NODE_SIZE, + &data_node->encrypted.bytes, &gcm_crypto_data->mac); if (PF_FAILURE(status)) { pf->last_error = status; goto out; } #ifdef DEBUG - file_node_t* file_mht_node = data_node->parent; - while (file_mht_node->node_number != 0) { - assert(file_mht_node->need_writing == true); - file_mht_node = file_mht_node->parent; + file_node_t* mht_node = data_node->parent; + while (mht_node->logical_node_number != 0) { + assert(mht_node->need_writing == true); + mht_node = mht_node->parent; } #endif } - // count dirty mht nodes + // count dirty MHT nodes size_t dirty_count = 0; - for (void* data = lruc_get_first(pf->cache); data != NULL; data = lruc_get_next(pf->cache)) { - if (((file_node_t*)data)->type == FILE_MHT_NODE_TYPE) { - if (((file_node_t*)data)->need_writing) + for (void* node = lruc_get_first(pf->cache); node != NULL; node = lruc_get_next(pf->cache)) { + if (((file_node_t*)node)->type == FILE_MHT_NODE_TYPE) { + if (((file_node_t*)node)->need_writing) dirty_count++; } } - // add all the mht nodes that needs writing to a list - mht_array = malloc(dirty_count * sizeof(*mht_array)); - if (!mht_array) { + // add all the MHT nodes that need writing to a list + mht_nodes_array = malloc(dirty_count * sizeof(*mht_nodes_array)); + if (!mht_nodes_array) { pf->last_error = PF_STATUS_NO_MEMORY; goto out; } uint64_t dirty_idx = 0; - for (void* data = lruc_get_first(pf->cache); data != NULL; data = lruc_get_next(pf->cache)) { - if (((file_node_t*)data)->type == FILE_MHT_NODE_TYPE) { - file_node_t* file_mht_node = (file_node_t*)data; - - if (file_mht_node->need_writing) - mht_array[dirty_idx++] = file_mht_node; + for (void* node = lruc_get_first(pf->cache); node != NULL; node = lruc_get_next(pf->cache)) { + if (((file_node_t*)node)->type == FILE_MHT_NODE_TYPE) { + file_node_t* mht_node = (file_node_t*)node; + if (mht_node->need_writing) + mht_nodes_array[dirty_idx++] = mht_node; } } if (dirty_count > 0) - sort_nodes(mht_array, 0, dirty_count - 1); + sort_nodes(mht_nodes_array, 0, dirty_count - 1); - // update the gmacs in the parents from last node to first (bottom layers first) + // update the keys and MACs in the parents from last node to first (bottom layers first) for (dirty_idx = dirty_count; dirty_idx > 0; dirty_idx--) { - file_node_t* file_mht_node = mht_array[dirty_idx - 1]; + file_node_t* mht_node = mht_nodes_array[dirty_idx - 1]; gcm_crypto_data_t* gcm_crypto_data = - &file_mht_node->parent->decrypted.mht - .mht_nodes_crypto[(file_mht_node->node_number - 1) % CHILD_MHT_NODES_COUNT]; + &mht_node->parent->decrypted.mht + .mht_nodes_crypto[(mht_node->logical_node_number - 1) % CHILD_MHT_NODES_COUNT]; if (!ipf_generate_random_key(pf, &gcm_crypto_data->key)) goto out; status = g_cb_aes_gcm_encrypt(&gcm_crypto_data->key, &g_empty_iv, NULL, 0, - &file_mht_node->decrypted.mht, PF_NODE_SIZE, - &file_mht_node->encrypted.cipher, &gcm_crypto_data->gmac); + &mht_node->decrypted.mht, PF_NODE_SIZE, + &mht_node->encrypted.bytes, &gcm_crypto_data->mac); if (PF_FAILURE(status)) { pf->last_error = status; goto out; } } - // update mht root gmac in the meta data node - if (!ipf_generate_random_key(pf, &pf->encrypted_part_plain.mht_key)) + // update root MHT node's key and MAC in the metadata node's headers + if (!ipf_generate_random_key(pf, &pf->metadata_decrypted_header.root_mht_node_key)) goto out; - status = g_cb_aes_gcm_encrypt(&pf->encrypted_part_plain.mht_key, &g_empty_iv, + status = g_cb_aes_gcm_encrypt(&pf->metadata_decrypted_header.root_mht_node_key, &g_empty_iv, NULL, 0, - &pf->root_mht.decrypted.mht, PF_NODE_SIZE, - &pf->root_mht.encrypted.cipher, - &pf->encrypted_part_plain.mht_gmac); + &pf->root_mht_node.decrypted.mht, PF_NODE_SIZE, + &pf->root_mht_node.encrypted.bytes, + &pf->metadata_decrypted_header.root_mht_node_mac); if (PF_FAILURE(status)) { pf->last_error = status; goto out; @@ -306,14 +303,14 @@ static bool ipf_update_all_data_and_mht_nodes(pf_context_t* pf) { ret = true; out: - free(mht_array); + free(mht_nodes_array); return ret; } -static bool ipf_read_node(pf_context_t* pf, uint64_t node_number, void* buffer) { - uint64_t offset = node_number * PF_NODE_SIZE; +static bool ipf_read_node(pf_context_t* pf, uint64_t logical_node_number, void* buffer) { + uint64_t offset = logical_node_number * PF_NODE_SIZE; - pf_status_t status = g_cb_read(pf->file, buffer, offset, PF_NODE_SIZE); + pf_status_t status = g_cb_read(pf->host_file_handle, buffer, offset, PF_NODE_SIZE); if (PF_FAILURE(status)) { pf->last_error = status; return false; @@ -322,10 +319,10 @@ static bool ipf_read_node(pf_context_t* pf, uint64_t node_number, void* buffer) return true; } -static bool ipf_write_node(pf_context_t* pf, uint64_t node_number, void* buffer) { - uint64_t offset = node_number * PF_NODE_SIZE; +static bool ipf_write_node(pf_context_t* pf, uint64_t logical_node_number, void* buffer) { + uint64_t offset = logical_node_number * PF_NODE_SIZE; - pf_status_t status = g_cb_write(pf->file, buffer, offset, PF_NODE_SIZE); + pf_status_t status = g_cb_write(pf->host_file_handle, buffer, offset, PF_NODE_SIZE); if (PF_FAILURE(status)) { pf->last_error = status; return false; @@ -336,41 +333,42 @@ static bool ipf_write_node(pf_context_t* pf, uint64_t node_number, void* buffer) // this is a very 'specific' function, tied to the architecture of the file layout, // returning the node numbers according to the data offset in the file -static void get_node_numbers(uint64_t offset, uint64_t* mht_node_number, uint64_t* data_node_number, +static void get_node_numbers(uint64_t offset, uint64_t* logical_mht_node_number, + uint64_t* logical_data_node_number, uint64_t* physical_mht_node_number, uint64_t* physical_data_node_number) { // physical nodes (file layout): - // node 0 - meta data node - // node 1 - mht - // nodes 2-97 - data (ATTACHED_DATA_NODES_COUNT == 96) - // node 98 - mht - // node 99-195 - data + // node 0 - metadata node + // node 1 - root MHT node + // nodes 2-97 - data nodes (ATTACHED_DATA_NODES_COUNT == 96) + // node 98 - MHT node + // node 99-195 - data nodes // etc. uint64_t _physical_mht_node_number; uint64_t _physical_data_node_number; - // "logical" nodes: sequential index of the corresponding mht/data node in all mht/data nodes - uint64_t _mht_node_number; - uint64_t _data_node_number; + // "logical" nodes: sequential index of the corresponding MHT/data node in all MHT/data nodes + uint64_t _logical_mht_node_number; + uint64_t _logical_data_node_number; assert(offset >= MD_USER_DATA_SIZE); - _data_node_number = (offset - MD_USER_DATA_SIZE) / PF_NODE_SIZE; - _mht_node_number = _data_node_number / ATTACHED_DATA_NODES_COUNT; - _physical_data_node_number = _data_node_number + _logical_data_node_number = (offset - MD_USER_DATA_SIZE) / PF_NODE_SIZE; + _logical_mht_node_number = _logical_data_node_number / ATTACHED_DATA_NODES_COUNT; + _physical_data_node_number = _logical_data_node_number + 1 // meta data node - + 1 // mht root - + _mht_node_number; // number of mht nodes in the middle - // (the root mht mht_node_number is 0) + + 1 // MHT root node + + _logical_mht_node_number; // number of MHT nodes in the middle + // (the logical_mht_node_number of root MHT node is 0) _physical_mht_node_number = _physical_data_node_number - - _data_node_number % ATTACHED_DATA_NODES_COUNT // now we are at - // the first data node attached to this mht node - - 1; // and now at the mht node itself! - - if (mht_node_number != NULL) - *mht_node_number = _mht_node_number; - if (data_node_number != NULL) - *data_node_number = _data_node_number; + - _logical_data_node_number % ATTACHED_DATA_NODES_COUNT + // now we are at the first data node attached to this MHT node + - 1; // and now at the MHT node itself + + if (logical_mht_node_number != NULL) + *logical_mht_node_number = _logical_mht_node_number; + if (logical_data_node_number != NULL) + *logical_data_node_number = _logical_data_node_number; if (physical_mht_node_number != NULL) *physical_mht_node_number = _physical_mht_node_number; if (physical_data_node_number != NULL) @@ -378,37 +376,34 @@ static void get_node_numbers(uint64_t offset, uint64_t* mht_node_number, uint64_ } static bool ipf_write_all_changes_to_disk(pf_context_t* pf) { - if (pf->encrypted_part_plain.size > MD_USER_DATA_SIZE && pf->root_mht.need_writing) { - void* data = NULL; + if (pf->metadata_decrypted_header.file_size > MD_USER_DATA_SIZE + && pf->root_mht_node.need_writing) { uint8_t* data_to_write; - uint64_t node_number; - file_node_t* file_node; + uint64_t logical_node_number; - for (data = lruc_get_first(pf->cache); data != NULL; data = lruc_get_next(pf->cache)) { - file_node = (file_node_t*)data; + void* node; + for (node = lruc_get_first(pf->cache); node != NULL; node = lruc_get_next(pf->cache)) { + file_node_t* file_node = (file_node_t*)node; if (!file_node->need_writing) continue; data_to_write = (uint8_t*)&file_node->encrypted; - node_number = file_node->physical_node_number; + logical_node_number = file_node->physical_node_number; - if (!ipf_write_node(pf, node_number, data_to_write)) { + if (!ipf_write_node(pf, logical_node_number, data_to_write)) return false; - } file_node->need_writing = false; } - if (!ipf_write_node(pf, /*node_number=*/1, &pf->root_mht.encrypted)) { + if (!ipf_write_node(pf, /*logical_node_number=*/1, &pf->root_mht_node.encrypted)) return false; - } - pf->root_mht.need_writing = false; + pf->root_mht_node.need_writing = false; } - if (!ipf_write_node(pf, /*node_number=*/0, &pf->file_metadata)) { + if (!ipf_write_node(pf, /*logical_node_number=*/0, &pf->metadata_node)) return false; - } return true; } @@ -417,16 +412,17 @@ static bool ipf_update_metadata_node(pf_context_t* pf) { pf_status_t status; pf_key_t key; - // randomize a new key, saves the key _id_ in the meta data plain part + // new key for metadata node encryption, saves the key nonce in metadata plaintext header if (!ipf_generate_random_metadata_key(pf, &key)) { // last error already set return false; } - // encrypt meta data encrypted part, also updates the gmac in the meta data plain part - status = g_cb_aes_gcm_encrypt(&key, &g_empty_iv, NULL, 0, &pf->encrypted_part_plain, - sizeof(metadata_encrypted_t), &pf->file_metadata.encrypted_part, - &pf->file_metadata.plain_part.metadata_gmac); + // encrypt metadata part-to-be-encrypted, also updates the MAC in metadata plaintext header + status = g_cb_aes_gcm_encrypt(&key, &g_empty_iv, NULL, 0, &pf->metadata_decrypted_header, + sizeof(metadata_decrypted_header_t), + &pf->metadata_node.encrypted_blob, + &pf->metadata_node.plaintext_header.metadata_mac); if (PF_FAILURE(status)) { pf->last_error = status; return false; @@ -437,17 +433,16 @@ static bool ipf_update_metadata_node(pf_context_t* pf) { static bool ipf_internal_flush(pf_context_t* pf) { if (!pf->need_writing) { - // no changes at all DEBUG_PF("no need to write"); return true; } - if (pf->encrypted_part_plain.size > MD_USER_DATA_SIZE && pf->root_mht.need_writing) { - // otherwise it's just one write - the meta-data node + if (pf->metadata_decrypted_header.file_size > MD_USER_DATA_SIZE + && pf->root_mht_node.need_writing) { if (!ipf_update_all_data_and_mht_nodes(pf)) { // this is something that shouldn't happen, can't fix this... pf->file_status = PF_STATUS_CRYPTO_ERROR; - DEBUG_PF("failed to update data nodes"); + DEBUG_PF("failed to update data and MHT nodes"); return false; } } @@ -455,25 +450,23 @@ static bool ipf_internal_flush(pf_context_t* pf) { if (!ipf_update_metadata_node(pf)) { // this is something that shouldn't happen, can't fix this... pf->file_status = PF_STATUS_CRYPTO_ERROR; - DEBUG_PF("failed to update metadata nodes"); + DEBUG_PF("failed to update metadata node"); return false; } if (!ipf_write_all_changes_to_disk(pf)) { pf->file_status = PF_STATUS_WRITE_TO_DISK_FAILED; - DEBUG_PF("failed to write changes to disk"); return false; } pf->need_writing = false; - return true; } static file_node_t* ipf_get_mht_node(pf_context_t* pf, uint64_t offset) { - file_node_t* file_mht_node; - uint64_t mht_node_number; + file_node_t* mht_node; + uint64_t logical_mht_node_number; uint64_t physical_mht_node_number; if (offset < MD_USER_DATA_SIZE) { @@ -481,59 +474,55 @@ static file_node_t* ipf_get_mht_node(pf_context_t* pf, uint64_t offset) { return NULL; } - get_node_numbers(offset, &mht_node_number, NULL, &physical_mht_node_number, NULL); + get_node_numbers(offset, &logical_mht_node_number, NULL, &physical_mht_node_number, NULL); - if (mht_node_number == 0) - return &pf->root_mht; + if (logical_mht_node_number == 0) + return &pf->root_mht_node; - // file is constructed from (ATTACHED_DATA_NODES_COUNT + CHILD_MHT_NODES_COUNT) * PF_NODE_SIZE - // bytes per MHT node - if ((offset - MD_USER_DATA_SIZE) % (ATTACHED_DATA_NODES_COUNT * PF_NODE_SIZE) == 0 && - offset == pf->encrypted_part_plain.size) { - file_mht_node = ipf_append_mht_node(pf, mht_node_number); + if ((offset - MD_USER_DATA_SIZE) % (ATTACHED_DATA_NODES_COUNT * PF_NODE_SIZE) == 0 + && offset == pf->metadata_decrypted_header.file_size) { + mht_node = ipf_append_mht_node(pf, logical_mht_node_number); } else { - file_mht_node = ipf_read_mht_node(pf, mht_node_number); + mht_node = ipf_read_mht_node(pf, logical_mht_node_number); } - return file_mht_node; + return mht_node; } -static file_node_t* ipf_append_mht_node(pf_context_t* pf, uint64_t mht_node_number) { - assert(mht_node_number > 0); - file_node_t* parent_file_mht_node = - ipf_read_mht_node(pf, (mht_node_number - 1) / CHILD_MHT_NODES_COUNT); +static file_node_t* ipf_append_mht_node(pf_context_t* pf, uint64_t logical_mht_node_number) { + assert(logical_mht_node_number > 0); + file_node_t* parent_mht_node = + ipf_read_mht_node(pf, (logical_mht_node_number - 1) / CHILD_MHT_NODES_COUNT); - if (parent_file_mht_node == NULL) // some error happened + if (parent_mht_node == NULL) return NULL; uint64_t physical_node_number = 1 + // meta data node - // the '1' is for the mht node preceding every 96 data nodes - mht_node_number * (1 + ATTACHED_DATA_NODES_COUNT); + // the '1' is for the MHT node preceding every 96 data nodes + logical_mht_node_number * (1 + ATTACHED_DATA_NODES_COUNT); - file_node_t* new_file_mht_node = NULL; - new_file_mht_node = calloc(1, sizeof(*new_file_mht_node)); - if (!new_file_mht_node) { + file_node_t* new_mht_node = calloc(1, sizeof(*new_mht_node)); + if (!new_mht_node) { pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - new_file_mht_node->type = FILE_MHT_NODE_TYPE; - new_file_mht_node->parent = parent_file_mht_node; - new_file_mht_node->node_number = mht_node_number; - new_file_mht_node->physical_node_number = physical_node_number; + new_mht_node->type = FILE_MHT_NODE_TYPE; + new_mht_node->parent = parent_mht_node; + new_mht_node->logical_node_number = logical_mht_node_number; + new_mht_node->physical_node_number = physical_node_number; - if (!lruc_add(pf->cache, new_file_mht_node->physical_node_number, new_file_mht_node)) { - free(new_file_mht_node); + if (!lruc_add(pf->cache, new_mht_node->physical_node_number, new_mht_node)) { + free(new_mht_node); pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - return new_file_mht_node; + return new_mht_node; } - static file_node_t* ipf_get_data_node(pf_context_t* pf, uint64_t offset) { - file_node_t* file_data_node = NULL; + file_node_t* data_node = NULL; if (offset < MD_USER_DATA_SIZE) { pf->last_error = PF_STATUS_UNKNOWN_ERROR; @@ -541,39 +530,35 @@ static file_node_t* ipf_get_data_node(pf_context_t* pf, uint64_t offset) { } if ((offset - MD_USER_DATA_SIZE) % PF_NODE_SIZE == 0 - && offset == pf->encrypted_part_plain.size) { - // new node - file_data_node = ipf_append_data_node(pf, offset); + && offset == pf->metadata_decrypted_header.file_size) { + data_node = ipf_append_data_node(pf, offset); } else { - // existing node - file_data_node = ipf_read_data_node(pf, offset); + data_node = ipf_read_data_node(pf, offset); } - // bump all the parents mht to reside before the data node in the cache - if (file_data_node != NULL) { - file_node_t* file_mht_node = file_data_node->parent; - while (file_mht_node->node_number != 0) { - // bump the mht node to the head of the lru - lruc_get(pf->cache, file_mht_node->physical_node_number); - file_mht_node = file_mht_node->parent; + // bump all the parent MHT nodes to reside before the data node in the cache + if (data_node != NULL) { + file_node_t* mht_node = data_node->parent; + while (mht_node->logical_node_number != 0) { + // bump the MHT node to the head of the LRU + lruc_get(pf->cache, mht_node->physical_node_number); + mht_node = mht_node->parent; } } // even if we didn't get the required data_node, we might have read other nodes in the process while (lruc_size(pf->cache) > MAX_NODES_IN_CACHE) { - void* data = lruc_get_last(pf->cache); - assert(data != NULL); - // for production - - if (data == NULL) { + void* node = lruc_get_last(pf->cache); + if (node == NULL) { pf->last_error = PF_STATUS_UNKNOWN_ERROR; return NULL; } - if (!((file_node_t*)data)->need_writing) { + if (!((file_node_t*)node)->need_writing) { lruc_remove_last(pf->cache); // before deleting the memory, need to scrub the plain secrets - file_node_t* file_node = (file_node_t*)data; + file_node_t* file_node = (file_node_t*)node; erase_memory(&file_node->decrypted, sizeof(file_node->decrypted)); free(file_node); } else { @@ -587,172 +572,167 @@ static file_node_t* ipf_get_data_node(pf_context_t* pf, uint64_t offset) { } } - return file_data_node; + return data_node; } static file_node_t* ipf_append_data_node(pf_context_t* pf, uint64_t offset) { - file_node_t* file_mht_node = ipf_get_mht_node(pf, offset); - if (file_mht_node == NULL) // some error happened + file_node_t* mht_node = ipf_get_mht_node(pf, offset); + if (mht_node == NULL) return NULL; - file_node_t* new_file_data_node = NULL; - - new_file_data_node = calloc(1, sizeof(*new_file_data_node)); - if (!new_file_data_node) { + file_node_t* new_data_node = calloc(1, sizeof(*new_data_node)); + if (!new_data_node) { pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - uint64_t node_number, physical_node_number; - get_node_numbers(offset, NULL, &node_number, NULL, &physical_node_number); + uint64_t logical_node_number; + uint64_t physical_node_number; + get_node_numbers(offset, NULL, &logical_node_number, NULL, &physical_node_number); - new_file_data_node->type = FILE_DATA_NODE_TYPE; - new_file_data_node->parent = file_mht_node; - new_file_data_node->node_number = node_number; - new_file_data_node->physical_node_number = physical_node_number; + new_data_node->type = FILE_DATA_NODE_TYPE; + new_data_node->parent = mht_node; + new_data_node->logical_node_number = logical_node_number; + new_data_node->physical_node_number = physical_node_number; - if (!lruc_add(pf->cache, new_file_data_node->physical_node_number, new_file_data_node)) { - free(new_file_data_node); + if (!lruc_add(pf->cache, new_data_node->physical_node_number, new_data_node)) { + free(new_data_node); pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - return new_file_data_node; + return new_data_node; } static file_node_t* ipf_read_data_node(pf_context_t* pf, uint64_t offset) { - uint64_t data_node_number; - uint64_t physical_node_number; - file_node_t* file_mht_node; + file_node_t* mht_node; pf_status_t status; - get_node_numbers(offset, NULL, &data_node_number, NULL, &physical_node_number); + uint64_t logical_data_node_number; + uint64_t physical_node_number; + get_node_numbers(offset, NULL, &logical_data_node_number, NULL, &physical_node_number); - file_node_t* file_data_node = (file_node_t*)lruc_get(pf->cache, physical_node_number); - if (file_data_node != NULL) - return file_data_node; + file_node_t* data_node = (file_node_t*)lruc_get(pf->cache, physical_node_number); + if (data_node != NULL) + return data_node; // need to read the data node from the disk - - file_mht_node = ipf_get_mht_node(pf, offset); - if (file_mht_node == NULL) // some error happened + mht_node = ipf_get_mht_node(pf, offset); + if (mht_node == NULL) return NULL; - file_data_node = calloc(1, sizeof(*file_data_node)); - if (!file_data_node) { + data_node = calloc(1, sizeof(*data_node)); + if (!data_node) { pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - file_data_node->type = FILE_DATA_NODE_TYPE; - file_data_node->node_number = data_node_number; - file_data_node->physical_node_number = physical_node_number; - file_data_node->parent = file_mht_node; + data_node->type = FILE_DATA_NODE_TYPE; + data_node->parent = mht_node; + data_node->logical_node_number = logical_data_node_number; + data_node->physical_node_number = physical_node_number; - if (!ipf_read_node(pf, file_data_node->physical_node_number, - file_data_node->encrypted.cipher)) { - free(file_data_node); + if (!ipf_read_node(pf, data_node->physical_node_number, data_node->encrypted.bytes)) { + free(data_node); return NULL; } gcm_crypto_data_t* gcm_crypto_data = - &file_data_node->parent->decrypted.mht - .data_nodes_crypto[file_data_node->node_number % ATTACHED_DATA_NODES_COUNT]; + &data_node->parent->decrypted.mht + .data_nodes_crypto[data_node->logical_node_number % ATTACHED_DATA_NODES_COUNT]; - // this function decrypt the data _and_ checks the integrity of the data against the gmac + // decrypt data and check integrity against the MAC in corresponding slot in MHT node status = g_cb_aes_gcm_decrypt(&gcm_crypto_data->key, &g_empty_iv, NULL, 0, - file_data_node->encrypted.cipher, PF_NODE_SIZE, - file_data_node->decrypted.data.data, &gcm_crypto_data->gmac); + &data_node->encrypted.bytes, PF_NODE_SIZE, + &data_node->decrypted.data.bytes, &gcm_crypto_data->mac); if (PF_FAILURE(status)) { - free(file_data_node); + free(data_node); pf->last_error = status; if (status == PF_STATUS_MAC_MISMATCH) pf->file_status = PF_STATUS_CORRUPTED; return NULL; } - if (!lruc_add(pf->cache, file_data_node->physical_node_number, file_data_node)) { - // scrub the plaintext data - erase_memory(&file_data_node->decrypted, sizeof(file_data_node->decrypted)); - free(file_data_node); + if (!lruc_add(pf->cache, data_node->physical_node_number, data_node)) { + erase_memory(&data_node->decrypted, sizeof(data_node->decrypted)); + free(data_node); pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - return file_data_node; + return data_node; } -static file_node_t* ipf_read_mht_node(pf_context_t* pf, uint64_t mht_node_number) { +static file_node_t* ipf_read_mht_node(pf_context_t* pf, uint64_t logical_mht_node_number) { pf_status_t status; - if (mht_node_number == 0) - return &pf->root_mht; + if (logical_mht_node_number == 0) + return &pf->root_mht_node; uint64_t physical_node_number = 1 + // meta data node - // the '1' is for the mht node preceding every 96 data nodes - mht_node_number * (1 + ATTACHED_DATA_NODES_COUNT); + // the '1' is for the MHT node preceding every 96 data nodes + logical_mht_node_number * (1 + ATTACHED_DATA_NODES_COUNT); - file_node_t* file_mht_node = (file_node_t*)lruc_find(pf->cache, physical_node_number); - if (file_mht_node != NULL) - return file_mht_node; + file_node_t* mht_node = (file_node_t*)lruc_find(pf->cache, physical_node_number); + if (mht_node != NULL) + return mht_node; - file_node_t* parent_file_mht_node = - ipf_read_mht_node(pf, (mht_node_number - 1) / CHILD_MHT_NODES_COUNT); + file_node_t* parent_mht_node = + ipf_read_mht_node(pf, (logical_mht_node_number - 1) / CHILD_MHT_NODES_COUNT); - if (parent_file_mht_node == NULL) // some error happened + if (parent_mht_node == NULL) return NULL; - file_mht_node = calloc(1, sizeof(*file_mht_node)); - if (!file_mht_node) { + mht_node = calloc(1, sizeof(*mht_node)); + if (!mht_node) { pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - file_mht_node->type = FILE_MHT_NODE_TYPE; - file_mht_node->node_number = mht_node_number; - file_mht_node->physical_node_number = physical_node_number; - file_mht_node->parent = parent_file_mht_node; + mht_node->type = FILE_MHT_NODE_TYPE; + mht_node->parent = parent_mht_node; + mht_node->logical_node_number = logical_mht_node_number; + mht_node->physical_node_number = physical_node_number; - if (!ipf_read_node(pf, file_mht_node->physical_node_number, - file_mht_node->encrypted.cipher)) { - free(file_mht_node); + if (!ipf_read_node(pf, mht_node->physical_node_number, mht_node->encrypted.bytes)) { + free(mht_node); return NULL; } gcm_crypto_data_t* gcm_crypto_data = - &file_mht_node->parent->decrypted.mht - .mht_nodes_crypto[(file_mht_node->node_number - 1) % CHILD_MHT_NODES_COUNT]; + &mht_node->parent->decrypted.mht + .mht_nodes_crypto[(mht_node->logical_node_number - 1) % CHILD_MHT_NODES_COUNT]; - // this function decrypt the data _and_ checks the integrity of the data against the gmac + // decrypt data and check integrity against the MAC in corresponding slot in parent MHT node status = g_cb_aes_gcm_decrypt(&gcm_crypto_data->key, &g_empty_iv, NULL, 0, - file_mht_node->encrypted.cipher, PF_NODE_SIZE, - &file_mht_node->decrypted.mht, &gcm_crypto_data->gmac); + &mht_node->encrypted.bytes, PF_NODE_SIZE, + &mht_node->decrypted.mht, &gcm_crypto_data->mac); if (PF_FAILURE(status)) { - free(file_mht_node); + free(mht_node); pf->last_error = status; if (status == PF_STATUS_MAC_MISMATCH) pf->file_status = PF_STATUS_CORRUPTED; return NULL; } - if (!lruc_add(pf->cache, file_mht_node->physical_node_number, file_mht_node)) { - erase_memory(&file_mht_node->decrypted, sizeof(file_mht_node->decrypted)); - free(file_mht_node); + if (!lruc_add(pf->cache, mht_node->physical_node_number, mht_node)) { + erase_memory(&mht_node->decrypted, sizeof(mht_node->decrypted)); + free(mht_node); pf->last_error = PF_STATUS_NO_MEMORY; return NULL; } - return file_mht_node; + return mht_node; } static bool ipf_init_new_file(pf_context_t* pf, const char* path) { - pf->file_metadata.plain_part.file_id = PF_FILE_ID; - pf->file_metadata.plain_part.major_version = PF_MAJOR_VERSION; - pf->file_metadata.plain_part.minor_version = PF_MINOR_VERSION; + pf->metadata_node.plaintext_header.file_id = PF_FILE_ID; + pf->metadata_node.plaintext_header.major_version = PF_MAJOR_VERSION; + pf->metadata_node.plaintext_header.minor_version = PF_MINOR_VERSION; // path length is checked in ipf_open() - memcpy(pf->encrypted_part_plain.path, path, strlen(path) + 1); + memcpy(pf->metadata_decrypted_header.file_path, path, strlen(path) + 1); pf->need_writing = true; if (!ipf_internal_flush(pf)) @@ -769,16 +749,16 @@ static bool ipf_init_fields(pf_context_t* pf) { return false; } #endif - memset(&pf->file_metadata, 0, sizeof(pf->file_metadata)); - memset(&pf->encrypted_part_plain, 0, sizeof(pf->encrypted_part_plain)); + memset(&pf->metadata_node, 0, sizeof(pf->metadata_node)); + memset(&pf->metadata_decrypted_header, 0, sizeof(pf->metadata_decrypted_header)); memset(&g_empty_iv, 0, sizeof(g_empty_iv)); - ipf_init_root_mht(&pf->root_mht); + ipf_init_root_mht_node(&pf->root_mht_node); - pf->file = NULL; - pf->need_writing = false; - pf->file_status = PF_STATUS_UNINITIALIZED; - pf->last_error = PF_STATUS_SUCCESS; + pf->host_file_handle = NULL; + pf->need_writing = false; + pf->file_status = PF_STATUS_UNINITIALIZED; + pf->last_error = PF_STATUS_SUCCESS; pf->cache = lruc_create(); return true; @@ -788,59 +768,59 @@ static bool ipf_init_existing_file(pf_context_t* pf, const char* path) { pf_status_t status; // read meta-data node - if (!ipf_read_node(pf, /*node_number=*/0, (uint8_t*)&pf->file_metadata)) { + if (!ipf_read_node(pf, /*logical_node_number=*/0, (uint8_t*)&pf->metadata_node)) { return false; } - if (pf->file_metadata.plain_part.file_id != PF_FILE_ID) { + if (pf->metadata_node.plaintext_header.file_id != PF_FILE_ID) { // such a file exists, but it is not a protected file pf->last_error = PF_STATUS_INVALID_HEADER; return false; } - if (pf->file_metadata.plain_part.major_version != PF_MAJOR_VERSION) { + if (pf->metadata_node.plaintext_header.major_version != PF_MAJOR_VERSION) { pf->last_error = PF_STATUS_INVALID_VERSION; return false; } pf_key_t key; - if (!ipf_restore_current_metadata_key(pf, &key)) + if (!ipf_generate_nonced_metadata_key(pf, &key)) return false; - // decrypt the encrypted part of the meta-data + // decrypt the encrypted part of the metadata node status = g_cb_aes_gcm_decrypt(&key, &g_empty_iv, NULL, 0, - &pf->file_metadata.encrypted_part, - sizeof(pf->file_metadata.encrypted_part), - &pf->encrypted_part_plain, - &pf->file_metadata.plain_part.metadata_gmac); + &pf->metadata_node.encrypted_blob, + sizeof(pf->metadata_node.encrypted_blob), + &pf->metadata_decrypted_header, + &pf->metadata_node.plaintext_header.metadata_mac); if (PF_FAILURE(status)) { pf->last_error = status; DEBUG_PF("failed to decrypt metadata: %d", status); return false; } - DEBUG_PF("data size %lu", pf->encrypted_part_plain.size); + DEBUG_PF("data size %lu", pf->metadata_decrypted_header.file_size); if (path) { - size_t path_len = strlen(pf->encrypted_part_plain.path); + size_t path_len = strlen(pf->metadata_decrypted_header.file_path); if (path_len != strlen(path) - || memcmp(path, pf->encrypted_part_plain.path, path_len) != 0) { + || memcmp(path, pf->metadata_decrypted_header.file_path, path_len) != 0) { pf->last_error = PF_STATUS_INVALID_PATH; return false; } } - if (pf->encrypted_part_plain.size > MD_USER_DATA_SIZE) { - // read the root node of the mht - if (!ipf_read_node(pf, /*node_number=*/1, &pf->root_mht.encrypted.cipher)) + if (pf->metadata_decrypted_header.file_size > MD_USER_DATA_SIZE) { + // read the root MHT node + if (!ipf_read_node(pf, /*logical_node_number=*/1, &pf->root_mht_node.encrypted.bytes)) return false; - // this also verifies the root mht gmac against the gmac in the meta-data encrypted part - status = g_cb_aes_gcm_decrypt(&pf->encrypted_part_plain.mht_key, &g_empty_iv, + // also verifies root MHT node's MAC against the MAC in metadata node's decrypted header + status = g_cb_aes_gcm_decrypt(&pf->metadata_decrypted_header.root_mht_node_key, &g_empty_iv, NULL, 0, // aad - &pf->root_mht.encrypted.cipher, PF_NODE_SIZE, - &pf->root_mht.decrypted.mht, - &pf->encrypted_part_plain.mht_gmac); + &pf->root_mht_node.encrypted.bytes, PF_NODE_SIZE, + &pf->root_mht_node.decrypted.mht, + &pf->metadata_decrypted_header.root_mht_node_mac); if (PF_FAILURE(status)) { pf->last_error = status; return false; @@ -850,7 +830,6 @@ static bool ipf_init_existing_file(pf_context_t* pf, const char* path) { return true; } - static void ipf_try_clear_error(pf_context_t* pf) { if (pf->file_status == PF_STATUS_UNINITIALIZED || pf->file_status == PF_STATUS_CRYPTO_ERROR || @@ -877,7 +856,6 @@ static void ipf_try_clear_error(pf_context_t* pf) { } } - static pf_context_t* ipf_open(const char* path, pf_file_mode_t mode, bool create, pf_handle_t file, uint64_t real_size, const pf_key_t* kdk_key, pf_status_t* status) { *status = PF_STATUS_NO_MEMORY; @@ -903,13 +881,7 @@ static pf_context_t* ipf_open(const char* path, pf_file_mode_t mode, bool create goto out; } - // for new file, this value will later be saved in the meta data plain part (init_new_file) - // for existing file, we will later compare this value with the value from the file - // (init_existing_file) - COPY_ARRAY(pf->user_kdk_key, *kdk_key); - - // omeg: we require a canonical full path to file, so no stripping path to filename only - // omeg: Intel's implementation opens the file, we get the fd and size from the Gramine handler + COPY_ARRAY(pf->kdk, *kdk_key); if (!file) { DEBUG_PF("invalid handle"); @@ -922,22 +894,20 @@ static pf_context_t* ipf_open(const char* path, pf_file_mode_t mode, bool create goto out; } - pf->file = file; + pf->host_file_handle = file; pf->mode = mode; if (!create) { - // existing file if (!ipf_init_existing_file(pf, path)) goto out; } else { - // new file if (!ipf_init_new_file(pf, path)) goto out; } pf->last_error = pf->file_status = PF_STATUS_SUCCESS; - DEBUG_PF("OK (data size %lu)", pf->encrypted_part_plain.size); + DEBUG_PF("OK (data size %lu)", pf->metadata_decrypted_header.file_size); out: if (pf) @@ -968,46 +938,44 @@ static bool ipf_check_writable(pf_context_t* pf) { return true; } -// write zeros if `ptr` is NULL +// writes zeros if `ptr` is NULL static size_t ipf_write(pf_context_t* pf, const void* ptr, uint64_t offset, size_t size) { if (size == 0) { pf->last_error = PF_STATUS_INVALID_PARAMETER; return 0; } - size_t data_left_to_write = size; - - if (!ipf_check_writable(pf)) { + if (!ipf_check_writable(pf)) return 0; - } + size_t data_left_to_write = size; const unsigned char* data_to_write = (const unsigned char*)ptr; - // the first block of user data is written in the meta-data encrypted part + // the first 3KB of user data is written in the metadata node's encrypted part if (offset < MD_USER_DATA_SIZE) { // offset is smaller than MD_USER_DATA_SIZE size_t empty_place_left_in_md = MD_USER_DATA_SIZE - (size_t)offset; size_t size_to_write = MIN(data_left_to_write, empty_place_left_in_md); - memcpy_or_zero_initialize(&pf->encrypted_part_plain.data[offset], data_to_write, + memcpy_or_zero_initialize(&pf->metadata_decrypted_header.file_data[offset], data_to_write, size_to_write); offset += size_to_write; if (data_to_write) data_to_write += size_to_write; data_left_to_write -= size_to_write; - if (offset > pf->encrypted_part_plain.size) - pf->encrypted_part_plain.size = offset; // file grew, update the new file size + if (offset > pf->metadata_decrypted_header.file_size) + pf->metadata_decrypted_header.file_size = offset; // file grew, update the new file size pf->need_writing = true; } while (data_left_to_write > 0) { - file_node_t* file_data_node = NULL; + file_node_t* data_node = NULL; // return the data node of the current offset, will read it from disk or create new one - // if needed (and also the mht node if needed) - file_data_node = ipf_get_data_node(pf, offset); - if (file_data_node == NULL) { + // if needed (and also the MHT node(s) if needed) + data_node = ipf_get_data_node(pf, offset); + if (data_node == NULL) { DEBUG_PF("failed to get data node"); break; } @@ -1016,26 +984,26 @@ static size_t ipf_write(pf_context_t* pf, const void* ptr, uint64_t offset, size size_t empty_place_left_in_node = PF_NODE_SIZE - offset_in_node; size_t size_to_write = MIN(data_left_to_write, empty_place_left_in_node); - memcpy_or_zero_initialize(&file_data_node->decrypted.data.data[offset_in_node], + memcpy_or_zero_initialize(&data_node->decrypted.data.bytes[offset_in_node], data_to_write, size_to_write); offset += size_to_write; if (data_to_write) data_to_write += size_to_write; data_left_to_write -= size_to_write; - if (offset > pf->encrypted_part_plain.size) { - pf->encrypted_part_plain.size = offset; // file grew, update the new file size + if (offset > pf->metadata_decrypted_header.file_size) { + pf->metadata_decrypted_header.file_size = offset; // file grew, update the new file size } - if (!file_data_node->need_writing) { - file_data_node->need_writing = true; - file_node_t* file_mht_node = file_data_node->parent; - while (file_mht_node->node_number != 0) { - // set all the mht parent nodes as 'need writing' - file_mht_node->need_writing = true; - file_mht_node = file_mht_node->parent; + if (!data_node->need_writing) { + data_node->need_writing = true; + file_node_t* mht_node = data_node->parent; + while (mht_node->logical_node_number != 0) { + // set all the MHT parent nodes as 'need writing' + mht_node->need_writing = true; + mht_node = mht_node->parent; } - pf->root_mht.need_writing = true; + pf->root_mht_node.need_writing = true; pf->need_writing = true; } } @@ -1061,9 +1029,10 @@ static size_t ipf_read(pf_context_t* pf, void* ptr, uint64_t offset, size_t size size_t data_left_to_read = size; - if (((uint64_t)data_left_to_read) > (uint64_t)(pf->encrypted_part_plain.size - offset)) { + if (((uint64_t)data_left_to_read) > + (uint64_t)(pf->metadata_decrypted_header.file_size - offset)) { // the request is bigger than what's left in the file - data_left_to_read = (size_t)(pf->encrypted_part_plain.size - offset); + data_left_to_read = (size_t)(pf->metadata_decrypted_header.file_size - offset); } // used at the end to return how much we actually read @@ -1071,31 +1040,30 @@ static size_t ipf_read(pf_context_t* pf, void* ptr, uint64_t offset, size_t size unsigned char* out_buffer = (unsigned char*)ptr; - // the first block of user data is read from the meta-data encrypted part + // the first 3KB of user data is read from the metadata node's encrypted part if (offset < MD_USER_DATA_SIZE) { - // offset is smaller than MD_USER_DATA_SIZE size_t data_left_in_md = MD_USER_DATA_SIZE - (size_t)offset; size_t size_to_read = MIN(data_left_to_read, data_left_in_md); - memcpy(out_buffer, &pf->encrypted_part_plain.data[offset], size_to_read); + memcpy(out_buffer, &pf->metadata_decrypted_header.file_data[offset], size_to_read); offset += size_to_read; out_buffer += size_to_read; data_left_to_read -= size_to_read; } while (data_left_to_read > 0) { - file_node_t* file_data_node = NULL; + file_node_t* data_node = NULL; // return the data node of the current offset, will read it from disk if needed - // (and also the mht node if needed) - file_data_node = ipf_get_data_node(pf, offset); - if (file_data_node == NULL) + // (and also the MHT node(s) if needed) + data_node = ipf_get_data_node(pf, offset); + if (data_node == NULL) break; uint64_t offset_in_node = (offset - MD_USER_DATA_SIZE) % PF_NODE_SIZE; size_t data_left_in_node = PF_NODE_SIZE - offset_in_node; size_t size_to_read = MIN(data_left_to_read, data_left_in_node); - memcpy(out_buffer, &file_data_node->decrypted.data.data[offset_in_node], size_to_read); + memcpy(out_buffer, &data_node->decrypted.data.bytes[offset_in_node], size_to_read); offset += size_to_read; out_buffer += size_to_read; data_left_to_read -= size_to_read; @@ -1105,9 +1073,9 @@ static size_t ipf_read(pf_context_t* pf, void* ptr, uint64_t offset, size_t size } static void ipf_delete_cache(pf_context_t* pf) { - void* data; - while ((data = lruc_get_last(pf->cache)) != NULL) { - file_node_t* file_node = (file_node_t*)data; + void* node; + while ((node = lruc_get_last(pf->cache)) != NULL) { + file_node_t* file_node = (file_node_t*)node; erase_memory(&file_node->decrypted, sizeof(file_node->decrypted)); free(file_node); lruc_remove_last(pf->cache); @@ -1132,8 +1100,7 @@ static bool ipf_close(pf_context_t* pf) { ipf_delete_cache(pf); - // scrub first MD_USER_DATA_SIZE of file data and the gmac_key - erase_memory(&pf->encrypted_part_plain, sizeof(pf->encrypted_part_plain)); + erase_memory(&pf->metadata_decrypted_header, sizeof(pf->metadata_decrypted_header)); lruc_destroy(pf->cache); @@ -1192,7 +1159,7 @@ pf_status_t pf_get_size(pf_context_t* pf, uint64_t* size) { if (!g_initialized) return PF_STATUS_UNINITIALIZED; - *size = pf->encrypted_part_plain.size; + *size = pf->metadata_decrypted_header.file_size; return PF_STATUS_SUCCESS; } @@ -1203,12 +1170,11 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size) { if (!(pf->mode & PF_FILE_MODE_WRITE)) return PF_STATUS_INVALID_MODE; - if (size == pf->encrypted_part_plain.size) + if (size == pf->metadata_decrypted_header.file_size) return PF_STATUS_SUCCESS; - if (size > pf->encrypted_part_plain.size) { - // Extend the file. - uint64_t offset = pf->encrypted_part_plain.size; + if (size > pf->metadata_decrypted_header.file_size) { + uint64_t offset = pf->metadata_decrypted_header.file_size; DEBUG_PF("extending the file from %lu to %lu", offset, size); if (ipf_write(pf, NULL, offset, size - offset) != size - offset) return pf->last_error; @@ -1219,7 +1185,7 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size) { // Truncation. // The structure of the protected file is such that we can simply truncate - // the file after the last data block belonging to still-used data. + // the file after the last data node belonging to still-used data. // Some MHT entries will be left with dangling data describing the truncated // nodes, but this is not a problem since they will be unused, and will be // overwritten with new data when the relevant nodes get allocated again. @@ -1239,12 +1205,12 @@ pf_status_t pf_set_size(pf_context_t* pf, uint64_t size) { get_node_numbers(size - 1, NULL, NULL, NULL, &physical_node_number); new_file_size = (physical_node_number + 1) * PF_NODE_SIZE; } - pf_status_t status = g_cb_truncate(pf->file, new_file_size); + pf_status_t status = g_cb_truncate(pf->host_file_handle, new_file_size); if (PF_FAILURE(status)) return status; // If successfully truncated, update our bookkeeping. - pf->encrypted_part_plain.size = size; - pf->need_writing = true; + pf->metadata_decrypted_header.file_size = size; + pf->need_writing = true; return PF_STATUS_SUCCESS; } @@ -1259,8 +1225,9 @@ pf_status_t pf_rename(pf_context_t* pf, const char* new_path) { if (new_path_size > PATH_MAX_SIZE) return PF_STATUS_PATH_TOO_LONG; - memset(pf->encrypted_part_plain.path, 0, sizeof(pf->encrypted_part_plain.path)); - memcpy(pf->encrypted_part_plain.path, new_path, new_path_size); + memset(pf->metadata_decrypted_header.file_path, 0, + sizeof(pf->metadata_decrypted_header.file_path)); + memcpy(pf->metadata_decrypted_header.file_path, new_path, new_path_size); pf->need_writing = true; if (!ipf_internal_flush(pf)) return pf->last_error; @@ -1283,7 +1250,7 @@ pf_status_t pf_read(pf_context_t* pf, uint64_t offset, size_t size, void* output return pf->last_error; } - if (offset >= pf->encrypted_part_plain.size) { + if (offset >= pf->metadata_decrypted_header.file_size) { *bytes_read = 0; return PF_STATUS_SUCCESS; } @@ -1303,7 +1270,7 @@ pf_status_t pf_write(pf_context_t* pf, uint64_t offset, size_t size, const void* if (!ipf_check_writable(pf)) return pf->last_error; - if (offset > pf->encrypted_part_plain.size) { + if (offset > pf->metadata_decrypted_header.file_size) { pf_status_t ret = pf_set_size(pf, offset); if (!PF_SUCCESS(ret)) { pf->last_error = ret; @@ -1329,7 +1296,7 @@ pf_status_t pf_flush(pf_context_t* pf) { * the app issues an actual fsync()/fdatasync() syscalls. The internal `ipf_internal_flush()` is * more broadly used: it's called when file contents must be flushed to the host OS (e.g. during * the rename operation). */ - pf_status_t status = g_cb_fsync(pf->file); + pf_status_t status = g_cb_fsync(pf->host_file_handle); if (PF_FAILURE(status)) { pf->last_error = status; return pf->last_error; diff --git a/common/src/protected_files/protected_files.h b/common/src/protected_files/protected_files.h index 207c3c8fb9..4bebe71a5c 100644 --- a/common/src/protected_files/protected_files.h +++ b/common/src/protected_files/protected_files.h @@ -14,22 +14,22 @@ #define PF_NODE_SIZE 4096U -/*! Size of the AES-GCM encryption key */ -#define PF_KEY_SIZE 16 - /*! Size of IV for AES-GCM */ #define PF_IV_SIZE 12 /*! Size of MAC fields */ #define PF_MAC_SIZE 16 +/*! Size of the AES-GCM encryption key */ +#define PF_KEY_SIZE 16 + /*! Size of the nonce used in KDF (Key Derivation Function) */ #define PF_NONCE_SIZE 32 typedef uint8_t pf_iv_t[PF_IV_SIZE]; typedef uint8_t pf_mac_t[PF_MAC_SIZE]; typedef uint8_t pf_key_t[PF_KEY_SIZE]; -typedef uint8_t pf_keyid_t[PF_NONCE_SIZE]; +typedef uint8_t pf_nonce_t[PF_NONCE_SIZE]; typedef enum _pf_status_t { PF_STATUS_SUCCESS = 0, diff --git a/common/src/protected_files/protected_files_format.h b/common/src/protected_files/protected_files_format.h index cef53c6bf4..38b4816284 100644 --- a/common/src/protected_files/protected_files_format.h +++ b/common/src/protected_files/protected_files_format.h @@ -38,42 +38,44 @@ enum { FILE_DATA_NODE_TYPE = 2, }; -typedef struct _data_node_crypto { +typedef struct _gcm_crypto_data { pf_key_t key; - pf_mac_t gmac; + pf_mac_t mac; } gcm_crypto_data_t; // for PF_NODE_SIZE == 4096, we have 96 attached data nodes and 32 mht child nodes +// 3/4 of the node is dedicated to data nodes, 1/4 to MHT nodes #define ATTACHED_DATA_NODES_COUNT ((PF_NODE_SIZE / sizeof(gcm_crypto_data_t)) * 3 / 4) #define CHILD_MHT_NODES_COUNT ((PF_NODE_SIZE / sizeof(gcm_crypto_data_t)) * 1 / 4) static_assert(ATTACHED_DATA_NODES_COUNT == 96, "ATTACHED_DATA_NODES_COUNT"); static_assert(CHILD_MHT_NODES_COUNT == 32, "CHILD_MHT_NODES_COUNT"); -typedef struct _metadata_plain { +typedef struct _metadata_plaintext_header { uint64_t file_id; uint8_t major_version; uint8_t minor_version; - pf_keyid_t metadata_key_id; - pf_mac_t metadata_gmac; /* GCM mac */ -} metadata_plain_t; + pf_nonce_t metadata_key_nonce; + pf_mac_t metadata_mac; /* GCM mac */ +} metadata_plaintext_header_t; -typedef struct _metadata_encrypted { - char path[PATH_MAX_SIZE]; - uint64_t size; - pf_key_t mht_key; - pf_mac_t mht_gmac; - uint8_t data[MD_USER_DATA_SIZE]; -} metadata_encrypted_t; +typedef struct _metadata_decrypted_header { + char file_path[PATH_MAX_SIZE]; + uint64_t file_size; + pf_key_t root_mht_node_key; + pf_mac_t root_mht_node_mac; + uint8_t file_data[MD_USER_DATA_SIZE]; +} metadata_decrypted_header_t; -typedef uint8_t metadata_encrypted_blob_t[sizeof(metadata_encrypted_t)]; +typedef uint8_t metadata_encrypted_blob_t[sizeof(metadata_decrypted_header_t)]; typedef uint8_t metadata_padding_t[PF_NODE_SIZE - - (sizeof(metadata_plain_t) + sizeof(metadata_encrypted_blob_t))]; + (sizeof(metadata_plaintext_header_t) + + sizeof(metadata_encrypted_blob_t))]; typedef struct _metadata_node { - metadata_plain_t plain_part; - metadata_encrypted_blob_t encrypted_part; - metadata_padding_t padding; + metadata_plaintext_header_t plaintext_header; + metadata_encrypted_blob_t encrypted_blob; + metadata_padding_t padding; } metadata_node_t; static_assert(sizeof(metadata_node_t) == PF_NODE_SIZE, "sizeof(metadata_node_t)"); @@ -84,12 +86,12 @@ typedef struct _mht_node { static_assert(sizeof(mht_node_t) == PF_NODE_SIZE, "sizeof(mht_node_t)"); typedef struct _data_node { - uint8_t data[PF_NODE_SIZE]; + uint8_t bytes[PF_NODE_SIZE]; } data_node_t; static_assert(sizeof(data_node_t) == PF_NODE_SIZE, "sizeof(data_node_t)"); typedef struct _encrypted_node { - uint8_t cipher[PF_NODE_SIZE]; + uint8_t bytes[PF_NODE_SIZE]; } encrypted_node_t; static_assert(sizeof(encrypted_node_t) == PF_NODE_SIZE, "sizeof(encrypted_node_t)"); @@ -103,7 +105,7 @@ typedef struct _file_node { bool need_writing; struct _file_node* parent; - uint64_t node_number; + uint64_t logical_node_number; uint64_t physical_node_number; encrypted_node_t encrypted; // encrypted data from storage (bounce buffer) @@ -117,7 +119,7 @@ typedef struct _file_node { typedef struct { uint32_t counter; // always "1" char label[MAX_LABEL_SIZE]; // must be NULL terminated - pf_keyid_t nonce; // nonce for key derivation from KDK, stored in metadata node + pf_nonce_t nonce; // nonce for key derivation from KDK, stored in metadata node uint32_t output_len; // in bits; always 128 } kdf_input_t; diff --git a/common/src/protected_files/protected_files_internal.h b/common/src/protected_files/protected_files_internal.h index 6193681bbb..1f48cac14b 100644 --- a/common/src/protected_files/protected_files_internal.h +++ b/common/src/protected_files/protected_files_internal.h @@ -13,22 +13,22 @@ #include "protected_files_format.h" struct pf_context { - pf_handle_t file; // opaque file handle (e.g. PAL handle) used by callbacks - pf_file_mode_t mode; // read-only, write-only or read-write - bool need_writing; // whether file was modified and thus needs writing to storage + pf_handle_t host_file_handle; // opaque file handle (e.g. PAL handle) used by callbacks + pf_file_mode_t mode; // read-only, write-only or read-write + bool need_writing; // whether file was modified and thus needs writing to storage - pf_status_t file_status; // PF_STATUS_SUCCESS, PF_STATUS_CRYPTO_ERROR, etc. - pf_status_t last_error; // FIXME: unclear why this is needed + pf_status_t file_status; // PF_STATUS_SUCCESS, PF_STATUS_CRYPTO_ERROR, etc. + pf_status_t last_error; // FIXME: unclear why this is needed - pf_key_t user_kdk_key; // KDK installed by user of PF (e.g. from Gramine manifest) + pf_key_t kdk; // KDK installed by user of PF (e.g. from Gramine manifest) - metadata_node_t file_metadata; // plaintext and encrypted metadata from storage (bounce buffer) - metadata_encrypted_t encrypted_part_plain; // contains file path, size, etc. + metadata_node_t metadata_node; // plaintext and encrypted metadata from storage (bounce buffer) + metadata_decrypted_header_t metadata_decrypted_header; // contains file path, size, etc. - file_node_t root_mht; // root MHT node is needed for files bigger than 3KB + file_node_t root_mht_node; // root MHT node is always needed (for files bigger than 3KB) - lruc_context_t* cache; // up to MAX_NODES_IN_CACHE nodes are cached for each file + lruc_context_t* cache; // up to MAX_NODES_IN_CACHE nodes are cached for each file #ifdef DEBUG - char* debug_buffer; // buffer for debug output + char* debug_buffer; // buffer for debug output #endif }; diff --git a/tools/sgx/pf_tamper/pf_tamper.c b/tools/sgx/pf_tamper/pf_tamper.c index 5dc7b10ed4..b5c3881f16 100644 --- a/tools/sgx/pf_tamper/pf_tamper.c +++ b/tools/sgx/pf_tamper/pf_tamper.c @@ -58,13 +58,13 @@ pf_key_t g_meta_key; static pf_iv_t g_empty_iv = {0}; -static void derive_main_key(const pf_key_t* kdk, const pf_keyid_t* key_id, pf_key_t* out_key) { +static void derive_main_key(const pf_key_t* kdk, const pf_nonce_t* nonce, pf_key_t* out_key) { kdf_input_t buf = {0}; pf_status_t status; buf.counter = 1; strncpy(buf.label, METADATA_KEY_NAME, MAX_LABEL_SIZE); - COPY_ARRAY(buf.nonce, *key_id); + COPY_ARRAY(buf.nonce, *nonce); buf.output_len = 0x80; status = mbedtls_aes_cmac(kdk, &buf, sizeof(buf), out_key); @@ -79,8 +79,8 @@ static void make_output_path(const char* suffix) { /* PF layout (node size is PF_NODE_SIZE): * - Node 0: metadata (metadata_node_t) - * - metadata_plain_t - * - metadata_encrypted_t (may include MD_USER_DATA_SIZE bytes of data) + * - metadata_plaintext_header_t + * - metadata_decrypted_header_t (may include MD_USER_DATA_SIZE bytes of data) * - metadata_padding_t * - Node 1: MHT (mht_node_t) * - Node 2-97: data (ATTACHED_DATA_NODES_COUNT == 96) @@ -111,66 +111,79 @@ static void truncate_file(const char* suffix, size_t output_size) { #define DATA_CRYPTO_SIZE (FIELD_SIZEOF(mht_node_t, data_nodes_crypto)) static void tamper_truncate(void) { - size_t mdps = sizeof(metadata_plain_t); - DBG("size(metadata_plain_t) = 0x%04lx\n", sizeof(metadata_plain_t)); - DBG("metadata_plain_t.file_id : 0x%04lx (0x%04lx)\n", - offsetof(metadata_plain_t, file_id), FIELD_SIZEOF(metadata_plain_t, file_id)); - DBG("metadata_plain_t.major_version : 0x%04lx (0x%04lx)\n", - offsetof(metadata_plain_t, major_version), FIELD_SIZEOF(metadata_plain_t, major_version)); - DBG("metadata_plain_t.minor_version : 0x%04lx (0x%04lx)\n", - offsetof(metadata_plain_t, minor_version), FIELD_SIZEOF(metadata_plain_t, minor_version)); - DBG("metadata_plain_t.metadata_key_id : 0x%04lx (0x%04lx)\n", - offsetof(metadata_plain_t, metadata_key_id), - FIELD_SIZEOF(metadata_plain_t, metadata_key_id)); - DBG("metadata_plain_t.metadata_gmac : 0x%04lx (0x%04lx)\n", - offsetof(metadata_plain_t, metadata_gmac), - FIELD_SIZEOF(metadata_plain_t, metadata_gmac)); - - DBG("size(metadata_encrypted_t) = 0x%04lx\n", sizeof(metadata_encrypted_t)); - DBG("metadata_encrypted_t.path : 0x%04lx (0x%04lx)\n", - mdps + offsetof(metadata_encrypted_t, path), - FIELD_SIZEOF(metadata_encrypted_t, path)); - DBG("metadata_encrypted_t.size : 0x%04lx (0x%04lx)\n", - mdps + offsetof(metadata_encrypted_t, size), FIELD_SIZEOF(metadata_encrypted_t, size)); - DBG("metadata_encrypted_t.mht_key : 0x%04lx (0x%04lx)\n", - mdps + offsetof(metadata_encrypted_t, mht_key), - FIELD_SIZEOF(metadata_encrypted_t, mht_key)); - DBG("metadata_encrypted_t.mht_gmac : 0x%04lx (0x%04lx)\n", - mdps + offsetof(metadata_encrypted_t, mht_gmac), - FIELD_SIZEOF(metadata_encrypted_t, mht_gmac)); - DBG("metadata_encrypted_t.data : 0x%04lx (0x%04lx)\n", - mdps + offsetof(metadata_encrypted_t, data), FIELD_SIZEOF(metadata_encrypted_t, data)); + size_t mdps = sizeof(metadata_plaintext_header_t); + DBG("size(metadata_plaintext_header_t) = 0x%04lx\n", + sizeof(metadata_plaintext_header_t)); + DBG("metadata_plaintext_header_t.file_id : 0x%04lx (0x%04lx)\n", + offsetof(metadata_plaintext_header_t, file_id), + FIELD_SIZEOF(metadata_plaintext_header_t, file_id)); + DBG("metadata_plaintext_header_t.major_version : 0x%04lx (0x%04lx)\n", + offsetof(metadata_plaintext_header_t, major_version), + FIELD_SIZEOF(metadata_plaintext_header_t, major_version)); + DBG("metadata_plaintext_header_t.minor_version : 0x%04lx (0x%04lx)\n", + offsetof(metadata_plaintext_header_t, minor_version), + FIELD_SIZEOF(metadata_plaintext_header_t, minor_version)); + DBG("metadata_plaintext_header_t.metadata_key_nonce : 0x%04lx (0x%04lx)\n", + offsetof(metadata_plaintext_header_t, metadata_key_nonce), + FIELD_SIZEOF(metadata_plaintext_header_t, metadata_key_nonce)); + DBG("metadata_plaintext_header_t.metadata_key_nonce : 0x%04lx (0x%04lx)\n", + offsetof(metadata_plaintext_header_t, metadata_key_nonce), + FIELD_SIZEOF(metadata_plaintext_header_t, metadata_key_nonce)); + + DBG("size(metadata_decrypted_header_t) = 0x%04lx\n", + sizeof(metadata_decrypted_header_t)); + DBG("metadata_decrypted_header_t.file_path : 0x%04lx (0x%04lx)\n", + mdps + offsetof(metadata_decrypted_header_t, file_path), + FIELD_SIZEOF(metadata_decrypted_header_t, file_path)); + DBG("metadata_decrypted_header_t.file_size : 0x%04lx (0x%04lx)\n", + mdps + offsetof(metadata_decrypted_header_t, file_size), + FIELD_SIZEOF(metadata_decrypted_header_t, file_size)); + DBG("metadata_decrypted_header_t.root_mht_node_key : 0x%04lx (0x%04lx)\n", + mdps + offsetof(metadata_decrypted_header_t, root_mht_node_key), + FIELD_SIZEOF(metadata_decrypted_header_t, root_mht_node_key)); + DBG("metadata_decrypted_header_t.root_mht_node_mac : 0x%04lx (0x%04lx)\n", + mdps + offsetof(metadata_decrypted_header_t, root_mht_node_mac), + FIELD_SIZEOF(metadata_decrypted_header_t, root_mht_node_mac)); + DBG("metadata_decrypted_header_t.file_data : 0x%04lx (0x%04lx)\n", + mdps + offsetof(metadata_decrypted_header_t, file_data), + FIELD_SIZEOF(metadata_decrypted_header_t, file_data)); DBG("size(metadata_padding_t) = 0x%04lx\n", sizeof(metadata_padding_t)); DBG("metadata_padding_t : 0x%04lx (0x%04lx)\n", - mdps + sizeof(metadata_encrypted_t), sizeof(metadata_padding_t)); + mdps + sizeof(metadata_decrypted_header_t), sizeof(metadata_padding_t)); /* node 0: metadata + 3k of user data */ /* plain metadata */ truncate_file("trunc_meta_plain_0", 0); - truncate_file("trunc_meta_plain_1", FIELD_TRUNCATED(metadata_plain_t, file_id)); - truncate_file("trunc_meta_plain_2", offsetof(metadata_plain_t, major_version)); - truncate_file("trunc_meta_plain_3", offsetof(metadata_plain_t, minor_version)); - truncate_file("trunc_meta_plain_4", offsetof(metadata_plain_t, metadata_key_id)); - truncate_file("trunc_meta_plain_5", FIELD_TRUNCATED(metadata_plain_t, metadata_key_id)); - truncate_file("trunc_meta_plain_6", offsetof(metadata_plain_t, metadata_gmac)); - truncate_file("trunc_meta_plain_7", FIELD_TRUNCATED(metadata_plain_t, metadata_gmac)); + truncate_file("trunc_meta_plain_1", FIELD_TRUNCATED(metadata_plaintext_header_t, file_id)); + truncate_file("trunc_meta_plain_2", offsetof(metadata_plaintext_header_t, major_version)); + truncate_file("trunc_meta_plain_3", offsetof(metadata_plaintext_header_t, minor_version)); + truncate_file("trunc_meta_plain_4", offsetof(metadata_plaintext_header_t, metadata_key_nonce)); + truncate_file("trunc_meta_plain_5", FIELD_TRUNCATED(metadata_plaintext_header_t, + metadata_key_nonce)); + truncate_file("trunc_meta_plain_6", offsetof(metadata_plaintext_header_t, metadata_key_nonce)); + truncate_file("trunc_meta_plain_7", FIELD_TRUNCATED(metadata_plaintext_header_t, + metadata_key_nonce)); /* encrypted metadata */ - truncate_file("trunc_meta_enc_0", mdps + offsetof(metadata_encrypted_t, path)); - truncate_file("trunc_meta_enc_1", mdps + FIELD_TRUNCATED(metadata_encrypted_t, path)); - truncate_file("trunc_meta_enc_2", mdps + offsetof(metadata_encrypted_t, size)); - truncate_file("trunc_meta_enc_3", mdps + FIELD_TRUNCATED(metadata_encrypted_t, size)); - truncate_file("trunc_meta_enc_4", mdps + offsetof(metadata_encrypted_t, mht_key)); - truncate_file("trunc_meta_enc_5", mdps + FIELD_TRUNCATED(metadata_encrypted_t, mht_key)); - truncate_file("trunc_meta_enc_6", mdps + offsetof(metadata_encrypted_t, mht_gmac)); - truncate_file("trunc_meta_enc_7", mdps + FIELD_TRUNCATED(metadata_encrypted_t, mht_gmac)); - truncate_file("trunc_meta_enc_8", mdps + offsetof(metadata_encrypted_t, data)); - truncate_file("trunc_meta_enc_9", mdps + FIELD_TRUNCATED(metadata_encrypted_t, data)); + truncate_file("trunc_meta_enc_0", mdps + offsetof(metadata_decrypted_header_t, file_path)); + truncate_file("trunc_meta_enc_1", mdps + FIELD_TRUNCATED(metadata_decrypted_header_t, + file_path)); + truncate_file("trunc_meta_enc_2", mdps + offsetof(metadata_decrypted_header_t, file_size)); + truncate_file("trunc_meta_enc_3", mdps + FIELD_TRUNCATED(metadata_decrypted_header_t, + file_size)); truncate_file("trunc_meta_enc_4", mdps + + offsetof(metadata_decrypted_header_t, root_mht_node_key)); + truncate_file("trunc_meta_enc_5", mdps + FIELD_TRUNCATED(metadata_decrypted_header_t, + root_mht_node_key)); truncate_file("trunc_meta_enc_6", mdps + + offsetof(metadata_decrypted_header_t, root_mht_node_mac)); + truncate_file("trunc_meta_enc_7", mdps + FIELD_TRUNCATED(metadata_decrypted_header_t, + root_mht_node_mac)); truncate_file("trunc_meta_enc_8", mdps + + offsetof(metadata_decrypted_header_t, file_data)); truncate_file("trunc_meta_enc_9", + mdps + FIELD_TRUNCATED(metadata_decrypted_header_t, file_data)); /* padding */ - truncate_file("trunc_meta_pad_0", mdps + sizeof(metadata_encrypted_t)); - truncate_file("trunc_meta_pad_1", mdps + sizeof(metadata_encrypted_t) + truncate_file("trunc_meta_pad_0", mdps + sizeof(metadata_decrypted_header_t)); + truncate_file("trunc_meta_pad_1", mdps + sizeof(metadata_decrypted_header_t) + sizeof(metadata_padding_t) / 2); /* node 1: mht root */ @@ -180,9 +193,9 @@ static void tamper_truncate(void) { truncate_file("trunc_mht_1", PF_NODE_SIZE + PF_KEY_SIZE / 2); /* after data_nodes_crypto[0].key */ truncate_file("trunc_mht_2", PF_NODE_SIZE + PF_KEY_SIZE); - /* middle of data_nodes_crypto[0].gmac */ + /* middle of data_nodes_crypto[0].mac */ truncate_file("trunc_mht_3", PF_NODE_SIZE + PF_KEY_SIZE + PF_MAC_SIZE / 2); - /* after data_nodes_crypto[0].gmac */ + /* after data_nodes_crypto[0].mac */ truncate_file("trunc_mht_4", PF_NODE_SIZE + PF_KEY_SIZE + PF_MAC_SIZE); /* after data_nodes_crypto */ truncate_file("trunc_mht_5", PF_NODE_SIZE + DATA_CRYPTO_SIZE); @@ -190,9 +203,9 @@ static void tamper_truncate(void) { truncate_file("trunc_mht_6", PF_NODE_SIZE + DATA_CRYPTO_SIZE + PF_KEY_SIZE / 2); /* after mht_nodes_crypto[0].key */ truncate_file("trunc_mht_7", PF_NODE_SIZE + DATA_CRYPTO_SIZE + PF_KEY_SIZE); - /* middle of mht_nodes_crypto[0].gmac */ + /* middle of mht_nodes_crypto[0].mac */ truncate_file("trunc_mht_8", PF_NODE_SIZE + DATA_CRYPTO_SIZE + PF_KEY_SIZE + PF_MAC_SIZE / 2); - /* after mht_nodes_crypto[0].gmac */ + /* after mht_nodes_crypto[0].mac */ truncate_file("trunc_mht_9", PF_NODE_SIZE + DATA_CRYPTO_SIZE + PF_KEY_SIZE + PF_MAC_SIZE); /* node 2-3: data #0, #1 */ @@ -213,18 +226,18 @@ static void tamper_truncate(void) { } /* returns mmap'd output contents */ -static void* create_output(const char* path) { +static void* create_output(const char* file_path) { void* mem = MAP_FAILED; - int fd = open(path, O_RDWR|O_CREAT, 0664); + int fd = open(file_path, O_RDWR|O_CREAT, 0664); if (fd < 0) - FATAL("Failed to open output file '%s': %s\n", path, strerror(errno)); + FATAL("Failed to open output file '%s': %s\n", file_path, strerror(errno)); if (ftruncate(fd, g_input_size) < 0) - FATAL("Failed to ftruncate output file '%s': %s\n", path, strerror(errno)); + FATAL("Failed to ftruncate output file '%s': %s\n", file_path, strerror(errno)); mem = mmap(NULL, g_input_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) - FATAL("Failed to mmap output file '%s': %s\n", path, strerror(errno)); + FATAL("Failed to mmap output file '%s': %s\n", file_path, strerror(errno)); memcpy(mem, g_input_data, g_input_size); @@ -255,11 +268,11 @@ static void pf_encrypt(const void* decrypted, size_t size, const pf_key_t* key, make_output_path(suffix); \ meta = create_output(g_output_path); \ out = (uint8_t*)meta; \ - pf_decrypt(&meta->encrypted_part, sizeof(meta->encrypted_part), &g_meta_key, \ - &meta->plain_part.metadata_gmac, meta_dec, "metadata"); \ + pf_decrypt(&meta->encrypted_blob, sizeof(meta->encrypted_blob), &g_meta_key, \ + &meta->plaintext_header.metadata_mac, meta_dec, "metadata"); \ mht_enc = (mht_node_t*)(out + PF_NODE_SIZE); \ - pf_decrypt(mht_enc, sizeof(*mht_enc), &meta_dec->mht_key, &meta_dec->mht_gmac, mht_dec, \ - "mht"); \ + pf_decrypt(mht_enc, sizeof(*mht_enc), &meta_dec->root_mht_node_key, \ + &meta_dec->root_mht_node_mac, mht_dec, "mht"); \ __VA_ARGS__ \ munmap(meta, g_input_size); \ } while (0) @@ -270,16 +283,16 @@ static void pf_encrypt(const void* decrypted, size_t size, const pf_key_t* key, if (update) { \ __BREAK_PF(suffix "_fixed", __VA_ARGS__ { \ pf_encrypt(meta_dec, sizeof(*meta_dec), &g_meta_key, \ - &meta->plain_part.metadata_gmac, meta->encrypted_part, \ - "metadata"); \ + &meta->plaintext_header.metadata_mac, \ + meta->encrypted_blob, "metadata"); \ } ); \ } \ } while (0) #define BREAK_MHT(suffix, ...) do { \ __BREAK_PF(suffix, __VA_ARGS__ { \ - pf_encrypt(mht_dec, sizeof(*mht_dec), &meta_dec->mht_key, &meta_dec->mht_gmac, \ - mht_enc, "mht"); \ + pf_encrypt(mht_dec, sizeof(*mht_dec), &meta_dec->root_mht_node_key, \ + &meta_dec->root_mht_node_mac, mht_enc, "mht"); \ } ); \ } while (0) @@ -288,7 +301,7 @@ static void pf_encrypt(const void* decrypted, size_t size, const pf_key_t* key, static void tamper_modify(void) { metadata_node_t* meta = NULL; uint8_t* out = NULL; - metadata_encrypted_t* meta_dec = malloc(sizeof(*meta_dec)); + metadata_decrypted_header_t* meta_dec = malloc(sizeof(*meta_dec)); if (!meta_dec) FATAL("Out of memory\n"); mht_node_t* mht_enc = NULL; @@ -298,53 +311,53 @@ static void tamper_modify(void) { /* plain part of the metadata isn't covered by the MAC so no point updating it */ BREAK_PF("meta_plain_id_0", /*update=*/false, - { meta->plain_part.file_id = 0; }); + { meta->plaintext_header.file_id = 0; }); BREAK_PF("meta_plain_id_1", /*update=*/false, - { meta->plain_part.file_id = UINT64_MAX; }); + { meta->plaintext_header.file_id = UINT64_MAX; }); BREAK_PF("meta_plain_version_0", /*update=*/false, - { meta->plain_part.major_version = 0; }); + { meta->plaintext_header.major_version = 0; }); BREAK_PF("meta_plain_version_1", /*update=*/false, - { meta->plain_part.major_version = 0xff; }); + { meta->plaintext_header.major_version = 0xff; }); BREAK_PF("meta_plain_version_2", /*update=*/false, - { meta->plain_part.minor_version = 0xff; }); - - /* metadata_key_id is the keying material for encrypted metadata key derivation, so create also - * PFs with updated MACs */ - BREAK_PF("meta_plain_keyid_0", /*update=*/true, - { meta->plain_part.metadata_key_id[0] ^= 1; }); - BREAK_PF("meta_plain_keyid_1", /*update=*/true, - { LAST_BYTE(meta->plain_part.metadata_key_id) ^= 0xfe; }); + { meta->plaintext_header.minor_version = 0xff; }); + + /* metadata_key_nonce is the keying material for encrypted metadata key derivation, so create + * also PFs with updated MACs */ + BREAK_PF("meta_plain_nonce_0", /*update=*/true, + { meta->plaintext_header.metadata_key_nonce[0] ^= 1; }); + BREAK_PF("meta_plain_nonce_1", /*update=*/true, + { LAST_BYTE(meta->plaintext_header.metadata_key_nonce) ^= 0xfe; }); BREAK_PF("meta_plain_mac_0", /*update=*/true, - { meta->plain_part.metadata_gmac[0] ^= 0xfe; }); + { meta->plaintext_header.metadata_key_nonce[0] ^= 0xfe; }); BREAK_PF("meta_plain_mac_1", /*update=*/true, - { LAST_BYTE(meta->plain_part.metadata_gmac) &= 1; }); + { LAST_BYTE(meta->plaintext_header.metadata_key_nonce) &= 1; }); BREAK_PF("meta_enc_filename_0", /*update=*/true, - { meta_dec->path[0] = 0; }); + { meta_dec->file_path[0] = 0; }); BREAK_PF("meta_enc_filename_1", /*update=*/true, - { meta_dec->path[0] ^= 1; }); + { meta_dec->file_path[0] ^= 1; }); BREAK_PF("meta_enc_filename_2", /*update=*/true, - { LAST_BYTE(meta_dec->path) ^= 0xfe; }); + { LAST_BYTE(meta_dec->file_path) ^= 0xfe; }); BREAK_PF("meta_enc_size_0", /*update=*/true, - { meta_dec->size = 0; }); + { meta_dec->file_size = 0; }); BREAK_PF("meta_enc_size_1", /*update=*/true, - { meta_dec->size = g_input_size - 1; }); + { meta_dec->file_size = g_input_size - 1; }); BREAK_PF("meta_enc_size_2", /*update=*/true, - { meta_dec->size = g_input_size + 1; }); + { meta_dec->file_size = g_input_size + 1; }); BREAK_PF("meta_enc_size_3", /*update=*/true, - { meta_dec->size = UINT64_MAX; }); + { meta_dec->file_size = UINT64_MAX; }); BREAK_PF("meta_enc_mht_key_0", /*update=*/true, - { meta_dec->mht_key[0] ^= 1; }); + { meta_dec->root_mht_node_key[0] ^= 1; }); BREAK_PF("meta_enc_mht_key_1", /*update=*/true, - { LAST_BYTE(meta_dec->mht_key) ^= 0xfe; }); + { LAST_BYTE(meta_dec->root_mht_node_key) ^= 0xfe; }); BREAK_PF("meta_enc_mht_mac_0", /*update=*/true, - { meta_dec->mht_gmac[0] ^= 1; }); + { meta_dec->root_mht_node_mac[0] ^= 1; }); BREAK_PF("meta_enc_mht_mac_1", /*update=*/true, - { LAST_BYTE(meta_dec->mht_gmac) ^= 0xfe; }); + { LAST_BYTE(meta_dec->root_mht_node_mac) ^= 0xfe; }); BREAK_PF("meta_enc_data_0", /*update=*/true, - { meta_dec->data[0] ^= 0xfe; }); + { meta_dec->file_data[0] ^= 0xfe; }); BREAK_PF("meta_enc_data_1", /*update=*/true, - { LAST_BYTE(meta_dec->data) ^= 1; }); + { LAST_BYTE(meta_dec->file_data) ^= 1; }); /* padding is ignored */ BREAK_PF("meta_padding_0", /*update=*/false, @@ -353,13 +366,13 @@ static void tamper_modify(void) { { LAST_BYTE(meta->padding) ^= 0xfe; }); BREAK_MHT("mht_0", { mht_dec->data_nodes_crypto[0].key[0] ^= 1; }); - BREAK_MHT("mht_1", { mht_dec->data_nodes_crypto[0].gmac[0] ^= 1; }); + BREAK_MHT("mht_1", { mht_dec->data_nodes_crypto[0].mac[0] ^= 1; }); BREAK_MHT("mht_2", { mht_dec->mht_nodes_crypto[0].key[0] ^= 1; }); - BREAK_MHT("mht_3", { mht_dec->mht_nodes_crypto[0].gmac[0] ^= 1; }); + BREAK_MHT("mht_3", { mht_dec->mht_nodes_crypto[0].mac[0] ^= 1; }); BREAK_MHT("mht_4", { mht_dec->data_nodes_crypto[ATTACHED_DATA_NODES_COUNT - 1].key[0] ^= 1; }); - BREAK_MHT("mht_5", { mht_dec->data_nodes_crypto[ATTACHED_DATA_NODES_COUNT - 1].gmac[0] ^= 1; }); + BREAK_MHT("mht_5", { mht_dec->data_nodes_crypto[ATTACHED_DATA_NODES_COUNT - 1].mac[0] ^= 1; }); BREAK_MHT("mht_6", { mht_dec->mht_nodes_crypto[CHILD_MHT_NODES_COUNT - 1].key[0] ^= 1; }); - BREAK_MHT("mht_7", { mht_dec->mht_nodes_crypto[CHILD_MHT_NODES_COUNT - 1].gmac[0] ^= 1; }); + BREAK_MHT("mht_7", { mht_dec->mht_nodes_crypto[CHILD_MHT_NODES_COUNT - 1].mac[0] ^= 1; }); BREAK_MHT("mht_8", { gcm_crypto_data_t crypto; memcpy(&crypto, &mht_dec->data_nodes_crypto[0], sizeof(crypto)); @@ -461,7 +474,7 @@ int main(int argc, char* argv[]) { } load_wrap_key(wrap_key_path, &g_wrap_key); - derive_main_key(&g_wrap_key, &((metadata_plain_t*)g_input_data)->metadata_key_id, + derive_main_key(&g_wrap_key, &((metadata_plaintext_header_t*)g_input_data)->metadata_key_nonce, &g_meta_key); g_input_name = basename(input_path);