Files
intel-linux-sgx/sdk/sign_tool/SignTool/manage_metadata.cpp
Li, Xun 60d36e0de7 Linux 2.10 Open Source Gold Release
Provided a reproducible SDK.
Supported new OS: RHEL 8.1, CentOS 8.1 and Fedora 31.
Supported user to specify platform id in PCK Cert ID Retrieval Tool’s command line option.
Added ability to execute Platform Cert ID Retrieval Tool on multi-package platforms without
  loading enclaves. PCCS now supports this functionality. The platform still needs to support
  SGX.
Updated Platform Cert ID Retrieval Tool and Multi-package registration tool to align with BIOS
  platform manifest changes.
Added .deb and .rpm installers for Platform Cert ID Retrieval Tool and Multi-package
  Registration Agent.
Fixed bugs.

Signed-off-by: Li, Xun <xun.li@intel.com>
2020-07-07 08:42:08 +08:00

1299 lines
46 KiB
C++

/*
* Copyright (C) 2011-2020 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.
*
*/
/**
* File:
* manage_metadata.cpp
* Description:
* Parse the xml file to get the metadata and generate the output DLL
* with metadata.
*/
#include "metadata.h"
#include "tinyxml2.h"
#include "manage_metadata.h"
#include "se_trace.h"
#include "util_st.h"
#include "section.h"
#include "se_page_attr.h"
#include "elf_util.h"
#include "crypto_wrapper.h"
#include "global_data.h"
#include "se_version.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <iostream>
#include <iomanip>
#include <fstream>
using tinyxml2::XML_ERROR_FILE_COULD_NOT_BE_OPENED;
using tinyxml2::XML_ERROR_FILE_NOT_FOUND;
using tinyxml2::XML_SUCCESS;
using tinyxml2::XMLElement;
using tinyxml2::XMLError;
#define ALIGN_SIZE 0x1000
static bool traverser_parameter(const char *temp_name, const char *temp_text, xml_parameter_t *parameter, int parameter_count)
{
assert(temp_name != NULL && parameter != NULL);
uint64_t temp_value=0;
if(temp_text == NULL)
{
se_trace(SE_TRACE_ERROR, LACK_VALUE_FOR_ELEMENT_ERROR, temp_name);
return false;
}
else
{
if(strchr(temp_text, '-'))
{
se_trace(SE_TRACE_ERROR, INVALID_VALUE_FOR_ELEMENT_ERROR, temp_name);
return false;
}
errno = 0;
char* endptr = NULL;
temp_value = (uint64_t)strtoull(temp_text, &endptr, 0);
if(*endptr!='\0'||errno!=0) //Invalid value or valid value but out of the representable range
{
se_trace(SE_TRACE_ERROR, INVALID_VALUE_FOR_ELEMENT_ERROR, temp_name);
return false;
}
}
//Look for the matched one
int i=0;
for(; i<parameter_count&&STRCMP(temp_name,parameter[i].name); i++);
if(i>=parameter_count) //no matched, return false
{
se_trace(SE_TRACE_ERROR, UNREC_ELEMENT_ERROR, temp_name);
return false;
}
//found one matched
if(parameter[i].flag==1) //repeated definition of XML element, return false
{
se_trace(SE_TRACE_ERROR, REPEATED_DEFINE_ERROR, temp_name);
return false;
}
parameter[i].flag = 1;
if((temp_value<parameter[i].min_value)||
(temp_value>parameter[i].max_value)) // the value is invalid, return false
{
se_trace(SE_TRACE_ERROR, VALUE_OUT_OF_RANGE_ERROR, temp_name);
return false;
}
parameter[i].value = temp_value;
SE_TRACE_DEBUG("%s = %s\n", temp_name, temp_text);
return true;
}
bool parse_metadata_file(const char *xmlpath, xml_parameter_t *parameter, int parameter_count)
{
const char* temp_name=NULL;
assert(parameter != NULL);
if(xmlpath == NULL) // user didn't define the metadata xml file.
{
se_trace(SE_TRACE_NOTICE, "Use default metadata...\n");
return true;
}
//use the metadata file that user gives us. parse xml file
tinyxml2::XMLDocument doc;
XMLError loadOkay = doc.LoadFile(xmlpath);
if(loadOkay != XML_SUCCESS)
{
if(doc.ErrorID() == XML_ERROR_FILE_COULD_NOT_BE_OPENED)
{
se_trace(SE_TRACE_ERROR, OPEN_FILE_ERROR, xmlpath);
}
else if(doc.ErrorID() == XML_ERROR_FILE_NOT_FOUND)
{
se_trace(SE_TRACE_ERROR, XML_NOT_FOUND_ERROR, xmlpath);
}
else
{
se_trace(SE_TRACE_ERROR, XML_FORMAT_ERROR);
}
return false;
}
doc.Print();//Write the document to standard out using formatted printing ("pretty print").
XMLElement *pmetadata_element = doc.FirstChildElement("EnclaveConfiguration");
if(!pmetadata_element || pmetadata_element->GetText() != NULL)
{
se_trace(SE_TRACE_ERROR, XML_FORMAT_ERROR);
return false;
}
XMLElement *sub_element = NULL;
sub_element = pmetadata_element->FirstChildElement();
const char *temp_text = NULL;
while(sub_element)//parse xml node
{
if(sub_element->FirstAttribute() != NULL)
{
se_trace(SE_TRACE_ERROR, XML_FORMAT_ERROR);
return false;
}
temp_name = sub_element->Value();
temp_text = sub_element->GetText();
//traverse every node. Compare with the default value.
if(traverser_parameter(temp_name, temp_text, parameter, parameter_count) == false)
{
se_trace(SE_TRACE_ERROR, XML_FORMAT_ERROR);
return false;
}
sub_element= sub_element->NextSiblingElement();
}
return true;
}
CMetadata::CMetadata(metadata_t *metadata, BinParser *parser)
: m_metadata(metadata)
, m_parser(parser), m_rva(0), m_gd_size(0), m_gd_template(NULL)
{
memset(m_metadata, 0, sizeof(metadata_t));
memset(&m_create_param, 0, sizeof(m_create_param));
}
CMetadata::~CMetadata()
{
}
bool CMetadata::build_metadata(const xml_parameter_t *parameter)
{
if(!modify_metadata(parameter))
{
return false;
}
// layout table
if(!build_layout_table())
{
return false;
}
// patch table
if(!build_patch_table())
{
return false;
}
if(!build_layout_entries())
{
return false;
}
if(!build_gd_template(m_gd_template, &m_gd_size))
{
return false;
}
return true;
}
#include <sstream>
#include <time.h>
bool CMetadata::get_time(uint32_t *date)
{
assert(date != NULL);
time_t rawtime = 0;
if(time( &rawtime) == -1)
return false;
struct tm *timeinfo = gmtime(&rawtime);
if(timeinfo == NULL)
return false;
uint32_t tmp_date = (timeinfo->tm_year+1900)*10000 + (timeinfo->tm_mon+1)*100 + timeinfo->tm_mday;
std::stringstream ss;
ss<<"0x"<<tmp_date;
ss>>std::hex>>tmp_date;
*date = tmp_date;
return true;
}
bool CMetadata::fill_enclave_css(const xml_parameter_t *para)
{
assert(para != NULL);
uint32_t date = 0;
if(false == get_time(&date))
return false;
//*****fill the header*******************//
uint8_t header[12] = {6, 0, 0, 0, 0xE1, 0, 0, 0, 0, 0, 1, 0};
uint8_t header2[16] = {1, 1, 0, 0, 0x60, 0, 0, 0, 0x60, 0, 0, 0, 1, 0, 0, 0};
memcpy_s(&m_metadata->enclave_css.header.header, sizeof(m_metadata->enclave_css.header.header), &header, sizeof(header));
memcpy_s(&m_metadata->enclave_css.header.header2, sizeof(m_metadata->enclave_css.header.header2), &header2, sizeof(header2));
// For 'type', signing tool clears the bit 31 for product enclaves
// and set the bit 31 for debug enclaves
m_metadata->enclave_css.header.type = (para[RELEASETYPE].value & 0x01) ? (1<<31) : 0;
m_metadata->enclave_css.header.module_vendor = (para[INTELSIGNED].value&0x01) ? 0x8086 : 0;
m_metadata->enclave_css.header.date = date;
//hardware version
m_metadata->enclave_css.header.hw_version = (uint32_t)para[HW].value;
// Misc_select/Misc_mask
m_metadata->enclave_css.body.misc_select = (uint32_t)para[MISCSELECT].value;
m_metadata->enclave_css.body.misc_mask = (uint32_t)para[MISCMASK].value;
//low 64 bit
m_metadata->enclave_css.body.attributes.flags = 0;
m_metadata->enclave_css.body.attribute_mask.flags = ~SGX_FLAGS_DEBUG;
if(para[DISABLEDEBUG].value == 1)
{
m_metadata->enclave_css.body.attributes.flags &= ~SGX_FLAGS_DEBUG;
m_metadata->enclave_css.body.attribute_mask.flags |= SGX_FLAGS_DEBUG;
}
if(para[PROVISIONKEY].value == 1)
{
m_metadata->enclave_css.body.attributes.flags |= SGX_FLAGS_PROVISION_KEY;
m_metadata->enclave_css.body.attribute_mask.flags |= SGX_FLAGS_PROVISION_KEY;
}
if(para[LAUNCHKEY].value == 1)
{
m_metadata->enclave_css.body.attributes.flags |= SGX_FLAGS_EINITTOKEN_KEY;
m_metadata->enclave_css.body.attribute_mask.flags |= SGX_FLAGS_EINITTOKEN_KEY;
}
if (para[ENABLEKSS].value == 1)
{
m_metadata->enclave_css.body.attributes.flags |= SGX_FLAGS_KSS;
m_metadata->enclave_css.body.attribute_mask.flags |= SGX_FLAGS_KSS;
}
if (memcpy_s(&(m_metadata->enclave_css.body.isvext_prod_id), SGX_ISVEXT_PROD_ID_SIZE,
&(para[ISVEXTPRODID_L].value), sizeof(para[ISVEXTPRODID_L].value)))
{
return false;
}
if (memcpy_s((uint8_t *)&(m_metadata->enclave_css.body.isvext_prod_id) + sizeof(para[ISVEXTPRODID_L].value),
SGX_ISVEXT_PROD_ID_SIZE - sizeof(para[ISVEXTPRODID_L].value), &(para[ISVEXTPRODID_H].value), sizeof(para[ISVEXTPRODID_H].value)))
{
return false;
}
if (memcpy_s(&(m_metadata->enclave_css.body.isv_family_id), SGX_ISV_FAMILY_ID_SIZE,
&(para[ISVFAMILYID_L].value), sizeof(para[ISVFAMILYID_L].value)))
{
return false;
}
if (memcpy_s((uint8_t *)&(m_metadata->enclave_css.body.isv_family_id) + sizeof(para[ISVFAMILYID_L].value),
SGX_ISV_FAMILY_ID_SIZE - sizeof(para[ISVFAMILYID_L].value), &(para[ISVFAMILYID_H].value), sizeof(para[ISVFAMILYID_H].value)))
{
return false;
}
bin_fmt_t bf = m_parser->get_bin_format();
if(bf == BF_PE64 || bf == BF_ELF64)
{
m_metadata->enclave_css.body.attributes.flags |= SGX_FLAGS_MODE64BIT;
m_metadata->enclave_css.body.attribute_mask.flags |= SGX_FLAGS_MODE64BIT;
}
// high 64 bit
//default setting
m_metadata->enclave_css.body.attributes.xfrm = SGX_XFRM_LEGACY;
m_metadata->enclave_css.body.attribute_mask.xfrm = SGX_XFRM_LEGACY | SGX_XFRM_RESERVED; // LEGACY and reservied bits would be checked.
m_metadata->enclave_css.body.isv_prod_id = (uint16_t)para[PRODID].value;
m_metadata->enclave_css.body.isv_svn = (uint16_t)para[ISVSVN].value;
return true;
}
bool CMetadata::modify_metadata(const xml_parameter_t *parameter)
{
assert(parameter != NULL);
if(!check_xml_parameter(parameter))
return false;
if(!fill_enclave_css(parameter))
return false;
m_metadata->version = META_DATA_MAKE_VERSION(MAJOR_VERSION,MINOR_VERSION );
m_metadata->size = offsetof(metadata_t, data);
m_metadata->tcs_policy = (uint32_t)parameter[TCSPOLICY].value;
m_metadata->ssa_frame_size = SSA_FRAME_SIZE;
m_metadata->max_save_buffer_size = MAX_SAVE_BUF_SIZE;
m_metadata->magic_num = METADATA_MAGIC;
m_metadata->desired_misc_select = 0;
m_metadata->tcs_min_pool = (uint32_t)parameter[TCSMINPOOL].value;
m_metadata->enclave_css.body.misc_select = (uint32_t)parameter[MISCSELECT].value;
m_metadata->enclave_css.body.misc_mask = (uint32_t)parameter[MISCMASK].value;
//set metadata.attributes
//low 64 bit: it's the same as enclave_css
memset(&m_metadata->attributes, 0, sizeof(sgx_attributes_t));
m_metadata->attributes.flags = m_metadata->enclave_css.body.attributes.flags;
//high 64 bit
//set bits that will not be checked
m_metadata->attributes.xfrm = ~m_metadata->enclave_css.body.attribute_mask.xfrm;
//set bits that have been set '1' and need to be checked
m_metadata->attributes.xfrm |= (m_metadata->enclave_css.body.attributes.xfrm & m_metadata->enclave_css.body.attribute_mask.xfrm);
return true;
}
bool CMetadata::check_xml_parameter(const xml_parameter_t *parameter)
{
//stack/heap must be page-align
if( (parameter[STACKMAXSIZE].value % ALIGN_SIZE)
|| (parameter[STACKMINSIZE].value % ALIGN_SIZE) )
{
se_trace(SE_TRACE_ERROR, SET_STACK_SIZE_ERROR);
return false;
}
if(parameter[STACKMINSIZE].value > parameter[STACKMAXSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_STACK_SIZE_ERROR);
return false;
}
if( (parameter[HEAPMAXSIZE].value % ALIGN_SIZE)
|| (parameter[HEAPMINSIZE].value % ALIGN_SIZE)
|| (parameter[HEAPINITSIZE].value % ALIGN_SIZE) )
{
se_trace(SE_TRACE_ERROR, SET_HEAP_SIZE_ALIGN_ERROR);
return false;
}
if (parameter[HEAPINITSIZE].flag != 0)
{
if (parameter[HEAPINITSIZE].value > parameter[HEAPMAXSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_HEAP_SIZE_INIT_MAX_ERROR);
return false;
}
if (parameter[HEAPMINSIZE].value > parameter[HEAPINITSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_HEAP_SIZE_INIT_MIN_ERROR);
return false;
}
}
else
{
if (parameter[HEAPMINSIZE].value > parameter[HEAPMAXSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_HEAP_SIZE_MAX_MIN_ERROR);
return false;
}
}
if ((parameter[RSRVMAXSIZE].value % ALIGN_SIZE)
|| (parameter[RSRVMINSIZE].value % ALIGN_SIZE)
|| (parameter[RSRVINITSIZE].value % ALIGN_SIZE))
{
se_trace(SE_TRACE_ERROR, SET_RSRV_SIZE_ALIGN_ERROR);
return false;
}
if (parameter[RSRVINITSIZE].flag != 0)
{
if (parameter[RSRVINITSIZE].value > parameter[RSRVMAXSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_RSRV_SIZE_INIT_MAX_ERROR);
return false;
}
if (parameter[RSRVMINSIZE].value > parameter[RSRVINITSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_RSRV_SIZE_INIT_MIN_ERROR);
return false;
}
}
else
{
if (parameter[RSRVMINSIZE].value > parameter[RSRVMAXSIZE].value)
{
se_trace(SE_TRACE_ERROR, SET_RSRV_SIZE_MAX_MIN_ERROR);
return false;
}
}
if(parameter[RSRVEXECUTABLE].flag != 0)
{
if(parameter[RSRVEXECUTABLE].value != 0 && parameter[RSRVEXECUTABLE].value != 1)
{
se_trace(SE_TRACE_ERROR, SET_RSRV_EXECUTABLE_ERROR);
return false;
}
}
// LE setting: HW != 0, Licensekey = 1
// Other enclave setting: HW = 0, Licensekey = 0
if((parameter[HW].value == 0 && parameter[LAUNCHKEY].value != 0) ||
(parameter[HW].value != 0 && parameter[LAUNCHKEY].value == 0))
{
se_trace(SE_TRACE_ERROR, SET_HW_LE_ERROR);
return false;
}
if (parameter[TCSMAXNUM].flag != 0)
{
if (parameter[TCSMAXNUM].value < parameter[TCSNUM].value)
{
se_trace(SE_TRACE_ERROR, SET_TCS_MAX_NUM_ERROR);
return false;
}
if ((parameter[TCSMINPOOL].flag != 0)
&& (parameter[TCSMINPOOL].value > parameter[TCSMAXNUM].value))
{
se_trace(SE_TRACE_ERROR, SET_TCS_MIN_POOL_ERROR);
return false;
}
}
else if ((parameter[TCSMINPOOL].flag != 0)
&& (parameter[TCSMINPOOL].value > parameter[TCSNUM].value))
{
se_trace(SE_TRACE_ERROR, SET_TCS_MIN_POOL_ERROR);
return false;
}
if ((parameter[ISVEXTPRODID_H].value || parameter[ISVEXTPRODID_L].value ||
parameter[ISVFAMILYID_H].value || parameter[ISVFAMILYID_L].value) &&
parameter[ENABLEKSS].value == 0)
{
se_trace(SE_TRACE_ERROR, SET_ENABLE_KSS_ERROR);
return false;
}
m_create_param.heap_init_size = parameter[HEAPINITSIZE].flag ? parameter[HEAPINITSIZE].value : parameter[HEAPMAXSIZE].value;
m_create_param.heap_min_size = parameter[HEAPMINSIZE].value;
m_create_param.heap_max_size = parameter[HEAPMAXSIZE].value;
m_create_param.rsrv_init_size = parameter[RSRVINITSIZE].flag ? parameter[RSRVINITSIZE].value : parameter[RSRVMAXSIZE].value;
m_create_param.rsrv_min_size = parameter[RSRVMINSIZE].value;
m_create_param.rsrv_max_size = parameter[RSRVMAXSIZE].value;
m_create_param.rsrv_executable = parameter[RSRVEXECUTABLE].flag ? parameter[RSRVEXECUTABLE].value : 0;
m_create_param.stack_max_size = parameter[STACKMAXSIZE].value;
m_create_param.stack_min_size = parameter[STACKMINSIZE].value;
m_create_param.tcs_num = (uint32_t)parameter[TCSNUM].value;
m_create_param.tcs_max_num = (uint32_t)(parameter[TCSMAXNUM].flag ? parameter[TCSMAXNUM].value : parameter[TCSNUM].value);
m_create_param.tcs_min_pool = (uint32_t)parameter[TCSMINPOOL].value;
m_create_param.tcs_policy = (uint32_t)parameter[TCSPOLICY].value;
se_trace(SE_TRACE_ERROR, "tcs_num %d, tcs_max_num %d, tcs_min_pool %d\n", m_create_param.tcs_num, m_create_param.tcs_max_num, m_create_param.tcs_min_pool);
SE_TRACE_DEBUG("RSRV_MIN_SIZE = 0x%016llX\n", m_create_param.rsrv_min_size);
SE_TRACE_DEBUG("RSRV_INIT_SIZE = 0x%016llX\n", m_create_param.rsrv_init_size);
SE_TRACE_DEBUG("RSRV_MAX_SIZE = 0x%016llX\n", m_create_param.rsrv_max_size);
return true;
}
void *CMetadata::alloc_buffer_from_metadata(uint32_t size)
{
void *addr = GET_PTR(void, m_metadata, m_metadata->size);
m_metadata->size += size;
if((m_metadata->size < size) || (m_metadata->size > METADATA_SIZE))
{
return NULL;
}
return addr;
}
/*
* Called within build_layout_table(), used to assign the rva to entry layout
* and load_step to group layout.
*/
bool CMetadata::update_layout_entries()
{
m_rva = calculate_sections_size();
if(m_rva == 0)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
se_trace(SE_TRACE_ERROR, "Sections size is 0\n");
return false;
}
SE_TRACE_DEBUG("\n");
for(uint32_t i = 0; i < m_layouts.size(); i++)
{
if(!IS_GROUP_ID(m_layouts[i].entry.id))
{
m_layouts[i].entry.rva = m_rva;
m_rva += (((uint64_t)m_layouts[i].entry.page_count) << SE_PAGE_SHIFT);
se_trace(SE_TRACE_DEBUG, "\tEntry Id(%2u) = %4u, %-16s, ", i, m_layouts[i].entry.id, layout_id_str[m_layouts[i].entry.id]);
se_trace(SE_TRACE_DEBUG, "Page Count = %5u, ", m_layouts[i].entry.page_count);
se_trace(SE_TRACE_DEBUG, "Attributes = 0x%02X, ", m_layouts[i].entry.attributes);
se_trace(SE_TRACE_DEBUG, "Flags = 0x%016llX, ", m_layouts[i].entry.si_flags);
se_trace(SE_TRACE_DEBUG, "RVA = 0x%016llX --- 0x%016llX\n", m_layouts[i].entry.rva, m_rva-1);
}
else
{
for (uint32_t j = 0; j < m_layouts[i].group.entry_count; j++)
{
m_layouts[i].group.load_step += ((uint64_t)(m_layouts[i-j-1].entry.page_count)) << SE_PAGE_SHIFT;
}
uint64_t temp_rva = m_rva;
m_rva += m_layouts[i].group.load_times * m_layouts[i].group.load_step;
se_trace(SE_TRACE_DEBUG, "\tEntry Id(%2u) = %4u, %-16s, ", i, m_layouts[i].entry.id, layout_id_str[m_layouts[i].entry.id & ~(GROUP_FLAG)]);
se_trace(SE_TRACE_DEBUG, "Entry Count = %4u, ", m_layouts[i].group.entry_count);
se_trace(SE_TRACE_DEBUG, "Load Times = %u, ", m_layouts[i].group.load_times);
se_trace(SE_TRACE_DEBUG, "LStep = 0x%016llX, ", m_layouts[i].group.load_step);
se_trace(SE_TRACE_DEBUG, "RVA = 0x%016llX --- 0x%016llX\n", temp_rva, m_rva-1);
}
}
return true;
}
bool CMetadata::build_layout_entries()
{
SE_TRACE_DEBUG("\n");
// enclave virtual size
m_metadata->enclave_size = calculate_enclave_size(m_rva);
if (m_metadata->enclave_size == (uint64_t)-1)
{
se_trace(SE_TRACE_ERROR, OUT_OF_EPC_ERROR);
return false;
}
// Add extra EPC pages to round the enclave size to power of 2
// We add a layout of guard pages
if (m_metadata->enclave_size - m_rva > 0)
{
uint32_t extra_pages = (uint32_t)((m_metadata->enclave_size - m_rva) >> SE_PAGE_SHIFT);
layout_t layout;
memset(&layout, 0, sizeof(layout));
layout.entry.id = LAYOUT_ID_GUARD;
layout.entry.rva = m_rva;
layout.entry.page_count = extra_pages;
m_layouts.push_back(layout);
se_trace(SE_TRACE_DEBUG, "\tEntry Id(%2u) = %4u, %-16s, ", 0, layout.entry.id, layout_id_str[layout.entry.id]);
se_trace(SE_TRACE_DEBUG, "Page Count = %5u, ", layout.entry.page_count);
se_trace(SE_TRACE_DEBUG, "Attributes = 0x%02X, ", layout.entry.attributes);
se_trace(SE_TRACE_DEBUG, "Flags = 0x%016llX, ", layout.entry.si_flags);
se_trace(SE_TRACE_DEBUG, "RVA = 0x%016llX --- 0x%016llX\n", layout.entry.rva, m_metadata->enclave_size - 1);
}
uint32_t size = (uint32_t)(m_layouts.size() * sizeof(layout_t));
layout_t *layout_table = (layout_t *) alloc_buffer_from_metadata(size);
if(layout_table == NULL)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
se_trace(SE_TRACE_ERROR, "Layout table could not be allocated\n");
return false;
}
m_metadata->dirs[DIR_LAYOUT].offset = (uint32_t)PTR_DIFF(layout_table, m_metadata);
m_metadata->dirs[DIR_LAYOUT].size = size;
for(uint32_t i = 0; i < m_layouts.size(); i++, layout_table++)
{
memcpy_s(layout_table, sizeof(layout_t), &m_layouts[i], sizeof(layout_t));
}
return true;
}
bool CMetadata::build_layout_table()
{
layout_t layout;
memset(&layout, 0, sizeof(layout));
layout_t guard_page;
memset(&guard_page, 0, sizeof(guard_page));
guard_page.entry.id = LAYOUT_ID_GUARD;
guard_page.entry.page_count = SE_GUARD_PAGE_SIZE >> SE_PAGE_SHIFT;
std::vector<layout_t> thread_layouts;
// heap
layout.entry.id = LAYOUT_ID_HEAP_MIN;
layout.entry.page_count = (uint32_t)(m_create_param.heap_min_size >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_EADD;
layout.entry.si_flags = SI_FLAGS_RW;
m_layouts.push_back(layout);
if(m_create_param.heap_init_size > m_create_param.heap_min_size)
{
layout.entry.id = LAYOUT_ID_HEAP_INIT;
layout.entry.page_count = (uint32_t)((m_create_param.heap_init_size - m_create_param.heap_min_size) >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_POST_REMOVE | PAGE_ATTR_POST_ADD;
layout.entry.si_flags = SI_FLAGS_RW;
m_layouts.push_back(layout);
}
if(m_create_param.heap_max_size > m_create_param.heap_init_size)
{
layout.entry.id = LAYOUT_ID_HEAP_MAX;
layout.entry.page_count = (uint32_t)((m_create_param.heap_max_size - m_create_param.heap_init_size) >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_POST_ADD;
layout.entry.si_flags = SI_FLAGS_RW;
m_layouts.push_back(layout);
}
// thread context memory layout
// guard page | stack | guard page | TCS | SSA | guard page | TLS
// vector 'thread_layouts' serves as a template for thread context
// guard page
thread_layouts.push_back(guard_page);
// stack
if(m_create_param.stack_max_size > m_create_param.stack_min_size)
{
layout.entry.id = LAYOUT_ID_STACK_MAX;
layout.entry.page_count = (uint32_t)((m_create_param.stack_max_size - m_create_param.stack_min_size) >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_EEXTEND | PAGE_DIR_GROW_DOWN;
layout.entry.si_flags = SI_FLAGS_RW;
layout.entry.content_size = 0xCCCCCCCC;
thread_layouts.push_back(layout);
}
layout.entry.id = LAYOUT_ID_STACK_MIN;
layout.entry.page_count = (uint32_t)(m_create_param.stack_min_size >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_EEXTEND;
layout.entry.si_flags = SI_FLAGS_RW;
layout.entry.content_size = 0xCCCCCCCC;
thread_layouts.push_back(layout);
// guard page
thread_layouts.push_back(guard_page);
// tcs
layout.entry.id = LAYOUT_ID_TCS;
layout.entry.page_count = TCS_SIZE >> SE_PAGE_SHIFT;
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_EEXTEND;
layout.entry.si_flags = SI_FLAGS_TCS;
tcs_t *tcs_template = (tcs_t *) alloc_buffer_from_metadata(TCS_TEMPLATE_SIZE);
if(tcs_template == NULL)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
return false;
}
layout.entry.content_offset = (uint32_t)PTR_DIFF(tcs_template, m_metadata),
layout.entry.content_size = TCS_TEMPLATE_SIZE;
thread_layouts.push_back(layout);
memset(&layout, 0, sizeof(layout));
// ssa
layout.entry.id = LAYOUT_ID_SSA;
layout.entry.page_count = SSA_FRAME_SIZE * SSA_NUM;
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_EEXTEND;
layout.entry.si_flags = SI_FLAGS_RW;
thread_layouts.push_back(layout);
// guard page
thread_layouts.push_back(guard_page);
// td
layout.entry.id = LAYOUT_ID_TD;
layout.entry.page_count = 1;
const Section *section = m_parser->get_tls_section();
if(section)
{
layout.entry.page_count += (uint32_t)(ROUND_TO_PAGE(section->virtual_size()) >> SE_PAGE_SHIFT);
}
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_EEXTEND;
layout.entry.si_flags = SI_FLAGS_RW;
thread_layouts.push_back(layout);
// adding utility thread context, part of its stack can be added and removed dynamically
for (auto l : thread_layouts)
{
if (l.entry.id == LAYOUT_ID_STACK_MAX)
l.entry.attributes |= PAGE_ATTR_POST_ADD | PAGE_ATTR_POST_REMOVE;
m_layouts.push_back(l);
}
uint32_t tcs_min_pool = 0; /* Number of static threads (EADD) */
uint32_t tcs_eremove = 0;
if(m_create_param.tcs_min_pool > m_create_param.tcs_num - 1)
{
tcs_min_pool = m_create_param.tcs_num - 1;
tcs_eremove = 0;
}
else
{
tcs_min_pool = m_create_param.tcs_min_pool;
tcs_eremove = m_create_param.tcs_num -1 - m_create_param.tcs_min_pool;
}
// adding thread contexts corresponding to tcs_min_pool
/* There won't be any static threads if
* m_create_param.tcs_num is 1 or
* m_create_param_tcs_min_pool is 0 */
if (tcs_min_pool > 0)
{
auto end = m_layouts.end();
m_layouts.insert(end, thread_layouts.begin(), thread_layouts.end());
if (tcs_min_pool > 1)
{
// group for tcs min pool
memset(&layout, 0, sizeof(layout));
layout.group.id = LAYOUT_ID_THREAD_GROUP;
layout.group.entry_count = (uint16_t)(thread_layouts.size());
layout.group.load_times = tcs_min_pool - 1;
m_layouts.push_back(layout);
}
}
// adding thread contexts corresponding to tcs_eremove
if (tcs_eremove > 0)
{
for(auto l : thread_layouts)
{
if(l.entry.id != LAYOUT_ID_GUARD)
{
l.entry.attributes |= PAGE_ATTR_EREMOVE;
}
m_layouts.push_back(l);
}
if (tcs_eremove > 1)
{
memset(&layout, 0, sizeof(layout));
layout.group.id = LAYOUT_ID_THREAD_GROUP;
layout.group.entry_count = (uint16_t)(thread_layouts.size());
layout.group.load_times = tcs_eremove - 1;
m_layouts.push_back(layout);
}
}
// dynamic thread contexts
if (m_create_param.tcs_max_num > tcs_min_pool + 1)
{
for(auto l : thread_layouts)
{
if(l.entry.id == LAYOUT_ID_STACK_MAX)
{
l.entry.id = (uint16_t)(LAYOUT_ID_HEAP_DYN_MIN - LAYOUT_ID_HEAP_MIN + l.entry.id);
l.entry.attributes = PAGE_ATTR_POST_ADD | PAGE_DIR_GROW_DOWN;
}
else if(l.entry.id != LAYOUT_ID_GUARD)
{
l.entry.id = (uint16_t)(LAYOUT_ID_HEAP_DYN_MIN - LAYOUT_ID_HEAP_MIN + l.entry.id);
l.entry.attributes = PAGE_ATTR_POST_ADD | PAGE_ATTR_DYN_THREAD;
}
m_layouts.push_back(l);
}
// dynamic thread group
memset(&layout, 0, sizeof(layout));
layout.group.id = LAYOUT_ID_THREAD_GROUP_DYN;
layout.group.entry_count = (uint16_t)(thread_layouts.size());
layout.group.load_times = m_create_param.tcs_max_num - tcs_min_pool - 1;
m_layouts.push_back(layout);
}
// RSRV region
if (m_create_param.rsrv_min_size > 0 ||
m_create_param.rsrv_init_size > 0 ||
m_create_param.rsrv_max_size > 0)
{
memset(&layout, 0, sizeof(layout));
layout.entry.id = LAYOUT_ID_RSRV_MIN;
layout.entry.page_count = (uint32_t)(m_create_param.rsrv_min_size >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_EADD;
layout.entry.si_flags = m_create_param.rsrv_executable ? SI_FLAGS_RWX : SI_FLAGS_RW;
m_layouts.push_back(layout);
if (m_create_param.rsrv_init_size > m_create_param.rsrv_min_size)
{
layout.entry.id = LAYOUT_ID_RSRV_INIT;
layout.entry.page_count = (uint32_t)((m_create_param.rsrv_init_size - m_create_param.rsrv_min_size) >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_EADD | PAGE_ATTR_POST_REMOVE | PAGE_ATTR_POST_ADD;
layout.entry.si_flags = m_create_param.rsrv_executable ? SI_FLAGS_RWX : SI_FLAGS_RW;
m_layouts.push_back(layout);
}
if (m_create_param.rsrv_max_size > m_create_param.rsrv_init_size)
{
layout.entry.id = LAYOUT_ID_RSRV_MAX;
layout.entry.page_count = (uint32_t)((m_create_param.rsrv_max_size - m_create_param.rsrv_init_size) >> SE_PAGE_SHIFT);
layout.entry.attributes = PAGE_ATTR_POST_ADD;
layout.entry.si_flags = SI_FLAGS_RW;
m_layouts.push_back(layout);
}
}
// update layout entries
if(false == update_layout_entries())
{
return false;
}
// tcs template
if(false == build_tcs_template(tcs_template))
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
se_trace(SE_TRACE_ERROR, "Could not build TCS template\n");
return false;
}
return true;
}
bool CMetadata::build_patch_entries(std::vector<patch_entry_t> &patches)
{
uint32_t size = (uint32_t)(patches.size() * sizeof(patch_entry_t));
patch_entry_t *patch_table = (patch_entry_t *) alloc_buffer_from_metadata(size);
if(patch_table == NULL)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
se_trace(SE_TRACE_ERROR, "Could not allocate patch table");
return false;
}
m_metadata->dirs[DIR_PATCH].offset = (uint32_t)PTR_DIFF(patch_table, m_metadata);
m_metadata->dirs[DIR_PATCH].size = size;
for(uint32_t i = 0; i < patches.size(); i++)
{
memcpy_s(patch_table, sizeof(patch_entry_t), &patches[i], sizeof(patch_entry_t));
patch_table++;
}
return true;
}
bool CMetadata::build_patch_table()
{
const uint8_t *base_addr = (const uint8_t *)m_parser->get_start_addr();
std::vector<patch_entry_t> patches;
patch_entry_t patch;
memset(&patch, 0, sizeof(patch));
// td template
m_gd_size = m_parser->get_global_data_size();
m_gd_template = (uint8_t *)alloc_buffer_from_metadata(m_gd_size);
if(m_gd_template == NULL)
{
return false;
}
uint64_t rva = m_parser->get_symbol_rva("g_global_data");
if(0 == rva)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
se_trace(SE_TRACE_ERROR, "Could not find g_global_data\n");
return false;
}
// Check whether the same SDK is used for enclave building and signing
global_data_t *gdata = (global_data_t *)get_rawdata_by_rva(rva);
if (gdata -> sdk_version != VERSION_UINT)
{
se_trace(SE_TRACE_ERROR, SDK_VERSION_ERROR);
return false;
}
patch.dst = (uint64_t)PTR_DIFF(gdata, base_addr);
patch.src = (uint32_t)PTR_DIFF(m_gd_template, m_metadata);
patch.size = m_gd_size;
patches.push_back(patch);
// patch the image header
uint32_t size = 0;
uint8_t *zero = (uint8_t *)alloc_buffer_from_metadata(0); // get addr only, size will be determined later
if(zero == NULL)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
se_trace(SE_TRACE_ERROR, "Could not allocate 0 bytes\n");
return false;
}
bin_fmt_t bf = m_parser->get_bin_format();
if(bf == BF_ELF32)
{
Elf32_Ehdr *elf_hdr = (Elf32_Ehdr *)base_addr;
patch.dst = (uint64_t)PTR_DIFF(&elf_hdr->e_shnum, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(elf_hdr->e_shnum);
patches.push_back(patch);
size = patch.size;
patch.dst = (uint64_t)PTR_DIFF(&elf_hdr->e_shoff, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(elf_hdr->e_shoff);
patches.push_back(patch);
if (patch.size > size) size = patch.size;
patch.dst = (uint64_t)PTR_DIFF(&elf_hdr->e_shstrndx, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(elf_hdr->e_shstrndx);
patches.push_back(patch);
if (patch.size > size) size = patch.size;
// Modify GNU_RELRO info to eliminate the impact of enclave measurement.
Elf32_Phdr *prg_hdr = GET_PTR(Elf32_Phdr, base_addr, elf_hdr->e_phoff);
for (unsigned idx = 0; idx < elf_hdr->e_phnum; ++idx, ++prg_hdr)
{
if(prg_hdr->p_type == PT_GNU_RELRO)
{
patch.dst = (uint64_t)PTR_DIFF(prg_hdr, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(Elf32_Phdr);
patches.push_back(patch);
if (patch.size > size) size = patch.size;
break;
}
}
}
else if(bf == BF_ELF64)
{
Elf64_Ehdr *elf_hdr = (Elf64_Ehdr *)base_addr;
patch.dst = (uint64_t)PTR_DIFF(&elf_hdr->e_shnum, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(elf_hdr->e_shnum);
patches.push_back(patch);
size = patch.size;
patch.dst = (uint64_t)PTR_DIFF(&elf_hdr->e_shoff, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(elf_hdr->e_shoff);
patches.push_back(patch);
if (patch.size > size) size = patch.size;
patch.dst = (uint64_t)PTR_DIFF(&elf_hdr->e_shstrndx, base_addr);
patch.src = (uint32_t)PTR_DIFF(zero, m_metadata);
patch.size = (uint32_t)sizeof(elf_hdr->e_shstrndx);
patches.push_back(patch);
if (patch.size > size) size = patch.size;
}
zero = (uint8_t *)alloc_buffer_from_metadata(size); // alloc buffer again with the accurate size
if(zero == NULL)
{
se_trace(SE_TRACE_ERROR, INVALID_ENCLAVE_ERROR);
return false;
}
memset(zero, 0, size);
if(false == build_patch_entries(patches))
{
se_trace(SE_TRACE_ERROR, NO_MEMORY_ERROR);
return false;
}
return true;
}
layout_entry_t *CMetadata::get_entry_by_id(uint16_t id, bool do_assert = true)
{
for (uint32_t i = 0; i < m_layouts.size(); i++)
{
if(m_layouts[i].entry.id == id)
return (layout_entry_t *)&m_layouts[i];
}
if (do_assert)
assert(false);
return NULL;
}
bool CMetadata::get_xsave_size(uint64_t xfrm, uint32_t *xsave_size)
{
assert (xsave_size != NULL);
struct {
uint64_t bits;
uint32_t size;
} xsave_size_table[] = { // Note that the xsave_size should be in ascending order
{SGX_XFRM_LEGACY, 512 + 64}, // 512 for legacy features, 64 for xsave header
{SGX_XFRM_AVX, 512 + 64 + 256}, // 256 for YMM0_H - YMM15_H registers
{SGX_XFRM_MPX, 512 + 64 + 256 + 256}, // 256 for MPX
{SGX_XFRM_AVX512, 512 + 64 + 256 + 256 + 1600}, // 1600 for k0 - k7, ZMM0_H - ZMM15_H, ZMM16 - ZMM31
// PT, PKRU ...
};
bool ret = true;
*xsave_size = 0;
if(!xfrm || (xfrm & SGX_XFRM_RESERVED))
{
return false;
}
for(size_t i = 0; i < sizeof(xsave_size_table)/sizeof(xsave_size_table[0]); i++)
{
if((xfrm & xsave_size_table[i].bits) == xsave_size_table[i].bits)
{
*xsave_size = xsave_size_table[i].size;
}
}
return ret;
}
bool CMetadata::build_gd_template(uint8_t *data, uint32_t *data_size)
{
if(false == get_xsave_size(m_metadata->attributes.xfrm, &m_create_param.xsave_size))
{
return false;
}
m_create_param.stack_base_addr = (size_t)(get_entry_by_id(LAYOUT_ID_STACK_MIN)->rva + m_create_param.stack_min_size - get_entry_by_id(LAYOUT_ID_TCS)->rva);
m_create_param.stack_limit_addr = (size_t)(m_create_param.stack_base_addr - m_create_param.stack_max_size);
m_create_param.ssa_base_addr = (size_t)(get_entry_by_id(LAYOUT_ID_SSA)->rva - get_entry_by_id(LAYOUT_ID_TCS)->rva);
m_create_param.enclave_size = m_metadata->enclave_size;
m_create_param.heap_offset = (size_t)get_entry_by_id(LAYOUT_ID_HEAP_MIN)->rva;
layout_entry_t * layout_rsrv = get_entry_by_id(LAYOUT_ID_RSRV_MIN, false);
if (NULL == layout_rsrv)
{
m_create_param.rsrv_offset = (size_t)0;
}
else
{
m_create_param.rsrv_offset = (size_t)layout_rsrv->rva;
}
size_t tmp_tls_addr = (size_t)(get_entry_by_id(LAYOUT_ID_TD)->rva - get_entry_by_id(LAYOUT_ID_TCS)->rva);
m_create_param.td_addr = tmp_tls_addr + (size_t)((get_entry_by_id(LAYOUT_ID_TD)->page_count - 1) << SE_PAGE_SHIFT);
const Section *section = m_parser->get_tls_section();
if(section)
{
/* adjust the tls_addr to be the pointer to the actual TLS data area */
m_create_param.tls_addr = (size_t)(m_create_param.td_addr - section->virtual_size());
assert(TRIM_TO_PAGE(m_create_param.tls_addr) == tmp_tls_addr);
}
else
m_create_param.tls_addr = tmp_tls_addr;
if(false == m_parser->update_global_data(m_metadata, &m_create_param, data, data_size))
{
se_trace(SE_TRACE_ERROR, NO_MEMORY_ERROR); // metadata structure doesnot have enough memory for global_data template
return false;
}
return true;
}
bool CMetadata::build_tcs_template(tcs_t *tcs)
{
tcs->oentry = m_parser->get_symbol_rva("enclave_entry");
if(tcs->oentry == 0)
{
return false;
}
tcs->nssa = SSA_NUM;
tcs->cssa = 0;
tcs->ossa = get_entry_by_id(LAYOUT_ID_SSA)->rva - get_entry_by_id(LAYOUT_ID_TCS)->rva;
//fs/gs pointer at TLS/TD
tcs->ofs_base = tcs->ogs_base = get_entry_by_id(LAYOUT_ID_TD)->rva - get_entry_by_id(LAYOUT_ID_TCS)->rva + (((uint64_t)get_entry_by_id(LAYOUT_ID_TD)->page_count - 1) << SE_PAGE_SHIFT);
tcs->ofs_limit = tcs->ogs_limit = (uint32_t)-1;
return true;
}
void* CMetadata::get_rawdata_by_rva(uint64_t rva)
{
std::vector<Section*> sections = m_parser->get_sections();
for(unsigned int i = 0; i < sections.size() ; i++)
{
uint64_t start_rva = TRIM_TO_PAGE(sections[i]->get_rva());
uint64_t end_rva = ROUND_TO_PAGE(sections[i]->get_rva() + sections[i]->virtual_size());
if(start_rva <= rva && rva < end_rva)
{
uint64_t offset = rva - sections[i]->get_rva();
if (offset > sections[i]->raw_data_size())
{
return 0;
}
return GET_PTR(void, sections[i]->raw_data(), offset);
}
}
return 0;
}
uint64_t CMetadata::calculate_sections_size()
{
std::vector<Section*> sections = m_parser->get_sections();
uint64_t max_rva = 0;
Section *last_section = NULL;
for(unsigned int i = 0; i < sections.size() ; i++)
{
if(sections[i]->get_rva() > max_rva) {
max_rva = sections[i]->get_rva();
last_section = sections[i];
}
}
uint64_t size = (NULL == last_section) ? (0) : (last_section->get_rva() + last_section->virtual_size());
size = ROUND_TO_PAGE(size);
return size;
}
uint64_t CMetadata::calculate_enclave_size(uint64_t size)
{
uint64_t enclave_max_size = m_parser->get_enclave_max_size();
if(size > enclave_max_size)
return (uint64_t)-1;
uint64_t round_size = 1;
while (round_size < size)
{
round_size <<=1;
if(!round_size)
return (uint64_t)-1;
}
se_trace(SE_TRACE_DEBUG, "Enclave: Size = 0x%016llX, Rounded Size = 0x%016llX\n", size, round_size);
if(round_size > enclave_max_size)
return (uint64_t)-1;
return round_size;
}
bool update_metadata(const char *path, const metadata_t *metadata, uint64_t meta_offset)
{
assert(path != NULL && metadata != NULL);
return write_data_to_file(path, std::ios::in | std::ios::binary| std::ios::out,
reinterpret_cast<uint8_t *>(const_cast<metadata_t *>( metadata)), METADATA_SIZE, (long)meta_offset);
}
#define PRINT_ELEMENT(stream, structure, element) \
do { \
(stream) << #structure << "->" << #element << ": " << std::hex << "0x" << structure->element << std::endl; \
}while(0)
#define PRINT_ARRAY(stream, structure, array, size) \
do{ \
(stream) << #structure << "->" << #array << ":" << std::hex; \
for(size_t i = 0; i < size; i++) \
{ \
if (i % 16 == 0) (stream) << std::endl; \
(stream) << "0x" << std::setfill('0') << std::setw(2) << (uint32_t)(structure)->array[i] << " "; \
} \
(stream) << std::endl; \
}while(0)
#define CONCAT(name, num) name##num
#define A(num) CONCAT(metadata, num)
static void print_metadata_internal(std::ofstream &meta_ofs, const metadata_t *metadata)
{
assert(metadata != NULL);
PRINT_ELEMENT(meta_ofs, metadata, magic_num);
PRINT_ELEMENT(meta_ofs, metadata, version);
PRINT_ELEMENT(meta_ofs, metadata, size);
PRINT_ELEMENT(meta_ofs, metadata, tcs_policy);
PRINT_ELEMENT(meta_ofs, metadata, ssa_frame_size);
PRINT_ELEMENT(meta_ofs, metadata, max_save_buffer_size);
PRINT_ELEMENT(meta_ofs, metadata, desired_misc_select);
PRINT_ELEMENT(meta_ofs, metadata, enclave_size);
PRINT_ELEMENT(meta_ofs, metadata, attributes.flags);
PRINT_ELEMENT(meta_ofs, metadata, attributes.xfrm);
// css.header
PRINT_ARRAY(meta_ofs, metadata, enclave_css.header.header, 12);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.header.type);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.header.module_vendor);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.header.date);
PRINT_ARRAY(meta_ofs, metadata, enclave_css.header.header2, 16);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.header.hw_version);
// css.key
PRINT_ARRAY(meta_ofs, metadata, enclave_css.key.modulus, SE_KEY_SIZE);
PRINT_ARRAY(meta_ofs, metadata, enclave_css.key.exponent, SE_EXPONENT_SIZE);
PRINT_ARRAY(meta_ofs, metadata, enclave_css.key.signature, SE_KEY_SIZE);
// css.body
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.misc_select);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.misc_mask);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.attributes.flags);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.attributes.xfrm);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.attribute_mask.flags);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.attribute_mask.xfrm);
PRINT_ARRAY(meta_ofs, metadata, enclave_css.body.enclave_hash.m, SGX_HASH_SIZE);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.isv_prod_id);
PRINT_ELEMENT(meta_ofs, metadata, enclave_css.body.isv_svn);
// css.buffer
PRINT_ARRAY(meta_ofs, metadata, enclave_css.buffer.q1, SE_KEY_SIZE);
PRINT_ARRAY(meta_ofs, metadata, enclave_css.buffer.q2, SE_KEY_SIZE);
}
bool print_metadata(const char *path, const metadata_t *metadata)
{
assert(path != NULL && metadata != NULL);
std::ofstream meta_ofs(path, std::ofstream::out | std::ofstream::trunc);
if (!meta_ofs.good())
{
se_trace(SE_TRACE_ERROR, OPEN_FILE_ERROR, path);
return false;
}
meta_ofs << "=============================" << std::endl
<< "The metadata information:" << std::endl
<< "=============================" << std::endl;
print_metadata_internal(meta_ofs, metadata);
// Print the compatible metadata info
size_t compat_meta_count = 0;
do {
metadata_t *compatible_metadata = GET_PTR(metadata_t, metadata, metadata->size);
if(compatible_metadata == NULL || (compatible_metadata->magic_num == METADATA_MAGIC && compatible_metadata->size == 0))
{
meta_ofs.close();
return false;
}
if(compatible_metadata->magic_num != METADATA_MAGIC)
break;
compat_meta_count++;
if(compat_meta_count == 1)
{
meta_ofs << std::endl << std::endl << std::endl
<< "====================================" << std::endl
<< "The compatible metadata information: " << std::endl
<< "====================================" << std::endl;
}
meta_ofs << std::endl << "Compatible metadata number "
<< compat_meta_count << ":" << std::endl
<< "------------------------------" << std::endl;
print_metadata_internal(meta_ofs, compatible_metadata);
metadata = compatible_metadata;
}while(1);
typedef struct _mrsigner_t
{
uint8_t value[SGX_HASH_SIZE];
} mrsigner_t;
mrsigner_t ms;
memset(&ms, 0, sizeof(mrsigner_t));
mrsigner_t *mrsigner = &ms;
unsigned int signer_len = SGX_HASH_SIZE;
if(sgx_EVP_Digest(EVP_sha256(), metadata->enclave_css.key.modulus, SE_KEY_SIZE, ms.value, &signer_len) != SGX_SUCCESS)
{
se_trace(SE_TRACE_ERROR, "ERROR: failed to calculate the mrsigner.\n");
meta_ofs.close();
return false;
}
meta_ofs << std::endl << std::endl
<< "===================" << std::endl
<< "The mrsigner value:" << std::endl
<< "===================" << std::endl;
PRINT_ARRAY(meta_ofs, mrsigner, value, SGX_HASH_SIZE);
meta_ofs.close();
return true;
}