diff --git a/demos/remote_attestation/maa/README.md b/demos/remote_attestation/maa/README.md new file mode 100644 index 00000000..1c9b466b --- /dev/null +++ b/demos/remote_attestation/maa/README.md @@ -0,0 +1,39 @@ +## Sample code for Occlum Remote Attestation to generate Microsoft Azure Attestation json file + +### References +* Part of the sample code, specifically the part to generate MAA format json file, is derived from the [Sample code for IntelĀ® SGX Attestation using Microsoft Azure Attestation service and IntelĀ® SGX SDK for Linux OS](https://github.com/Azure-Samples/microsoft-azure-attestation/tree/master/intel.sdk.attest.sample) + +## Prerequisites + +- Platform: Intel SGX enabled platform with DCAP installed. Follow [DCAP + Quick Install + Guide](https://software.intel.com/content/www/us/en/develop/articles/intel-software-guard-extensions-data-center-attestation-primitives-quick-install-guide.html) + for the detailed installation procedure. + +- Container: Start the Occlum latest docker container image for the demo. Follow + the [guide](https://github.com/occlum/occlum#how-to-use). + +Remember to configure `/etc/sgx_default_qcnl.conf` +in the container according to your PCCS setting after running the docker image. + +### Overview + +The full Microsoft Azure Attestation flow includes generating a quote in an SGX enclave and then get it validated by the Microsoft [`Azure Attestation (MAA) service`](https://github.com/Azure-Samples/microsoft-azure-attestation). + +There are five steps for a full flow MAA. + +1. Build an SGX enclave +2. Launch an SGX enclave and get SGX quote +3. Persist SGX quote and Enclave Held Data (EHD) to JSON file +4. Call Azure Attestation for validation +5. Output validation results + +This demo only covers the first three steps. + +* Build and Run +``` +# ./run.sh +``` + +Once successful, four different MAA format json files are saved in `out` dir. +With the generated MAA format json files, users could continue on step 4 and 5 with general MAA service APIs to do validation. diff --git a/demos/remote_attestation/maa/config/Occlum.json b/demos/remote_attestation/maa/config/Occlum.json new file mode 100644 index 00000000..c5a45d24 --- /dev/null +++ b/demos/remote_attestation/maa/config/Occlum.json @@ -0,0 +1,74 @@ +{ + "resource_limits": { + "kernel_space_heap_size": "32MB", + "kernel_space_stack_size": "1MB", + "user_space_size": "300MB", + "max_num_of_threads": 32 + }, + "process": { + "default_stack_size": "4MB", + "default_heap_size": "32MB", + "default_mmap_size": "100MB" + }, + "entry_points": [ + "/bin" + ], + "env": { + "default": [ + "OCCLUM=yes" + ], + "untrusted": [ + "EXAMPLE" + ] + }, + "metadata": { + "product_id": 0, + "version_number": 0, + "debuggable": true, + "enable_kss": false, + "family_id": { + "high": "0x0", + "low": "0x0" + }, + "ext_prod_id": { + "high": "0x0", + "low": "0x0" + } + }, + "mount": [ + { + "target": "/", + "type": "unionfs", + "options": { + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./build/mount/__ROOT", + "options": { + "MAC": "" + } + }, + { + "target": "/", + "type": "sefs", + "source": "./run/mount/__ROOT" + } + ] + } + }, + { + "target": "/host", + "type": "hostfs", + "source": "." + }, + { + "target": "/proc", + "type": "procfs" + }, + { + "target": "/dev", + "type": "devfs" + } + ] +} diff --git a/demos/remote_attestation/maa/config/Occlum_prodid.json b/demos/remote_attestation/maa/config/Occlum_prodid.json new file mode 100644 index 00000000..dc2254ff --- /dev/null +++ b/demos/remote_attestation/maa/config/Occlum_prodid.json @@ -0,0 +1,74 @@ +{ + "resource_limits": { + "kernel_space_heap_size": "32MB", + "kernel_space_stack_size": "1MB", + "user_space_size": "300MB", + "max_num_of_threads": 32 + }, + "process": { + "default_stack_size": "4MB", + "default_heap_size": "32MB", + "default_mmap_size": "100MB" + }, + "entry_points": [ + "/bin" + ], + "env": { + "default": [ + "OCCLUM=yes" + ], + "untrusted": [ + "EXAMPLE" + ] + }, + "metadata": { + "product_id": 9999, + "version_number": 0, + "debuggable": false, + "enable_kss": false, + "family_id": { + "high": "0x0", + "low": "0x0" + }, + "ext_prod_id": { + "high": "0x0", + "low": "0x0" + } + }, + "mount": [ + { + "target": "/", + "type": "unionfs", + "options": { + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./build/mount/__ROOT", + "options": { + "MAC": "" + } + }, + { + "target": "/", + "type": "sefs", + "source": "./run/mount/__ROOT" + } + ] + } + }, + { + "target": "/host", + "type": "hostfs", + "source": "." + }, + { + "target": "/proc", + "type": "procfs" + }, + { + "target": "/dev", + "type": "devfs" + } + ] +} diff --git a/demos/remote_attestation/maa/config/Occlum_release.json b/demos/remote_attestation/maa/config/Occlum_release.json new file mode 100644 index 00000000..d08f26ea --- /dev/null +++ b/demos/remote_attestation/maa/config/Occlum_release.json @@ -0,0 +1,74 @@ +{ + "resource_limits": { + "kernel_space_heap_size": "32MB", + "kernel_space_stack_size": "1MB", + "user_space_size": "300MB", + "max_num_of_threads": 32 + }, + "process": { + "default_stack_size": "4MB", + "default_heap_size": "32MB", + "default_mmap_size": "100MB" + }, + "entry_points": [ + "/bin" + ], + "env": { + "default": [ + "OCCLUM=yes" + ], + "untrusted": [ + "EXAMPLE" + ] + }, + "metadata": { + "product_id": 0, + "version_number": 0, + "debuggable": false, + "enable_kss": false, + "family_id": { + "high": "0x0", + "low": "0x0" + }, + "ext_prod_id": { + "high": "0x0", + "low": "0x0" + } + }, + "mount": [ + { + "target": "/", + "type": "unionfs", + "options": { + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./build/mount/__ROOT", + "options": { + "MAC": "" + } + }, + { + "target": "/", + "type": "sefs", + "source": "./run/mount/__ROOT" + } + ] + } + }, + { + "target": "/host", + "type": "hostfs", + "source": "." + }, + { + "target": "/proc", + "type": "procfs" + }, + { + "target": "/dev", + "type": "devfs" + } + ] +} diff --git a/demos/remote_attestation/maa/config/Occlum_securityversion.json b/demos/remote_attestation/maa/config/Occlum_securityversion.json new file mode 100644 index 00000000..60eee347 --- /dev/null +++ b/demos/remote_attestation/maa/config/Occlum_securityversion.json @@ -0,0 +1,74 @@ +{ + "resource_limits": { + "kernel_space_heap_size": "32MB", + "kernel_space_stack_size": "1MB", + "user_space_size": "300MB", + "max_num_of_threads": 32 + }, + "process": { + "default_stack_size": "4MB", + "default_heap_size": "32MB", + "default_mmap_size": "100MB" + }, + "entry_points": [ + "/bin" + ], + "env": { + "default": [ + "OCCLUM=yes" + ], + "untrusted": [ + "EXAMPLE" + ] + }, + "metadata": { + "product_id": 0, + "version_number": 8888, + "debuggable": false, + "enable_kss": false, + "family_id": { + "high": "0x0", + "low": "0x0" + }, + "ext_prod_id": { + "high": "0x0", + "low": "0x0" + } + }, + "mount": [ + { + "target": "/", + "type": "unionfs", + "options": { + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./build/mount/__ROOT", + "options": { + "MAC": "" + } + }, + { + "target": "/", + "type": "sefs", + "source": "./run/mount/__ROOT" + } + ] + } + }, + { + "target": "/host", + "type": "hostfs", + "source": "." + }, + { + "target": "/proc", + "type": "procfs" + }, + { + "target": "/dev", + "type": "devfs" + } + ] +} diff --git a/demos/remote_attestation/maa/gen_quote/Makefile b/demos/remote_attestation/maa/gen_quote/Makefile new file mode 100644 index 00000000..7d793a99 --- /dev/null +++ b/demos/remote_attestation/maa/gen_quote/Makefile @@ -0,0 +1,16 @@ +CC ?= gcc + +LDFLAGS += -L/opt/occlum/toolchains/dcap_lib/glibc \ + -locclum_dcap -lssl -lcrypto +CFLAGS += -fPIE -pie -I /opt/intel/sgxsdk/include \ + -I /opt/occlum/toolchains/dcap_lib/inc + +.PHONY: all clean + +all: gen_maa_json + +gen_maa_json: gen_maa_json.c + $(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@ + +clean: + rm -rf gen_maa_json diff --git a/demos/remote_attestation/maa/gen_quote/gen_maa_json.c b/demos/remote_attestation/maa/gen_quote/gen_maa_json.c new file mode 100644 index 00000000..fe3b29a6 --- /dev/null +++ b/demos/remote_attestation/maa/gen_quote/gen_maa_json.c @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +#include "sgx_quote_3.h" +#include "occlum_dcap.h" + +#define MAA_JSON "/host/maa.json" + +void sha256sum(const uint8_t *data, uint32_t data_size, uint8_t *hash) +{ + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, data, data_size); + SHA256_Final(hash, &sha256); +} + +const char *uint16_to_buffer (char *buffer, unsigned int maxSize, uint16_t n, size_t size) +{ + if (size * 2 >= maxSize || size < 2) + return "DEADBEEF"; + sprintf(&buffer[0], "%02X", (uint8_t)(n)); + sprintf(&buffer[2], "%02X", (uint8_t)(n >> 8)); + + for (int i=2; i < size; i++) + { + sprintf(&buffer[i*2], "%02X", 0); + } + buffer[size*2+1] = '\0'; + return buffer; +} + +const char *format_hex_buffer (char *buffer, unsigned int maxSize, uint8_t *data, size_t size) +{ + if (size * 2 >= maxSize) + return "DEADBEEF"; + + for (int i=0; i < size; i++) + { + sprintf(&buffer[i*2], "%02X", data[i]); + } + buffer[size*2+1] = '\0'; + return buffer; +} + + +void main() { + void *handle; + uint32_t quote_size; + uint8_t *p_quote_buffer; + sgx_quote3_t *p_quote; + sgx_report_body_t *p_report_body; + sgx_report_data_t *p_report_data; + int32_t ret; + + const int hex_buffer_size = 1024*64; + char hex_buffer[hex_buffer_size]; + + handle = dcap_quote_open(); + quote_size = dcap_get_quote_size(handle); + printf("quote size = %d\n", quote_size); + + p_quote_buffer = (uint8_t*)malloc(quote_size); + if (NULL == p_quote_buffer) { + printf("Couldn't allocate quote_buffer\n"); + goto CLEANUP; + } + memset(p_quote_buffer, 0, quote_size); + + uint8_t enclave_held_data[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; + sgx_report_data_t hash = {0}; + sha256sum(enclave_held_data, 6, hash.d); + // printf("report data hash:\n"); + // for (int i = 0; i < sizeof(hash.d); i++) { + // if (!(i % 16)) + // printf("\n\t"); + // printf("%02x ", hash.d[i]); + // } + // printf("\n"); + + // Get the Quote + ret = dcap_generate_quote(handle, p_quote_buffer, &hash); + if (0 != ret) { + printf( "Error in dcap_generate_quote.\n"); + goto CLEANUP; + } + + printf("DCAP generate quote successfully\n"); + + p_quote = (sgx_quote3_t *)p_quote_buffer; + p_report_body = (sgx_report_body_t *)(&p_quote->report_body); + p_report_data = (sgx_report_data_t *)(&p_report_body->report_data); + + // check report data + if (memcmp((void *)&hash, (void *)p_report_data, sizeof(sgx_report_data_t)) != 0) { + printf("mismathced report data\n"); + goto CLEANUP; + } + + // Create json file + FILE *fp = fopen(MAA_JSON, "w"); + if ( NULL == fp ) { + printf("fopen %s failed return %d\n", MAA_JSON, errno); + goto CLEANUP; + } + + // Generate Azure attestion json file + // Refer to https://github.com/Azure-Samples/microsoft-azure-attestation + fprintf(fp, "%s\n", "{"); + // Use 3 as type for now + fprintf(fp, " \"Type\": %d,\n", 3); + fprintf(fp, " \"MrEnclaveHex\": \"%s\",\n", format_hex_buffer(hex_buffer, hex_buffer_size, p_report_body->mr_enclave.m, SGX_HASH_SIZE)); + fprintf(fp, " \"MrSignerHex\": \"%s\",\n", format_hex_buffer(hex_buffer, hex_buffer_size, p_report_body->mr_signer.m, SGX_HASH_SIZE)); + fprintf(fp, " \"ProductIdHex\": \"%s\",\n", uint16_to_buffer(hex_buffer, hex_buffer_size, (uint16_t)p_report_body->isv_prod_id, 16)); + fprintf(fp, " \"SecurityVersion\": %u,\n", (int)p_report_body->isv_svn); + fprintf(fp, " \"Attributes\": %lu,\n", (uint64_t)p_report_body->attributes.flags); + fprintf(fp, " \"QuoteHex\": \"%s\",\n", format_hex_buffer(hex_buffer, hex_buffer_size, (uint8_t *)p_quote, quote_size)); + fprintf(fp, " \"EnclaveHeldDataHex\": \"%s\"\n", format_hex_buffer(hex_buffer, hex_buffer_size, enclave_held_data, sizeof( enclave_held_data))); + fprintf(fp, "%s\n", "}"); + fclose(fp); + +CLEANUP: + if (NULL != p_quote_buffer) { + free(p_quote_buffer); + } + + dcap_quote_close(handle); +} diff --git a/demos/remote_attestation/maa/maa.yaml b/demos/remote_attestation/maa/maa.yaml new file mode 100644 index 00000000..aabca95a --- /dev/null +++ b/demos/remote_attestation/maa/maa.yaml @@ -0,0 +1,16 @@ +includes: + - base.yaml +# dcap +targets: + # copy bins + - target: /bin + copy: + - files: + - ../gen_quote/gen_maa_json + # copy lib + - target: /opt/occlum/glibc/lib + copy: + - files: + - /opt/occlum/toolchains/dcap_lib/glibc/libocclum_dcap.so.0.1.0 + - /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 + diff --git a/demos/remote_attestation/maa/run.sh b/demos/remote_attestation/maa/run.sh new file mode 100755 index 00000000..bc2bee05 --- /dev/null +++ b/demos/remote_attestation/maa/run.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -e + +BLUE='\033[1;34m' +NC='\033[0m' +INSTANCE_DIR="occlum_instance" +bomfile="../maa.yaml" +json_dir=$PWD/out + +# parameter 1 defines the predefined Occlum json +# parameter 2 defines the generated maa json +function gen_maa_json() { + config=$1 + maa=${2:-"maa.json"} + + if [ ! -f $config ]; then + echo "Please provide valid Occlum json file" + exit -1 + fi + + rm -rf ${INSTANCE_DIR} && occlum new ${INSTANCE_DIR} + pushd ${INSTANCE_DIR} + + rm -rf image + copy_bom -f $bomfile --root image --include-dir /opt/occlum/etc/template + cp ../$config Occlum.json + occlum build + + echo -e "${BLUE}occlum run to generate quote in maa json format${NC}" + occlum run /bin/gen_maa_json + + echo -e "${BLUE}Generated maa json file ${json_dir}/$maa${NC}" + mv maa.json ${json_dir}/$maa + popd +} + +echo "*** Build glibc maa demo ***" +make -C gen_quote clean +make -C gen_quote + +rm -rf ${json_dir} && mkdir -p ${json_dir} + +gen_maa_json ./config/Occlum.json maa_debug.json +gen_maa_json ./config/Occlum_prodid.json maa_prodid.json +gen_maa_json ./config/Occlum_release.json maa_release.json +gen_maa_json ./config/Occlum_securityversion.json maa_securityversion.json + +