123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- /*
- * Copyright (C) 2011-2017 Intel Corporation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Intel Corporation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include "monotonic_counter_database_sqlite_rpdb.h"
- #include "monotonic_counter_database_sqlite_access_hw_mc.h"
- #include "monotonic_counter_database_sqlite_bin_hash_tree_utility.h"
- #include "monotonic_counter_database_sqlite_cache.h"
- #include "pse_op_t.h"
- #include "util.h"
- #include "utility.h"
- #include "sgx_tcrypto.h"
- #define CHECK_ERROR_CODE(ret, lable) if(OP_SUCCESS != ret) { ret = OP_ERROR_INTERNAL; goto lable; }
- /*******************************************************************
- ** Function name: calculate_owner_id
- ** Descrption:
- ** Calculate VMC Access Control Information. An ID of the creator of a VMC is defined as:
- ** MR=[];
- ** If (OwnerPolicy.MRSIGNER==1) MR=MR||REPORT(creator).MRSIGNER;
- ** If (OwnerPolicy.MREnclave==1) MR=MR||REPORT(creator).MRENCLAVE;
- ** MaskedAttrs = REPORT(creator).ATTRIBUTES & OwnerAttrMask
- ** OwnerID =SHA256(MR||MaskedAttrs|| REPORT(creator).ProdID));
- *******************************************************************/
- static sgx_status_t calculate_owner_id(
- const isv_attributes_t &owner_attributes, // [IN] ISV's attributes info
- const uint16_t mc_policy, // [IN] user's access control policy
- const uint8_t* mc_att_mask, // [IN] attribute mask
- void* owner_id) // [OUT] ID of the creator of VMC
- {
- sgx_sha_state_handle_t ctx = NULL;
- sgx_status_t sgx_ret = SGX_SUCCESS;
- assert(owner_id != NULL && mc_att_mask != NULL);
- do
- {
- sgx_ret = sgx_sha256_init(&ctx);
- BREAK_ON_ERROR(sgx_ret);
- if (mc_policy & MC_POLICY_SIGNER)
- {
- sgx_ret = sgx_sha256_update((const uint8_t *)(&owner_attributes.mr_signer),
- sizeof(owner_attributes.mr_signer),
- ctx);
- BREAK_ON_ERROR(sgx_ret);
- }
- if (mc_policy & MC_POLICY_ENCLAVE)
- {
- sgx_ret = sgx_sha256_update((const uint8_t *)(&owner_attributes.mr_enclave),
- sizeof(owner_attributes.mr_enclave),
- ctx);
- BREAK_ON_ERROR(sgx_ret);
- }
- uint64_t masked_att_flags = owner_attributes.attribute.flags & *((const uint64_t*)mc_att_mask);
- sgx_ret = sgx_sha256_update((const uint8_t *)&masked_att_flags, sizeof(masked_att_flags), ctx);
- BREAK_ON_ERROR(sgx_ret);
- uint64_t masked_att_xfrm = owner_attributes.attribute.xfrm & *((const uint64_t*)(mc_att_mask+8));
- sgx_ret = sgx_sha256_update((const uint8_t *)&masked_att_xfrm, sizeof(masked_att_xfrm), ctx);
- BREAK_ON_ERROR(sgx_ret);
- sgx_ret = sgx_sha256_update((const uint8_t *)(&owner_attributes.isv_prod_id), sizeof(sgx_prod_id_t), ctx);
- BREAK_ON_ERROR(sgx_ret);
- sgx_ret = sgx_sha256_get_hash(ctx, (sgx_sha256_hash_t*)owner_id);
- BREAK_ON_ERROR(sgx_ret);
- } while (0);
- if(ctx)
- {
- sgx_status_t ret = sgx_sha256_close(ctx);
- sgx_ret = (sgx_ret != SGX_SUCCESS)? sgx_ret : ret;
- }
- return sgx_ret;
- }
- /*******************************************************************
- ** Function name: rpdb_accessible
- ** Descrption: check permission of accessing to a VMC entry, according to UUID and ISV's attributes.
- ** Return Value:
- ** OP_SUCCESS --- the ISV has access right of the VMC
- ** else ERROR --- the ISV doesn't have access right of the VMC
- **
- *******************************************************************/
- static pse_op_error_t rpdb_accessible(
- const isv_attributes_t &owner_attributes, //[in] ISV's attributes
- const vmc_data_blob_t &vmc) // [in] Points to VMC data blob buffer read from SQLite Database
- {
- uint8_t sha256_value[32] = {0};
- // calculate ID of ISV
- if(SGX_SUCCESS!= calculate_owner_id(owner_attributes, vmc.owner_policy, (const uint8_t*)(vmc.owner_attr_mask), sha256_value))
- {
- return OP_ERROR_INTERNAL;
- }
- // compare the ID of ISV and the ID of creator of the VMC entry.
- if(memcmp(sha256_value, vmc.owner_id, sizeof(sha256_value)))
- {
- return OP_ERROR_INVALID_OWNER;
- }
- // if ISV's SVN is less than the SVN of the VMC's creator, deny access.
- if (vmc.owner_svn > owner_attributes.isv_svn)
- {
- return OP_ERROR_INVALID_OWNER;
- }
- // PASS permission check.
- return OP_SUCCESS;
- }
- /*******************************************************************
- ** Function name: operate_vmc
- ** Descrption:
- ** This function perform READ or WRITE operation on VMC SQLite Database, which depends
- ** on the parameter rpdb_op.
- **
- *******************************************************************/
- static pse_op_error_t operate_vmc(const isv_attributes_t &owner_attributes, // [IN] ISV's attributes that
- const mc_rpdb_uuid_t &mc_rpdb_uuid, // [IN] UUID of VMC
- vmc_data_blob_t &rpdb, // [IN,OUT] Pointer that points to VMC data blob
- rpdb_op_t rpdb_op, // [IN] operation type
- op_leafnode_flag_t* op_leafnode_flag_info) // [IN] flag struture used to update USED flag in SQLite Database
- {
- pse_op_error_t rc = OP_SUCCESS;
- sgx_status_t stat = SGX_SUCCESS;
- uint32_t entry_index = 0;
- uint32_t leaf_id;
- uint32_t invalid_node_id;
- pse_vmc_hash_tree_cache_t cache;
- bool is_read_from_cache = false;
- uint8_t rpdata_roothash[ROOT_HASH_SIZE] = {0};
- memset(&cache, 0, sizeof(cache));
- // For CREATE/DELETE operation, op_leafnode_flag_info must point to a valid flag struture, since
- // the USED flag and QOUTA table in SQLite Database would be updated according to the flag info.
- assert(!((RPDB_OP_CREATE == rpdb_op || RPDB_OP_DELETE == rpdb_op) && !op_leafnode_flag_info));
- // get RPDB ID for UUID
- memcpy(&entry_index, mc_rpdb_uuid.entry_index, UUID_ENTRY_INDEX_SIZE);
- if(entry_index > (INIT_LEAF_NODE_ID_BASE-1))
- {
- return OP_ERROR_INVALID_COUNTER;
- }
- // Read the current RPDATA from CSME to check whether the cached vm db is not of date.
- // The newly read RPDATA_EPOCH must match the cached RPDATA_EPOCH.
- if ((rc = read_rpdata()) != OP_SUCCESS)
- {
- return rc;
- }
- if ((rc = get_cached_roothash(rpdata_roothash)) != OP_SUCCESS)
- {
- return rc;
- }
- // get LEAF ID from RPDB ID.
- leaf_id = entry_index + INIT_LEAF_NODE_ID_BASE;
- // set all related nodes ids
- set_related_nodes_ids(leaf_id, &cache);
- // check the cached vmc db root with current rpdata value
- // if the cached vmc db is not out of date, try to get all related nodes from cache
- rc = access_hash_tree_cache(rpdb_op, CACHE_OP_READ, &cache, rpdata_roothash);
- if(OP_SUCCESS == rc)
- {
- is_read_from_cache = true;
- }
- if(!is_read_from_cache)
- {
- // not found in the cache, need to read from VMC DB -- OCall
- stat = sqlite_read_db(&rc,
- leaf_id,
- &cache);
- if(OP_SUCCESS != rc || SGX_SUCCESS != stat)
- {
- if (stat != SGX_SUCCESS)
- {
- rc = OP_ERROR_INTERNAL;
- }
- goto clean_up;
- }
- // node ids may be modified in untrusted domain, so reset them
- set_related_nodes_ids(leaf_id, &cache);
- // verify the integrition of the data
- rc = verify_related_nodes_of_leaf(&cache, &invalid_node_id);
- if(OP_SUCCESS != rc)
- {
- goto clean_up;
- }
- }
- if(RPDB_OP_READ == rpdb_op)
- {
- // first check the is_used flag, a VMC must have been created before being read.
- if(0 == cache.self.leaf.is_used)
- {
- rc = OP_ERROR_INVALID_COUNTER;
- goto clean_up;
- }
- if(0 != memcmp(mc_rpdb_uuid.nonce, cache.self.leaf.nonce, UUID_NONCE_SIZE))
- {
- rc = OP_ERROR_INVALID_COUNTER;
- goto clean_up;
- }
- memcpy(&rpdb, &cache.self.leaf, LEAF_NODE_SIZE);
- if(!is_read_from_cache) // need to update caculated root into cache buffer
- {
- if ((rc = get_cached_roothash(cache.root.hash)) != OP_SUCCESS)
- {
- goto clean_up;
- }
- }
- rc = OP_SUCCESS;
- // for READ operation, return here.
- goto clean_up;
- }
- // READING RPDB won't reach here.
- assert(RPDB_OP_READ != rpdb_op);
- if(rpdb_op == RPDB_OP_CREATE) // CREATING VMC
- {
- if(0 != cache.self.leaf.is_used)
- {
- rc = OP_ERROR_INTERNAL;
- goto clean_up;
- }
- }
- else // INCREMENTING and DELETING VMC need access right.
- {
- // first check the is_used flag, a VMC must have been created before being read.
- if(0 == cache.self.leaf.is_used)
- {
- rc = OP_ERROR_INVALID_COUNTER;
- goto clean_up;
- }
- // nonce must be the same with the value stored in the VMC entry
- if(memcmp(mc_rpdb_uuid.nonce, ((vmc_data_blob_t*)&cache.self.leaf)->nonce, UUID_NONCE_SIZE))
- {
- return OP_ERROR_INVALID_COUNTER;
- }
- // check access right
- rc = rpdb_accessible(owner_attributes, *((vmc_data_blob_t*)&cache.self.leaf));
- if(OP_SUCCESS != rc)
- {
- goto clean_up;
- }
- }
- if(RPDB_OP_INCREMENT == rpdb_op)
- {
- cache.self.leaf.value += 1;
- // output updated leaf node
- memcpy(&rpdb, &cache.self.leaf, LEAF_NODE_SIZE);
- }
- else // rpdb_op is RPDB_OP_CREATE or RPDB_OP_DELETE
- {
- memcpy(&cache.self.leaf, &rpdb, LEAF_NODE_SIZE);
- }
- // calculate all effected nodes new hash value and root hash
-
- rc = update_related_nodes_of_leaf(&cache,
- (RPDB_OP_CREATE == rpdb_op || RPDB_OP_DELETE == rpdb_op) ? op_leafnode_flag_info->op_type : NON_OP);
- if(OP_SUCCESS != rc)
- {
- goto clean_up;
- }
- // write back all ralated nodes to database
- stat = sqlite_write_db(&rc,
- &cache,
- (RPDB_OP_CREATE == rpdb_op || RPDB_OP_DELETE == rpdb_op),
- op_leafnode_flag_info);
- if(OP_SUCCESS != rc || SGX_SUCCESS != stat)
- {
- if (stat != SGX_SUCCESS)
- {
- rc = OP_ERROR_INTERNAL;
- }
- goto clean_up;
- }
- rc = update_rpdata(cache.root.hash);
- clean_up:
- if(OP_SUCCESS == rc)
- {
- // a successful access to VMC entry
- if(RPDB_OP_READ != rpdb_op || !is_read_from_cache)
- {
- // update cache
- access_hash_tree_cache(rpdb_op, CACHE_OP_UPDATE, &cache, NULL);
- }
- }
-
- return rc;
- }
- /*******************************************************************
- ** Function name: create_vmc
- ** Descrption: create a VMC in SQLite Database and return UUID of the VMC to the caller.
- **
- *******************************************************************/
- pse_op_error_t create_vmc(const isv_attributes_t &owner_attributes, // [IN] ISV's attributes
- vmc_data_blob_t &data, // [IN,OUT] VMC blob data
- mc_rpdb_uuid_t &mc_rpdb_uuid) // [OUT] UUID of VMC
- {
- pse_op_error_t rc = OP_SUCCESS;
- sgx_status_t stat = SGX_SUCCESS;
- uint32_t tmp_rpdb_id = {0};
- int leaf_node_id = 0;
- op_leafnode_flag_t op_leafnode_flag_info;
- int retry_times = 1;
- // Check MC Service Availablity Status
- if((rc = get_mc_service_status()) != OP_SUCCESS)
- {
- if ((rc = initialize_sqlite_database_file(false)) != OP_SUCCESS)
- return rc;
- }
- // Calculate Owner ID and copy to "data->owner_id"
- if(SGX_SUCCESS != calculate_owner_id(owner_attributes,
- data.owner_policy,
- data.owner_attr_mask,
- data.owner_id))
- {
- rc = OP_ERROR_INTERNAL;
- goto end;
- }
- // Copy Owner's SVN
- data.owner_svn = owner_attributes.isv_svn;
-
- // read sgx random number for uuid->nonce.
- stat = sgx_read_rand(mc_rpdb_uuid.nonce, UUID_NONCE_SIZE);
- if( SGX_SUCCESS != stat )
- {
- rc = OP_ERROR_INTERNAL;
- goto end;
- }
- do{
- // get an empty database leaf node and return coressponding ID as rpdb ID to caller
- stat = sqlite_get_empty_leafnode(&rc, &leaf_node_id, const_cast<sgx_measurement_t*>(&owner_attributes.mr_signer));
- if(stat == SGX_SUCCESS) // OCALL success
- {
- if (rc == OP_SUCCESS)
- {
- // check leaf_node_id
- if (leaf_node_id < INIT_LEAF_NODE_ID_BASE || leaf_node_id > INIT_MAX_LEAF_NODE_ID)
- {
- // Invalid leaf node id, valid range must be [INIT_LEAF_NODE_ID_BASE, INIT_LEAF_NODE_ID_BASE*2-1]
- rc = OP_ERROR_INTERNAL;
- break;
- }
- }
- else if( (rc == OP_ERROR_DATABASE_FATAL || rc == OP_ERROR_INVALID_VMC_DB) && retry_times > 0)
- {
- // try to re-initialize vmc db
- if (OP_SUCCESS != (rc = initialize_sqlite_database_file(true)))
- {
- break;
- }
- else
- {
- // if successful, try to create again
- continue;
- }
- }
- else
- {
- // other errors
- break;
- }
- }
- else // OCALL failure
- {
- rc = OP_ERROR_INTERNAL;
- break;
- }
- // RPDB ID = LEAD ID - OFFSET(which is INIT_LEAF_NODE_ID_BASE)
- // Valid range of RPDB ID is from 0 to (INIT_LEAF_NODE_ID_BASE-1).
- tmp_rpdb_id = leaf_node_id - INIT_LEAF_NODE_ID_BASE;
- memcpy(mc_rpdb_uuid.entry_index, &tmp_rpdb_id, UUID_ENTRY_INDEX_SIZE);
- memcpy(data.nonce, mc_rpdb_uuid.nonce, UUID_NONCE_SIZE);
- // mark the flag as USED
- data.is_used = 1;
- // copy creator's mrsigner
- memcpy(&op_leafnode_flag_info.mr_signer, &owner_attributes.mr_signer, sizeof(sgx_measurement_t));
- // will set the USED flag in SQLite Database
- op_leafnode_flag_info.op_type = SET_LEAFNODE_FLAG;
- // call operate_vmc to store VMC creation info into SQLite Database.
- rc = operate_vmc(owner_attributes,
- mc_rpdb_uuid,
- data,
- RPDB_OP_CREATE,
- &op_leafnode_flag_info);
- if((OP_ERROR_INVALID_VMC_DB == rc || OP_ERROR_DATABASE_FATAL == rc)
- && retry_times > 0)
- {
- // try to re-initialize vmc db
- if (OP_SUCCESS != (rc = initialize_sqlite_database_file(true)) )
- {
- break;
- }
- else
- {
- // if successful, try to create vmc again
- continue;
- }
- }
- else
- {
- break;
- }
- }while(retry_times--);
- end:
- if(OP_SUCCESS != rc)
- {
- memset(mc_rpdb_uuid.entry_index, 0xFF, UUID_ENTRY_INDEX_SIZE);
- memset(mc_rpdb_uuid.nonce, 0x0, UUID_NONCE_SIZE);
- }
- return rc;
- }
- pse_op_error_t read_vmc(
- const isv_attributes_t &owner_attributes, // [IN] ISV's attributes that
- const mc_rpdb_uuid_t &mc_rpdb_uuid, // [IN] UUID of VMC
- vmc_data_blob_t &rpdb) // [IN,OUT] Pointer that points to VMC data blob
- {
- pse_op_error_t op_ret = OP_SUCCESS;
- // Check MC Service Availablity Status
- if((op_ret = get_mc_service_status()) != OP_SUCCESS)
- {
- if ((op_ret = initialize_sqlite_database_file(false)) != OP_SUCCESS)
- return op_ret;
- }
- op_ret = operate_vmc(owner_attributes,
- mc_rpdb_uuid,
- rpdb,
- RPDB_OP_READ,
- NULL); // the op_leafnode_flag_info that is used to update USED flag in SQLite Database is not required for READ operation.
- if (OP_ERROR_INVALID_VMC_DB == op_ret ||
- OP_ERROR_DATABASE_FATAL == op_ret)
- {
- op_ret = initialize_sqlite_database_file(true);
- if(OP_SUCCESS == op_ret)
- {
- // If initilize_sqlite_database_file() is successful, return INVALId_VMC_ID, as the DB initialization cleared all existing VMCs.
- return OP_ERROR_INVALID_COUNTER;
- }
- }
- return op_ret;
- }
- pse_op_error_t inc_vmc(
- const isv_attributes_t &owner_attributes, // [IN] ISV's attributes that
- const mc_rpdb_uuid_t &mc_rpdb_uuid, // [IN] UUID of VMC
- vmc_data_blob_t &rpdb) // [IN,OUT] Pointer that points to VMC data blob
- {
- pse_op_error_t op_ret = OP_SUCCESS;
- // Check MC Service Availablity Status
- if((op_ret = get_mc_service_status()) != OP_SUCCESS)
- {
- if ((op_ret = initialize_sqlite_database_file(false)) != OP_SUCCESS)
- return op_ret;
- }
- op_ret = operate_vmc(owner_attributes,
- mc_rpdb_uuid,
- rpdb,
- RPDB_OP_INCREMENT,
- NULL); // the op_leafnode_flag_info that is used to update USED flag in SQLite Database is not required for INC operation.
- if (OP_ERROR_INVALID_VMC_DB == op_ret ||
- OP_ERROR_DATABASE_FATAL == op_ret)
- {
- op_ret = initialize_sqlite_database_file(true);
- if(OP_SUCCESS == op_ret)
- {
- // If initilize_sqlite_database_file() is successful, return INVALId_VMC_ID, as the DB initialization cleared all existing VMCs.
- return OP_ERROR_INVALID_COUNTER;
- }
- }
- return op_ret;
- }
- /*******************************************************************
- ** Function name: delete_vmc
- ** Descrption: delete VMC from SQLite Database according to the specified UUID.
- **
- *******************************************************************/
- pse_op_error_t delete_vmc(const isv_attributes_t &owner_attributes, // [IN] ISV's attributes
- const mc_rpdb_uuid_t &mc_rpdb_uuid) // [IN] UUID of VMC
- {
- pse_op_error_t op_ret = OP_SUCCESS;
- hash_tree_leaf_node_t leaf_node;
- uint32_t rpdb_id = 0;
- op_leafnode_flag_t op_leafnode_flag_info;
- // Check MC Service Availablity Status
- if((op_ret = get_mc_service_status()) != OP_SUCCESS)
- {
- if ((op_ret = initialize_sqlite_database_file(false)) != OP_SUCCESS)
- return op_ret;
- }
- memset(&leaf_node, 0, sizeof(leaf_node));
- // get RPDB ID
- memcpy(&rpdb_id, mc_rpdb_uuid.entry_index, UUID_ENTRY_INDEX_SIZE);
- // check the RPDB ID
- if(rpdb_id>(INIT_LEAF_NODE_ID_BASE-1))
- {
- return OP_ERROR_INVALID_COUNTER;
- }
- // will clear the USED flag in SQLite Database
- op_leafnode_flag_info.op_type = CLR_LEAFNODE_FLAG;
- // call operate_vmc to delete VMC blob from SQLite Database.
- op_ret = operate_vmc(owner_attributes,
- mc_rpdb_uuid,
- leaf_node,
- RPDB_OP_DELETE,
- &op_leafnode_flag_info);
- if (OP_ERROR_INVALID_VMC_DB == op_ret ||
- OP_ERROR_DATABASE_FATAL == op_ret)
- {
- op_ret = initialize_sqlite_database_file(true);
- }
- return op_ret;
- }
|