diff --git a/cmake/add_enclave_executable.cmake b/cmake/add_enclave_executable.cmake index 94018e14c59..3a6432d89c5 100644 --- a/cmake/add_enclave_executable.cmake +++ b/cmake/add_enclave_executable.cmake @@ -28,7 +28,7 @@ function(add_enclave_executable BIN SIGNCONF) # custom rule to sign the binary add_custom_command(OUTPUT ${BIN}.signed.so - COMMAND oesign $ ${SIGNCONF} ${CMAKE_CURRENT_BINARY_DIR}/${BIN}-private.pem + COMMAND oesign "sign" $ ${SIGNCONF} ${CMAKE_CURRENT_BINARY_DIR}/${BIN}-private.pem DEPENDS oesign ${BIN} ${SIGNCONF} ${BIN}-private.pem WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/tools/oesign/CMakeLists.txt b/tools/oesign/CMakeLists.txt index 95a4b32e580..4bacc139b7d 100644 --- a/tools/oesign/CMakeLists.txt +++ b/tools/oesign/CMakeLists.txt @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -add_executable(oesign main.c) +add_executable(oesign main.c oedump.c) target_link_libraries(oesign oehost) diff --git a/tools/oesign/main.c b/tools/oesign/main.c index 100d3be316c..96ced3b6a4c 100644 --- a/tools/oesign/main.c +++ b/tools/oesign/main.c @@ -13,6 +13,7 @@ #include "../host/enclave.h" static const char* arg0; +void oedump(const char*); OE_PRINTF_FORMAT(1, 2) void Err(const char* format, ...) @@ -456,13 +457,29 @@ void _merge_config_file_options( properties->header.size_settings.num_tcs = options->num_tcs; } -static const char _usage[] = - "Usage: %s EnclaveImage ConfigFile KeyFile\n" +static const char _usage_gen[] = + "Usage: %s [options]\n" + + "\n" + + "Commands:\n" + + " sign - Sign the specified enclave.\n" + + " dump - Print out the Open Enclave metadata for the specified " + "enclave.\n" + + "\n" + + "For help with a specific command, enter \"%s -?\"\n"; + +static const char _usage_sign[] = + "Usage: %s enclave_image sign config_file key_file\n" "\n" "Where:\n" - " EnclaveImage -- path of an enclave image file\n" - " ConfigFile -- configuration file containing enclave properties\n" - " KeyFile -- private key file used to digitally sign the image\n" + " enclave_image -- path of an enclave image file\n" + " config_file -- configuration file containing enclave properties\n" + " key_file -- private key file used to digitally sign the image\n" "\n" "Description:\n" " This utility (1) injects runtime properties into an enclave image " @@ -497,6 +514,62 @@ static const char _usage[] = " The resulting image is written to .signed.so.\n" "\n"; +static const char _usage_dump[] = + "\n" + "Usage: %s enclave_image dump\n" + "\n" + "Where:\n" + " enclave_image -- path of an enclave image file\n" + "\n" + "Description:\n" + " This option dumps the oeinfo and signature information of an " + "enclave\n"; + +int arg_handler(int argc, const char* argv[]) +{ + const char* enclave; + + switch (argc) + { + case 1: + case 2: + fprintf(stderr, _usage_gen, argv[0], argv[0]); + exit(1); + case 3: + if (strcmp(argv[1], "dump") == 0) + { + if (strcmp(argv[2], "-?") == 0) + { + fprintf(stderr, _usage_dump, argv[0]); + exit(1); + } + enclave = argv[2]; + /* dump oeinfo and signature information */ + oedump(enclave); + exit(0); + } + else if (strcmp(argv[1], "sign") == 0) + { + if (strcmp(argv[2], "-?") == 0) + { + fprintf(stderr, _usage_sign, argv[0]); + exit(1); + } + + fprintf(stderr, _usage_gen, argv[0], argv[0]); + exit(1); + } + case 5: + if (strcmp(argv[1], "sign") == 0) + return 0; + fprintf(stderr, _usage_gen, argv[0], argv[0]); + exit(1); + default: + fprintf(stderr, _usage_gen, argv[0], argv[0]); + exit(1); + } +} + int main(int argc, const char* argv[]) { arg0 = argv[0]; @@ -512,17 +585,12 @@ int main(int argc, const char* argv[]) oe_sgx_enclave_properties_t props; oe_sgx_load_context_t context; - /* Check arguments */ - if (argc != 4) - { - fprintf(stderr, _usage, arg0); - exit(1); - } + arg_handler(argc, argv); - /* Collect arguments */ - enclave = argv[1]; - conffile = argv[2]; - keyfile = argv[3]; + /* Collect arguments for signing*/ + enclave = argv[2]; + conffile = argv[3]; + keyfile = argv[4]; /* Load the configuration file */ if (_load_config_file(conffile, &options) != 0) diff --git a/tools/oesign/oedump.c b/tools/oesign/oedump.c new file mode 100644 index 00000000000..ac6f39d0b33 --- /dev/null +++ b/tools/oesign/oedump.c @@ -0,0 +1,353 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +size_t errors = 0; + +static bool verbose_opt = false; + +/* Find enclave property struct within an .oeinfo section */ +static oe_result_t _find_enclave_properties( + uint8_t* section_data, + size_t section_size, + oe_enclave_type_t enclave_type, + size_t struct_size, + oe_sgx_enclave_properties_t** enclave_properties) +{ + oe_result_t result = OE_UNEXPECTED; + uint8_t* ptr = section_data; + size_t bytes_remaining = section_size; + + *enclave_properties = NULL; + + /* While there are more enclave property structures */ + while (bytes_remaining >= struct_size) + { + oe_sgx_enclave_properties_t* p = (oe_sgx_enclave_properties_t*)ptr; + + if (p->header.enclave_type == enclave_type) + { + if (p->header.size != struct_size) + { + result = OE_FAILURE; + goto done; + } + + /* Found it! */ + *enclave_properties = p; + break; + } + + /* If size of structure extends beyond end of section */ + if (p->header.size > bytes_remaining) + break; + + ptr += p->header.size; + bytes_remaining -= p->header.size; + } + + if (*enclave_properties == NULL) + { + result = OE_NOT_FOUND; + goto done; + } + + result = OE_OK; + +done: + return result; +} + +oe_result_t oe_sgx_load_properties( + const elf64_t* elf, + const char* section_name, + oe_sgx_enclave_properties_t* properties) +{ + oe_result_t result = OE_UNEXPECTED; + uint8_t* section_data; + size_t section_size; + + if (properties) + memset(properties, 0, sizeof(*properties)); + + /* Check for null parameter */ + if (!elf || !section_name || !properties) + { + result = OE_INVALID_PARAMETER; + goto done; + } + + /* Get pointer to and size of the given section */ + if (elf64_find_section(elf, section_name, §ion_data, §ion_size) != + 0) + { + result = OE_NOT_FOUND; + goto done; + } + + /* Find SGX enclave property struct */ + { + oe_sgx_enclave_properties_t* enclave_properties; + + if ((result = _find_enclave_properties( + section_data, + section_size, + OE_ENCLAVE_TYPE_SGX, + sizeof(oe_sgx_enclave_properties_t), + &enclave_properties)) != OE_OK) + { + result = OE_NOT_FOUND; + goto done; + } + + OE_CHECK( + oe_memcpy_s( + properties, + sizeof(*properties), + enclave_properties, + sizeof(*enclave_properties))); + } + + result = OE_OK; + +done: + return result; +} + +OE_PRINTF_FORMAT(1, 2) +void err(const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "*** Error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + errors++; +} + +void dump_entry_point(elf64_t* elf) +{ + elf64_sym_t sym; + const char* name; + + if (elf64_find_dynamic_symbol_by_address( + elf, elf64_get_header(elf)->e_entry, STT_FUNC, &sym) != 0) + { + err("cannot find entry point symbol"); + return; + } + + if (!(name = elf64_get_string_from_dynstr(elf, sym.st_name))) + { + err("cannot resolve entry point name"); + return; + } + + if (strcmp(name, "_start") != 0) + { + err("invalid entry point name: %s", name); + return; + } + + printf("=== Entry point: \n"); + printf("name=%s\n", name); + printf("address=%016llx\n", OE_LLX(sym.st_value)); + printf("\n"); +} + +void dump_enclave_properties(const oe_sgx_enclave_properties_t* props) +{ + const sgx_sigstruct_t* sigstruct; + + printf("=== SGX Enclave Properties:\n"); + + printf("product_id=%u\n", props->config.product_id); + + printf("security_version=%u\n", props->config.security_version); + + bool debug = props->config.attributes & OE_SGX_FLAGS_DEBUG; + printf("debug=%u\n", debug); + + printf( + "num_heap_pages=%llu\n", + OE_LLU(props->header.size_settings.num_heap_pages)); + + printf( + "num_stack_pages=%llu\n", + OE_LLU(props->header.size_settings.num_stack_pages)); + + printf("num_tcs=%llu\n", OE_LLU(props->header.size_settings.num_tcs)); + + sigstruct = (const sgx_sigstruct_t*)props->sigstruct; + + printf("mrenclave="); + oe_hex_dump(sigstruct->enclavehash, sizeof(sigstruct->enclavehash)); + + printf("signature="); + oe_hex_dump(sigstruct->signature, sizeof(sigstruct->signature)); + + printf("\n"); + + if (verbose_opt) + __sgx_dump_sigstruct(sigstruct); +} + +typedef struct _visit_sym_data +{ + const elf64_t* elf; + const elf64_shdr_t* shdr; + oe_result_t result; +} visit_sym_data_t; + +static int _visit_sym(const elf64_sym_t* sym, void* data_) +{ + int rc = -1; + visit_sym_data_t* data = (visit_sym_data_t*)data_; + const elf64_shdr_t* shdr = data->shdr; + const char* name; + + data->result = OE_UNEXPECTED; + + /* Skip symbol if not a function */ + if ((sym->st_info & 0x0F) != STT_FUNC) + { + rc = 0; + goto done; + } + + /* Skip symbol if not in the ".ecall" section */ + if (sym->st_value < shdr->sh_addr || + sym->st_value + sym->st_size > shdr->sh_addr + shdr->sh_size) + { + rc = 0; + goto done; + } + + /* Skip null names */ + if (!(name = elf64_get_string_from_dynstr(data->elf, sym->st_name))) + { + rc = 0; + goto done; + } + + /* Dump the ECALL name */ + printf("%s (%016llx)\n", name, OE_LLX(sym->st_value)); + + rc = 0; + +done: + return rc; +} + +void dump_ecall_section(elf64_t* elf) +{ + elf64_shdr_t shdr; + + printf("=== ECALLs:\n"); + + /* Find the .ecall section */ + if (elf64_find_section_header(elf, ".ecall", &shdr) != 0) + { + err("missing .ecall section"); + return; + } + + /* Dump all the ECALLs */ + { + visit_sym_data_t data; + data.elf = elf; + data.shdr = &shdr; + + if (elf64_visit_symbols(elf, _visit_sym, &data) != 0) + { + err("failed to find ECALLs in .ecall section"); + return; + } + } + + printf("\n"); +} + +void check_global(elf64_t* elf, const char* name) +{ + elf64_sym_t sym; + + if (elf64_find_dynamic_symbol_by_name(elf, name, &sym) != 0) + { + err("failed to find required symbol: %s\n", name); + return; + } + + printf("%s (%016llx)\n", name, OE_LLX(sym.st_value)); +} + +void check_globals(elf64_t* elf) +{ + printf("=== Globals:\n"); + + check_global(elf, "oe_num_pages"); + check_global(elf, "oe_virtual_base_addr"); + check_global(elf, "oe_base_reloc_page"); + check_global(elf, "oe_num_reloc_pages"); + check_global(elf, "oe_base_ecall_page"); + check_global(elf, "oe_num_ecall_pages"); + check_global(elf, "oe_base_heap_page"); + check_global(elf, "oe_num_heap_pages"); + + printf("\n"); +} + +void oedump(const char* enc_bin) +{ + elf64_t elf; + oe_sgx_enclave_properties_t props; + + /* Load the ELF-64 object */ + if (elf64_load(enc_bin, &elf) != 0) + { + fprintf(stderr, "failed to load %s\n", enc_bin); + goto done; + } + + /* Load the SGX enclave properties */ + if (oe_sgx_load_properties(&elf, OE_INFO_SECTION_NAME, &props) != OE_OK) + { + err("failed to load SGX enclave properties from %s section", + OE_INFO_SECTION_NAME); + } + + printf("\n"); + + /* Dump the entry point */ + dump_entry_point(&elf); + + /* Dump the signature section */ + dump_enclave_properties(&props); + + /* Dump the ECALL section */ + dump_ecall_section(&elf); + + /* Check globals */ + check_globals(&elf); + + if (errors) + { + fprintf(stderr, "*** Found %zu errors\n", errors); + goto done; + } + +done: + elf64_unload(&elf); + return; +}