diff --git a/.ci/lib/stage-test-sgx.jenkinsfile b/.ci/lib/stage-test-sgx.jenkinsfile index 40354e9bbb..cf3d421eb0 100644 --- a/.ci/lib/stage-test-sgx.jenkinsfile +++ b/.ci/lib/stage-test-sgx.jenkinsfile @@ -9,7 +9,7 @@ stage('test-sgx') { timeout(time: 5, unit: 'MINUTES') { sh ''' cd CI-Examples/python - RA_CLIENT_SPID=${ra_client_spid} make ${MAKEOPTS} + make ${MAKEOPTS} RA_TYPE=epid RA_CLIENT_SPID=${ra_client_spid} make ${MAKEOPTS} check ''' } @@ -102,12 +102,10 @@ stage('test-sgx') { cd CI-Examples/ra-tls-mbedtls if [ "${ra_client_spid}" != "" ] && [ "${ra_client_key}" != "" ]; \ then \ - make check_epid RA_CLIENT_SPID=${ra_client_spid} \ - RA_TLS_EPID_API_KEY=${ra_client_key} \ - RA_CLIENT_LINKABLE=0; \ - make check_epid_fail RA_CLIENT_SPID=${ra_client_spid} \ - RA_TLS_EPID_API_KEY=${ra_client_key} \ - RA_CLIENT_LINKABLE=0; \ + make check_epid RA_TYPE=epid RA_CLIENT_SPID=${ra_client_spid} \ + RA_TLS_EPID_API_KEY=${ra_client_key} RA_CLIENT_LINKABLE=0; \ + make check_epid_fail RA_TYPE=epid RA_CLIENT_SPID=${ra_client_spid} \ + RA_TLS_EPID_API_KEY=${ra_client_key} RA_CLIENT_LINKABLE=0; \ else \ echo "Failure: no ra_client_spid and/or ra_client_key!"; \ exit 1; \ @@ -119,9 +117,8 @@ stage('test-sgx') { cd CI-Examples/ra-tls-secret-prov if [ "${ra_client_spid}" != "" ] && [ "${ra_client_key}" != "" ]; \ then \ - make SGX=1 check_epid RA_CLIENT_SPID=${ra_client_spid} \ - RA_TLS_EPID_API_KEY=${ra_client_key} \ - RA_CLIENT_LINKABLE=0; \ + make check_epid RA_TYPE=epid RA_CLIENT_SPID=${ra_client_spid} \ + RA_TLS_EPID_API_KEY=${ra_client_key} RA_CLIENT_LINKABLE=0; \ else \ echo "Failure: no ra_client_spid and/or ra_client_key!"; \ exit 1; \ diff --git a/.ci/lib/stage-test.jenkinsfile b/.ci/lib/stage-test.jenkinsfile index 7d139fb56b..6dc85ddf06 100644 --- a/.ci/lib/stage-test.jenkinsfile +++ b/.ci/lib/stage-test.jenkinsfile @@ -15,7 +15,7 @@ stage('test') { try { sh ''' cd LibOS/test/regression - RA_CLIENT_SPID=${ra_client_spid} gramine-test build -v + RA_TYPE=epid RA_CLIENT_SPID=${ra_client_spid} gramine-test build -v python3 -m pytest -v --junit-xml libos-regression.xml ''' } finally { @@ -31,7 +31,8 @@ stage('test') { cd LibOS/test/regression # For some unknown reason it fails without this clean on sgx-18.04 pipeline gramine-test clean - RA_CLIENT_SPID=${ra_client_spid} gramine-test -n tests_musl.toml build -v + RA_TYPE=epid RA_CLIENT_SPID=${ra_client_spid} \ + gramine-test -n tests_musl.toml build -v python3 -m pytest -v --junit-xml libos-regression-musl.xml ''' } finally { diff --git a/CI-Examples/busybox/Makefile b/CI-Examples/busybox/Makefile index fb33a48308..0510443e4a 100644 --- a/CI-Examples/busybox/Makefile +++ b/CI-Examples/busybox/Makefile @@ -13,6 +13,9 @@ else GRAMINE_LOG_LEVEL = error endif +RA_TYPE ?= none +RA_CLIENT_SPID ?= +RA_CLIENT_LINKABLE ?= 0 .PHONY: all all: busybox busybox.manifest @@ -44,6 +47,9 @@ busybox.manifest: busybox.manifest.template gramine-manifest \ -Dlog_level=$(GRAMINE_LOG_LEVEL) \ -Darch_libdir=$(ARCH_LIBDIR) \ + -Dra_type=$(RA_TYPE) \ + -Dra_client_spid=$(RA_CLIENT_SPID) \ + -Dra_client_linkable=$(RA_CLIENT_LINKABLE) \ $< > $@ # Make on Ubuntu <= 20.04 doesn't support "Rules with Grouped Targets" (`&:`), diff --git a/CI-Examples/busybox/README.md b/CI-Examples/busybox/README.md index 451d9e9d94..9e728c4328 100644 --- a/CI-Examples/busybox/README.md +++ b/CI-Examples/busybox/README.md @@ -3,6 +3,34 @@ This directory contains the Makefile and the template manifest for the most recent version of Busybox (as of this writing, commit ac78f2ac96). +## Building with SGX remote attestation + +If you want to try out [`/dev/attestation/` files][attestation], you must build +the example with SGX remote attestation enabled. By default, the example is +built *without* remote attestation. + +[attestation]: https://gramine.readthedocs.io/en/latest/attestation.html + +If you want to build the example for DCAP attestation, first make sure you have +a working DCAP setup. Then build the example as follows: +``` +make SGX=1 RA_TYPE=dcap +``` + +Otherwise, you will probably want to use EPID attestation. For this, you will +additionally need to provide an SPID and specify whether it is set up for +linkable quotes or not: +``` +make SGX=1 RA_TYPE=epid RA_CLIENT_SPID=12345678901234567890123456789012 \ + RA_CLIENT_LINKABLE=0 +``` + +The above dummy values will suffice for simple experiments, but if you wish to +run `sgx-quote.py` and verify the output, you will need to provide an +[SPID recognized by Intel][spid]. + +[spid]: https://gramine.readthedocs.io/en/latest/sgx-intro.html#term-spid + # Quick Start ```sh diff --git a/CI-Examples/busybox/busybox.manifest.template b/CI-Examples/busybox/busybox.manifest.template index 09078ff89f..13aadc096b 100644 --- a/CI-Examples/busybox/busybox.manifest.template +++ b/CI-Examples/busybox/busybox.manifest.template @@ -22,6 +22,10 @@ fs.mounts = [ sgx.debug = true +sgx.remote_attestation = "{{ ra_type }}" +sgx.ra_client_spid = "{{ ra_client_spid }}" +sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} + sgx.trusted_files = [ "file:{{ gramine.libos }}", "file:busybox", diff --git a/CI-Examples/python/Makefile b/CI-Examples/python/Makefile index 54ebbc2ca7..6750f29e4a 100644 --- a/CI-Examples/python/Makefile +++ b/CI-Examples/python/Makefile @@ -12,11 +12,18 @@ ifeq ($(SGX),1) all: python.manifest.sgx python.sig python.token endif +RA_TYPE ?= none +RA_CLIENT_SPID ?= +RA_CLIENT_LINKABLE ?= 0 + python.manifest: python.manifest.template gramine-manifest \ -Dlog_level=$(GRAMINE_LOG_LEVEL) \ -Darch_libdir=$(ARCH_LIBDIR) \ -Dentrypoint=$(realpath $(shell sh -c "command -v python3")) \ + -Dra_type=$(RA_TYPE) \ + -Dra_client_spid=$(RA_CLIENT_SPID) \ + -Dra_client_linkable=$(RA_CLIENT_LINKABLE) \ $< >$@ # Make on Ubuntu <= 20.04 doesn't support "Rules with Grouped Targets" (`&:`), diff --git a/CI-Examples/python/README.md b/CI-Examples/python/README.md index d096d9dded..bcfb6c7bb8 100644 --- a/CI-Examples/python/README.md +++ b/CI-Examples/python/README.md @@ -18,18 +18,25 @@ Run `make` (non-debug) or `make DEBUG=1` (debug) in the directory. ## Building for SGX -To facilitate the `scripts/sgx-quote.py` example, the enclave is set up for -remote attestation. By default it will be built for DCAP attestation, which -means that you need a working DCAP setup to launch the enclave. +Run `make SGX=1` (non-debug) or `make SGX=1 DEBUG=1` (debug) in the directory. -If you do have DCAP set up, run `make SGX=1` (non-debug) or -`make SGX=1 DEBUG=1` (debug) in this directory. +If you want to run the `scripts/sgx-quote.py` script, you must build the example +with SGX remote attestation enabled. By default, the example is built *without* +remote attestation. + +If you want to build the example for DCAP attestation, first make sure you have +a working DCAP setup. Then build the example as follows: +``` +make SGX=1 RA_TYPE=dcap +``` Otherwise, you will probably want to use EPID attestation. For this, you will -need to provide an SPID and specify whether it is set up for linkable quotes or not: +additionally need to provide an SPID and specify whether it is set up for +linkable quotes or not: ``` -RA_CLIENT_SPID=12345678901234567890123456789012 RA_CLIENT_LINKABLE=0 make SGX=1 +make SGX=1 RA_TYPE=epid RA_CLIENT_SPID=12345678901234567890123456789012 \ + RA_CLIENT_LINKABLE=0 ``` The above dummy values will suffice for simple experiments, but if you wish to diff --git a/CI-Examples/python/python.manifest.template b/CI-Examples/python/python.manifest.template index b7777293c1..c8f4219acf 100644 --- a/CI-Examples/python/python.manifest.template +++ b/CI-Examples/python/python.manifest.template @@ -28,9 +28,9 @@ sgx.enclave_size = "512M" sys.stack.size = "2M" sgx.thread_num = 32 -sgx.remote_attestation = true -sgx.ra_client_spid = "{{ env.get('RA_CLIENT_SPID', '') }}" -sgx.ra_client_linkable = {{ 'true' if env.get('RA_CLIENT_LINKABLE', '0') == '1' else 'false' }} +sgx.remote_attestation = "{{ ra_type }}" +sgx.ra_client_spid = "{{ ra_client_spid }}" +sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} sgx.trusted_files = [ "file:{{ gramine.libos }}", diff --git a/CI-Examples/python/scripts/sgx-quote.py b/CI-Examples/python/scripts/sgx-quote.py index 9081bb6053..f551a55417 100644 --- a/CI-Examples/python/scripts/sgx-quote.py +++ b/CI-Examples/python/scripts/sgx-quote.py @@ -8,9 +8,12 @@ def tohex(b): if not os.path.exists("/dev/attestation/user_report_data"): print("Cannot find `/dev/attestation/user_report_data`; " - "are you running under SGX?") + "are you running under SGX, with remote attestation enabled?") sys.exit(1) +with open('/dev/attestation/attestation_type') as f: + print(f"Detected attestation type: {f.read()}") + with open("/dev/attestation/user_report_data", "wb") as f: f.write(b'\0'*64) diff --git a/CI-Examples/ra-tls-mbedtls/Makefile b/CI-Examples/ra-tls-mbedtls/Makefile index 4a09f67448..046c5c8f60 100644 --- a/CI-Examples/ra-tls-mbedtls/Makefile +++ b/CI-Examples/ra-tls-mbedtls/Makefile @@ -3,11 +3,6 @@ GRAMINE_PKGLIBDIR ?= /usr/lib/x86_64-linux-gnu/gramine # this is debian/ubuntu s ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine) -# for EPID attestation, specify your SPID and linkable/unlinkable attestation policy; -# for DCAP/ECDSA attestation, specify SPID as empty string (linkable value is ignored) -RA_CLIENT_SPID ?= -RA_CLIENT_LINKABLE ?= 0 - ifeq ($(DEBUG),1) GRAMINE_LOG_LEVEL = debug CFLAGS += -O0 -ggdb3 @@ -19,6 +14,10 @@ endif CFLAGS += -fPIE LDFLAGS += -pie +RA_TYPE ?= none +RA_CLIENT_SPID ?= +RA_CLIENT_LINKABLE ?= 0 + .PHONY: all all: app epid # by default, only build EPID because it doesn't rely on additional (DCAP) libs @@ -93,6 +92,7 @@ server.manifest: server.manifest.template gramine-manifest \ -Dlog_level=$(GRAMINE_LOG_LEVEL) \ -Darch_libdir=$(ARCH_LIBDIR) \ + -Dra_type=$(RA_TYPE) \ -Dra_client_spid=$(RA_CLIENT_SPID) \ -Dra_client_linkable=$(RA_CLIENT_LINKABLE) \ $< > $@ @@ -155,7 +155,7 @@ client_epid.token: client_epid.sig .PHONY: check_epid check_epid: app epid - gramine-sgx server epid & SERVER_ID=$$!; \ + gramine-sgx server & SERVER_ID=$$!; \ sleep 30; \ ./client epid > OUTPUT; \ ./client epid 0 0 0 0 >> OUTPUT; \ @@ -168,14 +168,14 @@ check_epid: app epid .PHONY: check_epid_fail check_epid_fail: app epid - gramine-sgx server epid dummy-option >/dev/null & SERVER_ID=$$!; \ + gramine-sgx server dummy-option >/dev/null & SERVER_ID=$$!; \ sleep 30; \ ./client epid && exit 1 || echo "[ Success 1/1 ]"; \ kill -9 $$SERVER_ID .PHONY: check_dcap check_dcap: app dcap - gramine-sgx server dcap >/dev/null & SERVER_ID=$$!; \ + gramine-sgx server >/dev/null & SERVER_ID=$$!; \ sleep 30; \ ./client dcap > OUTPUT; \ ./client dcap 0 0 0 0 >> OUTPUT; \ @@ -188,7 +188,7 @@ check_dcap: app dcap .PHONY: check_dcap_fail check_dcap_fail: app dcap - gramine-sgx server dcap dummy-option >/dev/null & SERVER_ID=$$!; \ + gramine-sgx server dummy-option >/dev/null & SERVER_ID=$$!; \ sleep 30; \ ./client dcap && exit 1 || echo "[ Success 1/1 ]"; \ kill -9 $$SERVER_ID diff --git a/CI-Examples/ra-tls-mbedtls/README.md b/CI-Examples/ra-tls-mbedtls/README.md index 034ee7c920..f02b62123f 100644 --- a/CI-Examples/ra-tls-mbedtls/README.md +++ b/CI-Examples/ra-tls-mbedtls/README.md @@ -4,11 +4,11 @@ This directory contains the Makefile, the template server manifest, and the minimal server and client written against the mbedTLS library. The server and client are based on `ssl_server.c` and `ssl_client1.c` example -programs shipped with mbedTLS. We modified them to allow using RA-TLS flows if -the programs are given the command-line argument `epid`/`dcap`. In particular, -the server uses a self-signed RA-TLS cert with the SGX quote embedded in it via -`ra_tls_create_key_and_crt()`. The client uses an RA-TLS verification callback -to verify the server RA-TLS certificate via `ra_tls_verify_callback()`. +programs shipped with mbedTLS. We modified them to allow using RA-TLS flows. In +particular, the server uses a self-signed RA-TLS cert with the SGX quote +embedded in it via `ra_tls_create_key_and_crt()`. The client uses an RA-TLS +verification callback to verify the server RA-TLS certificate via +`ra_tls_verify_callback()`. This example uses the RA-TLS libraries `ra_tls_attest.so` for server and `ra_tls_verify_epid.so`/ `ra_tls_verify_dcap.so` for client. These libraries are @@ -24,14 +24,12 @@ https://gramine.readthedocs.io/en/latest/attestation.html. ## RA-TLS server The server is supposed to run in the SGX enclave with Gramine and RA-TLS -dlopen-loaded. If RA-TLS library `ra_tls_attest.so` is not requested by user via -`epid`/`dcap` command-line argument, the server falls back to using normal X.509 -PKI flows (specified as `native` command-line argument). +dlopen-loaded. If the server is started not in the SGX enclave, then it falls +back to using normal X.509 PKI flows. -If server is run with more command-line arguments (the only important thing is -to have at least one additional argument), then the server will maliciously -modify the SGX quote before sending to the client. This is useful for testing -purposes. +If server is run with a command-line argument (the only important thing is to +have at least one argument), then the server will maliciously modify the SGX +quote before sending to the client. This is useful for testing purposes. ## RA-TLS client @@ -78,7 +76,7 @@ an [SPID and the corresponding IAS API keys][spid]. ```sh make app -./server native & +./server & ./client native # client will successfully connect to the server via normal x.509 PKI flows kill %% @@ -88,9 +86,10 @@ kill %% ```sh make clean -RA_CLIENT_SPID= RA_CLIENT_LINKABLE=<1 if SPID is linkable, else 0> make app epid +make app epid RA_TYPE=epid RA_CLIENT_SPID= \ + RA_CLIENT_LINKABLE=<1 if SPID is linkable, else 0> -gramine-sgx ./server epid & +gramine-sgx ./server & RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 \ RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \ @@ -109,9 +108,9 @@ kill %% ```sh make clean -make app dcap +make app dcap RA_TYPE=dcap -gramine-sgx ./server dcap & +gramine-sgx ./server & RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 \ RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \ @@ -129,9 +128,9 @@ kill %% ```sh make clean -make app dcap +make app dcap RA_TYPE=dcap -gramine-sgx ./server dcap & +gramine-sgx ./server & RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 ./client dcap \ \ @@ -147,9 +146,9 @@ kill %% ```sh make clean -make app dcap +make app dcap RA_TYPE=dcap -gramine-sgx ./server dcap dummy-option & +gramine-sgx ./server dummy-option & ./client dcap # client will fail to verify the malicious SGX quote and will *not* connect to the server @@ -165,11 +164,14 @@ as `RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE`, `RA_TLS_ALLOW_OUTDATED_TCB_INSECURE`, ```sh make clean -RA_CLIENT_SPID= RA_CLIENT_LINKABLE=<1 if SPID is linkable, else 0> make app client_epid.manifest.sgx +make app epid RA_TYPE=epid RA_CLIENT_SPID= \ + RA_CLIENT_LINKABLE=<1 if SPID is linkable, else 0> -gramine-sgx ./server epid & +gramine-sgx ./server & -RA_TLS_EPID_API_KEY= gramine-sgx ./client_epid epid +RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \ + RA_TLS_EPID_API_KEY= \ + gramine-sgx ./client_epid epid # client will successfully connect to the server via RA-TLS/EPID flows kill %% @@ -179,12 +181,12 @@ kill %% ```sh make clean -make app dcap +make app dcap RA_TYPE=dcap -gramine-sgx ./server dcap & +gramine-sgx ./server & -RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 gramine-sgx \ - ./client_dcap dcap \ +RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \ + gramine-sgx ./client_dcap dcap \ \ \ \ diff --git a/CI-Examples/ra-tls-mbedtls/client.manifest.template b/CI-Examples/ra-tls-mbedtls/client.manifest.template index a6676dec38..596703aa99 100644 --- a/CI-Examples/ra-tls-mbedtls/client.manifest.template +++ b/CI-Examples/ra-tls-mbedtls/client.manifest.template @@ -1,33 +1,35 @@ -# Client manifest file (both for EPID and DCAP) +# Client manifest file loader.entrypoint = "file:{{ gramine.libos }}" libos.entrypoint = "client" loader.log_level = "{{ log_level }}" -loader.env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}" -loader.env.RA_TLS_CLIENT_INSIDE_SGX = "1" +loader.env.LD_LIBRARY_PATH = "/lib:/usr/local/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}" loader.env.LC_ALL = "C" +loader.env.RA_TLS_CLIENT_INSIDE_SGX = "1" + loader.insecure__use_cmdline_argv = true loader.insecure__use_host_env = true fs.mounts = [ { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "/usr/local/lib", uri = "file:/usr/local/lib" }, { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, { path = "/usr{{ arch_libdir }}", uri = "file:/usr{{ arch_libdir }}" }, { path = "/etc", uri = "file:/etc" }, ] sgx.debug = true -sgx.remote_attestation = true -sgx.enclave_size = "256M" +sgx.enclave_size = "512M" sgx.thread_num = 4 sgx.trusted_files = [ "file:{{ gramine.libos }}", "file:client", "file:{{ gramine.runtimedir() }}/", + "file:/usr/local/lib/", "file:{{ arch_libdir }}/", "file:/usr{{ arch_libdir }}/", "file:ssl/ca.crt", diff --git a/CI-Examples/ra-tls-mbedtls/server.manifest.template b/CI-Examples/ra-tls-mbedtls/server.manifest.template index 521e843559..1510c83f1c 100644 --- a/CI-Examples/ra-tls-mbedtls/server.manifest.template +++ b/CI-Examples/ra-tls-mbedtls/server.manifest.template @@ -19,7 +19,8 @@ fs.mounts = [ ] sgx.debug = true -sgx.remote_attestation = true + +sgx.remote_attestation = "{{ ra_type }}" sgx.ra_client_spid = "{{ ra_client_spid }}" sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} diff --git a/CI-Examples/ra-tls-mbedtls/src/server.c b/CI-Examples/ra-tls-mbedtls/src/server.c index 32b9926909..abd413ce73 100644 --- a/CI-Examples/ra-tls-mbedtls/src/server.c +++ b/CI-Examples/ra-tls-mbedtls/src/server.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -65,6 +66,25 @@ static void my_debug(void* ctx, int level, const char* file, int line, const cha fflush((FILE*)ctx); } +static ssize_t file_read(const char* path, char* buf, size_t count) { + FILE* f = fopen(path, "r"); + if (!f) + return -errno; + + ssize_t bytes = fread(buf, 1, count, f); + if (bytes <= 0) { + int errsv = errno; + fclose(f); + return -errsv; + } + + int close_ret = fclose(f); + if (close_ret < 0) + return -errno; + + return bytes; +} + int main(int argc, char** argv) { int ret; size_t len; @@ -72,9 +92,7 @@ int main(int argc, char** argv) { mbedtls_net_context client_fd; unsigned char buf[1024]; const char* pers = "ssl_server"; - - void* ra_tls_attest_lib = NULL; - ra_tls_create_key_and_crt_der_f = NULL; + void* ra_tls_attest_lib; uint8_t* der_key = NULL; uint8_t* der_crt = NULL; @@ -99,13 +117,19 @@ int main(int argc, char** argv) { mbedtls_debug_set_threshold(DEBUG_LEVEL); #endif - if (argc < 2 || - (strcmp(argv[1], "native") && strcmp(argv[1], "epid") && strcmp(argv[1], "dcap"))) { - mbedtls_printf("USAGE: %s native|epid|dcap [SGX measurements]\n", argv[0]); + char attestation_type_str[32] = {0}; + ret = file_read("/dev/attestation/attestation_type", attestation_type_str, + sizeof(attestation_type_str) - 1); + if (ret < 0 && ret != -ENOENT) { + mbedtls_printf("User requested RA-TLS attestation but cannot read SGX-specific file " + "/dev/attestation/attestation_type\n"); return 1; } - if (!strcmp(argv[1], "epid") || !strcmp(argv[1], "dcap")) { + if (ret == -ENOENT || !strcmp(attestation_type_str, "none")) { + ra_tls_attest_lib = NULL; + ra_tls_create_key_and_crt_der_f = NULL; + } else if (!strcmp(attestation_type_str, "epid") || !strcmp(attestation_type_str, "dcap")) { ra_tls_attest_lib = dlopen("libra_tls_attest.so", RTLD_LAZY); if (!ra_tls_attest_lib) { mbedtls_printf("User requested RA-TLS attestation but cannot find lib\n"); @@ -121,10 +145,14 @@ int main(int argc, char** argv) { mbedtls_printf("%s\n", error); return 1; } + } else { + mbedtls_printf("Unrecognized remote attestation type: %s\n", attestation_type_str); + return 1; } if (ra_tls_attest_lib) { - mbedtls_printf("\n . Creating the RA-TLS server cert and key..."); + mbedtls_printf("\n . Creating the RA-TLS server cert and key (using \"%s\" as " + "attestation type)...", attestation_type_str); fflush(stdout); size_t der_key_size; @@ -150,7 +178,7 @@ int main(int argc, char** argv) { mbedtls_printf(" ok\n"); - if (argc > 2) { + if (argc > 1) { /* user asks to maliciously modify the embedded SGX quote (for testing purposes) */ mbedtls_printf(" . Maliciously modifying SGX quote embedded in RA-TLS cert..."); fflush(stdout); diff --git a/CI-Examples/ra-tls-secret-prov/Makefile b/CI-Examples/ra-tls-secret-prov/Makefile index d195138dd3..9a349fe721 100644 --- a/CI-Examples/ra-tls-secret-prov/Makefile +++ b/CI-Examples/ra-tls-secret-prov/Makefile @@ -3,11 +3,6 @@ GRAMINE_PKGLIBDIR ?= /usr/lib/x86_64-linux-gnu/gramine # this is debian/ubuntu s ARCH_LIBDIR ?= /lib/$(shell $(CC) -dumpmachine) -# for EPID attestation, specify your SPID and linkable/unlinkable attestation policy; -# for DCAP/ECDSA attestation, specify SPID as empty string (linkable value is ignored) -RA_CLIENT_SPID ?= -RA_CLIENT_LINKABLE ?= 0 - ifeq ($(DEBUG),1) GRAMINE_LOG_LEVEL = debug CFLAGS += -O0 -ggdb3 @@ -19,6 +14,10 @@ endif CFLAGS += -fPIE LDFLAGS += -pie +RA_TYPE ?= none +RA_CLIENT_SPID ?= +RA_CLIENT_LINKABLE ?= 0 + .PHONY: clients clients: secret_prov_min_client secret_prov_client secret_prov_pf_client @@ -78,6 +77,7 @@ secret_prov_client.manifest: secret_prov_client.manifest.template gramine-manifest \ -Dlog_level=$(GRAMINE_LOG_LEVEL) \ -Darch_libdir=$(ARCH_LIBDIR) \ + -Dra_type=$(RA_TYPE) \ -Dra_client_spid=$(RA_CLIENT_SPID) \ -Dra_client_linkable=$(RA_CLIENT_LINKABLE) \ $< > $@ @@ -102,6 +102,7 @@ secret_prov_min_client.manifest: secret_prov_min_client.manifest.template gramine-manifest \ -Dlog_level=$(GRAMINE_LOG_LEVEL) \ -Darch_libdir=$(ARCH_LIBDIR) \ + -Dra_type=$(RA_TYPE) \ -Dra_client_spid=$(RA_CLIENT_SPID) \ -Dra_client_linkable=$(RA_CLIENT_LINKABLE) \ $< > $@ @@ -129,6 +130,7 @@ secret_prov_pf_client.manifest: secret_prov_pf_client.manifest.template gramine-manifest \ -Dlog_level=$(GRAMINE_LOG_LEVEL) \ -Darch_libdir=$(ARCH_LIBDIR) \ + -Dra_type=$(RA_TYPE) \ -Dra_client_spid=$(RA_CLIENT_SPID) \ -Dra_client_linkable=$(RA_CLIENT_LINKABLE) \ $< > $@ diff --git a/CI-Examples/ra-tls-secret-prov/README.md b/CI-Examples/ra-tls-secret-prov/README.md index 1b693bd62f..b6cc620a75 100644 --- a/CI-Examples/ra-tls-secret-prov/README.md +++ b/CI-Examples/ra-tls-secret-prov/README.md @@ -29,8 +29,7 @@ build time. Because this example builds and uses debug SGX enclaves (`sgx.debug` is set to `true`), we use environment variable `RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1`. -Note that in production environments, -you must *not* use this option! +Note that in production environments, you must *not* use this option! Moreover, we set `RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1`, to allow performing the tests when some of Intel's security advisories haven't been addressed (for @@ -70,7 +69,8 @@ build time. [spid]: https://gramine.readthedocs.io/en/latest/sgx-intro.html#term-spid ```sh -RA_CLIENT_SPID= RA_CLIENT_LINKABLE=<1 if SPID is linkable, else 0> make app epid files/input.txt +make app epid files/input.txt RA_TYPE=epid RA_CLIENT_SPID= \ + RA_CLIENT_LINKABLE=<1 if SPID is linkable, else 0> RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 \ RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \ @@ -92,7 +92,7 @@ kill %% - Secret Provisioning flows, ECDSA-based (DCAP) attestation: ```sh -make app dcap files/input.txt +make app dcap files/input.txt RA_TYPE=dcap RA_TLS_ALLOW_DEBUG_ENCLAVE_INSECURE=1 \ RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \ diff --git a/CI-Examples/ra-tls-secret-prov/secret_prov_client.manifest.template b/CI-Examples/ra-tls-secret-prov/secret_prov_client.manifest.template index d442599397..3cf486e4df 100644 --- a/CI-Examples/ra-tls-secret-prov/secret_prov_client.manifest.template +++ b/CI-Examples/ra-tls-secret-prov/secret_prov_client.manifest.template @@ -18,7 +18,8 @@ fs.mounts = [ sgx.enclave_size = "512M" sgx.debug = true -sgx.remote_attestation = true + +sgx.remote_attestation = "{{ ra_type }}" sgx.ra_client_spid = "{{ ra_client_spid }}" sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} diff --git a/CI-Examples/ra-tls-secret-prov/secret_prov_min_client.manifest.template b/CI-Examples/ra-tls-secret-prov/secret_prov_min_client.manifest.template index 3fb1f141d3..84b83157c5 100644 --- a/CI-Examples/ra-tls-secret-prov/secret_prov_min_client.manifest.template +++ b/CI-Examples/ra-tls-secret-prov/secret_prov_min_client.manifest.template @@ -22,7 +22,8 @@ fs.mounts = [ sgx.enclave_size = "512M" sgx.debug = true -sgx.remote_attestation = true + +sgx.remote_attestation = "{{ ra_type }}" sgx.ra_client_spid = "{{ ra_client_spid }}" sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} diff --git a/CI-Examples/ra-tls-secret-prov/secret_prov_pf_client.manifest.template b/CI-Examples/ra-tls-secret-prov/secret_prov_pf_client.manifest.template index 2f540b7eb9..5890e5932f 100644 --- a/CI-Examples/ra-tls-secret-prov/secret_prov_pf_client.manifest.template +++ b/CI-Examples/ra-tls-secret-prov/secret_prov_pf_client.manifest.template @@ -24,7 +24,8 @@ fs.mounts = [ sgx.enclave_size = "512M" sgx.debug = true -sgx.remote_attestation = true + +sgx.remote_attestation = "{{ ra_type }}" sgx.ra_client_spid = "{{ ra_client_spid }}" sgx.ra_client_linkable = {{ 'true' if ra_client_linkable == '1' else 'false' }} diff --git a/Documentation/attestation.rst b/Documentation/attestation.rst index 9c4ac1456f..f97f835e06 100644 --- a/Documentation/attestation.rst +++ b/Documentation/attestation.rst @@ -118,6 +118,10 @@ low-level abstractions of *attestation report* and *attestation quote* objects (:term:`SGX Report` and :term:`SGX Quote` in SGX parlance), in the form of the below pseudo-files: +- ``/dev/attestation/attestation_type`` pseudo-file can be opened for read and + contains the name of the attestation scheme used (currently one of ``none``, + ``epid`` and ``dcap``). + - ``/dev/attestation/user_report_data`` pseudo-file can be opened for read or write access. Typically, it is opened and written into before opening and reading from the ``/dev/attestation/report`` and ``/dev/attestation/quote`` @@ -278,15 +282,13 @@ certificate. The library is *not* thread-safe. The library expects the following information in the manifest for EPID based attestation: -- ``sgx.remote_attestation = true`` -- remote attestation is enabled. +- ``sgx.remote_attestation = "epid"`` -- EPID remote attestation is enabled. - ``sgx.ra_client_spid`` -- client SPID for EPID remote attestation. - ``sgx.ra_client_linkable`` -- client linkable/unlinkable attestation mode. For DCAP/ECDSA based attestation, the library expects instead: -- ``sgx.remote_attestation = true`` -- remote attestation is enabled. -- ``sgx.ra_client_spid = ""`` -- hints that this is a DCAP attestation, *not* - EPID attestation. +- ``sgx.remote_attestation = "dcap"`` -- DCAP remote attestation is enabled. The library uses the following environment variables if available: diff --git a/Documentation/manifest-syntax.rst b/Documentation/manifest-syntax.rst index d76a454806..bb3dc6cd1c 100644 --- a/Documentation/manifest-syntax.rst +++ b/Documentation/manifest-syntax.rst @@ -722,22 +722,23 @@ Attestation and quotes :: - sgx.remote_attestation = [true|false] - (Default: false) + sgx.remote_attestation = "[none|epid|dcap]" + (Default: "none") sgx.ra_client_linkable = [true|false] sgx.ra_client_spid = "[HEX]" + (Only for EPID based attestation) -This syntax specifies the parameters for remote attestation. To enable it, -``remote_attestation`` must be set to ``true``. +This syntax specifies the parameters for remote attestation. By default it is +not enabled. -For EPID based attestation, ``ra_client_linkable`` and ``ra_client_spid`` must -be filled with your registered Intel SGX EPID Attestation Service credentials -(linkable/unlinkable mode and SPID of the client respectively). +For :term:`EPID` based attestation, ``remote_attestation`` must be set to +``epid``. In addition, ``ra_client_linkable`` and ``ra_client_spid`` must be +filled with your registered Intel SGX EPID Attestation Service credentials +(linkable/unlinkable mode and :term:`SPID` of the client respectively). -For DCAP/ECDSA based attestation, ``ra_client_spid`` must be an empty string -(this is a hint to Gramine to use DCAP instead of EPID) and -``ra_client_linkable`` is ignored. +For :term:`DCAP` based attestation, ``remote_attestation`` must be set to +``dcap``. ``ra_client_spid`` and ``ra_client_linkable`` are ignored. Pre-heating enclave ^^^^^^^^^^^^^^^^^^^ @@ -935,3 +936,16 @@ replaced with ``type = "encrypted"`` mounts (see :ref:`encrypted-files`). This syntax allowed specifying the default encryption key for protected files. It has been replaced by ``fs.insecure__keys.[KEY_NAME]]``. Note that both old and new syntax are suitable for debugging purposes only. + +Attestation and quotes (deprecated syntax) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +:: + + sgx.remote_attestation = [true|false] + +This syntax specified whether to enable SGX remote attestation. The boolean +value has been replaced with the string value. The ``none`` value in the new +syntax corresponds to the ``false`` boolean value in the deprecated syntax. The +explicit ``epid`` and ``dcap`` values in the new syntax replace the ambiguous +``true`` boolean value in the deprecated syntax. diff --git a/Documentation/tutorials/pytorch/index.rst b/Documentation/tutorials/pytorch/index.rst index 633af98575..30ceef4f54 100644 --- a/Documentation/tutorials/pytorch/index.rst +++ b/Documentation/tutorials/pytorch/index.rst @@ -495,7 +495,7 @@ re-use the same ``ssl/`` directory and specify ``localhost``. For more info on the used environment variables and other manifest options, see `here `__:: - sgx.remote_attestation = true + sgx.remote_attestation = "dcap" # this tutorial uses DCAP attestation only loader.env.LD_PRELOAD = "libsecret_prov_attest.so" loader.env.SECRET_PROVISION_CONSTRUCTOR = "1" diff --git a/LibOS/src/fs/dev/attestation.c b/LibOS/src/fs/dev/attestation.c index f85aabcf9d..9fd01f15e8 100644 --- a/LibOS/src/fs/dev/attestation.c +++ b/LibOS/src/fs/dev/attestation.c @@ -15,8 +15,10 @@ * be generally single-threaded and therefore do not introduce synchronization here. */ +#include "api.h" #include "shim_fs_encrypted.h" #include "shim_fs_pseudo.h" +#include "toml_utils.h" /* user_report_data, target_info and quote are opaque blobs of predefined maximum sizes. Currently * these sizes are overapproximations of SGX requirements (report_data is 64B, target_info is @@ -236,6 +238,24 @@ static int quote_load(struct shim_dentry* dent, char** out_data, size_t* out_siz return 0; } +/*! + * \brief Get remote attestation type used. + * + * In case of SGX, same as `sgx.remote_attestation` manifest option. + */ +static int attestation_type_load(struct shim_dentry* dent, char** out_data, size_t* out_size) { + __UNUSED(dent); + + assert(g_pal_public_state->attestation_type); + char* str = strdup(g_pal_public_state->attestation_type); + if (!str) + return -ENOMEM; + + *out_data = str; + *out_size = strlen(str); + return 0; +} + static int deprecated_pfkey_load(struct shim_dentry* dent, char** out_data, size_t* out_size) { __UNUSED(dent); @@ -364,32 +384,54 @@ static int key_save(struct shim_dentry* dent, const char* data, size_t size) { return 0; } +static int init_sgx_attestation(struct pseudo_node* attestation) { + if (strcmp(g_pal_public_state->host_type, "Linux-SGX")) + return 0; -int init_attestation(struct pseudo_node* dev) { - struct pseudo_node* attestation = pseudo_add_dir(dev, "attestation"); + if (!g_pal_public_state->attestation_type) { + log_error("Cannot determine remote attestation type during init of /dev/attestation/"); + return -EINVAL; + } - if (!strcmp(g_pal_public_state->host_type, "Linux-SGX")) { - log_debug("host is Linux-SGX, adding SGX-specific /dev/attestation files: " - "report, quote, etc."); + /* always add /dev/attestation/attestation_type file, even if it is "none" */ + pseudo_add_str(attestation, "attestation_type", attestation_type_load); - struct pseudo_node* user_report_data = pseudo_add_str(attestation, "user_report_data", NULL); - user_report_data->perm = PSEUDO_PERM_FILE_RW; - user_report_data->str.save = &user_report_data_save; + if (!strcmp(g_pal_public_state->attestation_type, "none")) { + log_debug("host is Linux-SGX but remote attestation type is 'none', adding only " + "/dev/attestation/attestation_type file and skipping others (report, etc.)"); + return 0; + } - struct pseudo_node* target_info = pseudo_add_str(attestation, "target_info", NULL); - target_info->perm = PSEUDO_PERM_FILE_RW; - target_info->str.save = &target_info_save; + log_debug("host is Linux-SGX and remote attestation type is '%s', adding SGX-specific " + "/dev/attestation/ files: report, quote, etc.", g_pal_public_state->attestation_type); - pseudo_add_str(attestation, "my_target_info", &my_target_info_load); - pseudo_add_str(attestation, "report", &report_load); - pseudo_add_str(attestation, "quote", "e_load); + struct pseudo_node* user_report_data = pseudo_add_str(attestation, "user_report_data", NULL); + user_report_data->perm = PSEUDO_PERM_FILE_RW; + user_report_data->str.save = &user_report_data_save; - /* TODO: This file is deprecated in v1.2, remove 2 versions later. */ - struct pseudo_node* deprecated_pfkey = pseudo_add_str(attestation, "protected_files_key", - &deprecated_pfkey_load); - deprecated_pfkey->perm = PSEUDO_PERM_FILE_RW; - deprecated_pfkey->str.save = &deprecated_pfkey_save; - } + struct pseudo_node* target_info = pseudo_add_str(attestation, "target_info", NULL); + target_info->perm = PSEUDO_PERM_FILE_RW; + target_info->str.save = &target_info_save; + + pseudo_add_str(attestation, "my_target_info", &my_target_info_load); + pseudo_add_str(attestation, "report", &report_load); + pseudo_add_str(attestation, "quote", "e_load); + + /* TODO: This file is deprecated in v1.2, remove 2 versions later. */ + struct pseudo_node* deprecated_pfkey = pseudo_add_str(attestation, "protected_files_key", + &deprecated_pfkey_load); + deprecated_pfkey->perm = PSEUDO_PERM_FILE_RW; + deprecated_pfkey->str.save = &deprecated_pfkey_save; + + return 0; +} + +int init_attestation(struct pseudo_node* dev) { + struct pseudo_node* attestation = pseudo_add_dir(dev, "attestation"); + + int ret = init_sgx_attestation(attestation); + if (ret < 0) + return ret; struct pseudo_node* keys = pseudo_add_dir(attestation, "keys"); struct pseudo_node* key = pseudo_add_str(keys, /*name=*/NULL, &key_load); diff --git a/LibOS/test/regression/attestation.manifest.template b/LibOS/test/regression/attestation.manifest.template index 377269b4df..5025821ef2 100644 --- a/LibOS/test/regression/attestation.manifest.template +++ b/LibOS/test/regression/attestation.manifest.template @@ -5,35 +5,25 @@ loader.argv0_override = "{{ entrypoint }}" loader.env.LD_LIBRARY_PATH = "/lib" loader.insecure__use_cmdline_argv = true -# Keep the deprecated `fs.mount` syntax for test purposes -# TODO: this syntax is deprecated in v1.2 and will be removed two versions after it. - -fs.mount.lib.type = "chroot" -fs.mount.lib.path = "/lib" -fs.mount.lib.uri = "file:{{ gramine.runtimedir(libc) }}" - -fs.mount.entrypoint.type = "chroot" -fs.mount.entrypoint.path = "{{ entrypoint }}" -fs.mount.entrypoint.uri = "file:{{ binary_dir }}/{{ entrypoint }}" - -fs.mount.bin.type = "chroot" -fs.mount.bin.path = "/bin" -fs.mount.bin.uri = "file:/bin" +fs.mounts = [ + { path = "/lib", uri = "file:{{ gramine.runtimedir(libc) }}" }, + { path = "/{{ entrypoint }}", uri = "file:{{ binary_dir }}/{{ entrypoint }}" }, +] -sgx.insecure__protected_files_key = "ffeeddccbbaa99887766554433221100" +fs.insecure__keys.default = "ffeeddccbbaa99887766554433221100" sgx.nonpie_binary = true sgx.debug = true -sgx.remote_attestation = true + +sgx.remote_attestation = "{{ env.get('RA_TYPE', 'none') }}" +sgx.ra_client_spid = "{{ env.get('RA_CLIENT_SPID', '') }}" +sgx.ra_client_linkable = {{ 'true' if env.get('RA_CLIENT_LINKABLE', '0') == '1' else 'false' }} # below three entries are irrelevant, only for test purposes sgx.seal_key.flags_mask = "0xffffffffffffffff" sgx.seal_key.xfrm_mask = "0xfffffffffff9ff1b" sgx.seal_key.misc_mask = "0xffffffff" -sgx.ra_client_spid = "{{ env.get('RA_CLIENT_SPID', '') }}" -sgx.ra_client_linkable = {{ 'true' if env.get('RA_CLIENT_LINKABLE', '0') == '1' else 'false' }} - sgx.trusted_files = [ "file:{{ gramine.libos }}", "file:{{ gramine.runtimedir(libc) }}/", diff --git a/LibOS/test/regression/attestation_deprecated_syntax.manifest.template b/LibOS/test/regression/attestation_deprecated_syntax.manifest.template new file mode 100644 index 0000000000..78c9b89404 --- /dev/null +++ b/LibOS/test/regression/attestation_deprecated_syntax.manifest.template @@ -0,0 +1,34 @@ +{% set entrypoint = "attestation" -%} + +loader.entrypoint = "file:{{ gramine.libos }}" +libos.entrypoint = "{{ entrypoint }}" + +loader.argv0_override = "{{ entrypoint }}" +loader.env.LD_LIBRARY_PATH = "/lib" +loader.insecure__use_cmdline_argv = true + +# Keep the deprecated `fs.mount` syntax for test purposes +# TODO: this syntax is deprecated in v1.2 and will be removed two versions after it. + +fs.mount.lib.type = "chroot" +fs.mount.lib.path = "/lib" +fs.mount.lib.uri = "file:{{ gramine.runtimedir(libc) }}" + +fs.mount.entrypoint.type = "chroot" +fs.mount.entrypoint.path = "{{ entrypoint }}" +fs.mount.entrypoint.uri = "file:{{ binary_dir }}/{{ entrypoint }}" + +sgx.insecure__protected_files_key = "ffeeddccbbaa99887766554433221100" + +sgx.nonpie_binary = true +sgx.debug = true + +sgx.remote_attestation = true +sgx.ra_client_spid = "{{ env.get('RA_CLIENT_SPID', '') }}" +sgx.ra_client_linkable = {{ 'true' if env.get('RA_CLIENT_LINKABLE', '0') == '1' else 'false' }} + +sgx.trusted_files = [ + "file:{{ gramine.libos }}", + "file:{{ gramine.runtimedir(libc) }}/", + "file:{{ binary_dir }}/{{ entrypoint }}", +] diff --git a/LibOS/test/regression/test_libos.py b/LibOS/test/regression/test_libos.py index e2a3db431d..73077cccda 100644 --- a/LibOS/test/regression/test_libos.py +++ b/LibOS/test/regression/test_libos.py @@ -489,6 +489,18 @@ def test_001_attestation_stdio(self): self.assertIn("Test local attestation... SUCCESS", stdout) self.assertIn("Test quote interface... SUCCESS", stdout) + def test_002_attestation_deprecated(self): + stdout, _ = self.run_binary(['attestation_deprecated_syntax'], timeout=60) + self.assertIn("Test resource leaks in attestation filesystem... SUCCESS", stdout) + self.assertIn("Test local attestation... SUCCESS", stdout) + self.assertIn("Test quote interface... SUCCESS", stdout) + + def test_003_attestation_deprecated_stdio(self): + stdout, _ = self.run_binary(['attestation_deprecated_syntax', 'test_stdio'], timeout=60) + self.assertIn("Test resource leaks in attestation filesystem... SUCCESS", stdout) + self.assertIn("Test local attestation... SUCCESS", stdout) + self.assertIn("Test quote interface... SUCCESS", stdout) + class TC_30_Syscall(RegressionTestCase): def test_000_getcwd(self): stdout, _ = self.run_binary(['getcwd']) diff --git a/LibOS/test/regression/tests.toml b/LibOS/test/regression/tests.toml index 9bb4e4322a..fb8f634d56 100644 --- a/LibOS/test/regression/tests.toml +++ b/LibOS/test/regression/tests.toml @@ -124,4 +124,5 @@ manifests = [ manifests = [ "attestation", + "attestation_deprecated_syntax", ] diff --git a/Pal/include/pal/pal.h b/Pal/include/pal/pal.h index 7624477243..5cc7284f54 100644 --- a/Pal/include/pal/pal.h +++ b/Pal/include/pal/pal.h @@ -94,6 +94,7 @@ enum { * started by PAL (usually our LibOS). */ struct pal_public_state { const char* host_type; + const char* attestation_type; /* currently only for Linux-SGX */ /* * Handles and executables diff --git a/Pal/src/host/Linux-SGX/common_manifest_sgx_parser.c b/Pal/src/host/Linux-SGX/common_manifest_sgx_parser.c new file mode 100644 index 0000000000..5269f30c1a --- /dev/null +++ b/Pal/src/host/Linux-SGX/common_manifest_sgx_parser.c @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* Copyright (C) 2022 Intel Corporation */ + +/* Common utilities to parse the manifest. Since functions in this file are used in both untrusted + * and trusted PAL, and the former uses UNIX error codes whereas the latter uses PAL error codes, + * the functions return UNIX error codes (callers in trusted PAL must convert to PAL error codes). + */ + +#include +#include +#include + +#include "api.h" +#include "hex.h" +#include "pal_linux.h" +#include "sgx_attest.h" +#include "toml.h" +#include "toml_utils.h" + +static int get_epid_params(toml_table_t* manifest_root, char** out_spid_str, bool* out_linkable) { + int ret; + + char* spid_str; + ret = toml_string_in(manifest_root, "sgx.ra_client_spid", &spid_str); + if (ret < 0) { + log_error("Cannot parse 'sgx.ra_client_spid'"); + return -EINVAL; + } + + bool linkable; + ret = toml_bool_in(manifest_root, "sgx.ra_client_linkable", /*defaultval=*/false, &linkable); + if (ret < 0) { + log_error("Cannot parse 'sgx.ra_client_linkable' (the value must be `true` or `false`)"); + free(spid_str); + return -EINVAL; + } + + *out_spid_str = spid_str; + *out_linkable = linkable; + return 0; +} + +int parse_attestation_type(toml_table_t* manifest_root, + enum sgx_attestation_type* out_attestation_type) { + int ret; + char* sgx_attestation_type_str = NULL; + char* sgx_ra_client_spid_str = NULL; + bool dummy_linkable; + enum sgx_attestation_type attestation_type = SGX_ATTESTATION_NONE; + + /* we parse SPID and linkable here even if there is no sgx.remote_attestation (or it is not + * EPID), simply to error out early on incorrect values */ + ret = get_epid_params(manifest_root, &sgx_ra_client_spid_str, &dummy_linkable); + if (ret < 0) + goto out; + + ret = toml_string_in(manifest_root, "sgx.remote_attestation", &sgx_attestation_type_str); + if (!ret) { + if (sgx_attestation_type_str) { + if (!strcmp(sgx_attestation_type_str, "none")) { + attestation_type = SGX_ATTESTATION_NONE; + } else if (!strcmp(sgx_attestation_type_str, "epid")) { + attestation_type = SGX_ATTESTATION_EPID; + } else if (!strcmp(sgx_attestation_type_str, "dcap")) { + attestation_type = SGX_ATTESTATION_DCAP; + } else { + log_error("Unknown 'sgx.remote_attestation' type (recognized values are " + "\"none\", \"epid\" and \"dcap\")"); + ret = -EINVAL; + goto out; + } + } + } else { + /* TODO: Bool syntax is deprecated in v1.3, remove 2 versions later. */ + bool sgx_remote_attestation_enabled; + ret = toml_bool_in(manifest_root, "sgx.remote_attestation", /*defaultval=*/false, + &sgx_remote_attestation_enabled); + if (ret < 0) { + log_error("Cannot parse 'sgx.remote_attestation' (the value must be \"none\", \"epid\" " + "or \"dcap\", or in case of legacy syntax `true` or `false`)"); + ret = -EINVAL; + goto out; + } + if (sgx_remote_attestation_enabled) { + /* legacy syntax: use EPID if SPID is a non-empty string in manifest, otherwise DCAP */ + if (sgx_ra_client_spid_str && strlen(sgx_ra_client_spid_str)) { + attestation_type = SGX_ATTESTATION_EPID; + } else { + attestation_type = SGX_ATTESTATION_DCAP; + } + } + log_always("Detected deprecated syntax 'sgx.remote_attestation = true|false'; " + "consider using 'sgx.remote_attestation = \"none\"|\"epid\"|\"dcap\"'."); + } + + *out_attestation_type = attestation_type; + ret = 0; +out: + free(sgx_attestation_type_str); + free(sgx_ra_client_spid_str); + return ret; +} + +int parse_attestation_epid_params(toml_table_t* manifest_root, sgx_spid_t* out_spid, + bool* out_linkable) { + int ret; + char* sgx_ra_client_spid_str = NULL; + sgx_spid_t spid = {0}; + bool linkable = false; + + ret = get_epid_params(manifest_root, &sgx_ra_client_spid_str, &linkable); + if (ret < 0) + goto out; + + if (!sgx_ra_client_spid_str || strlen(sgx_ra_client_spid_str) != sizeof(spid) * 2) { + log_error("Malformed 'sgx.ra_client_spid' value in the manifest: %s", + sgx_ra_client_spid_str); + ret = -EINVAL; + goto out; + } + + /* sgx.ra_client_spid must be hex string */ + for (size_t i = 0; i < strlen(sgx_ra_client_spid_str); i++) { + int8_t val = hex2dec(sgx_ra_client_spid_str[i]); + if (val < 0) { + log_error("Malformed 'sgx.ra_client_spid' value in the manifest: %s", + sgx_ra_client_spid_str); + ret = -EINVAL; + goto out; + } + spid[i / 2] = spid[i / 2] * 16 + (uint8_t)val; + } + + memcpy(out_spid, &spid, sizeof(spid)); + *out_linkable = linkable; + ret = 0; +out: + free(sgx_ra_client_spid_str); + return ret; +} diff --git a/Pal/src/host/Linux-SGX/db_main.c b/Pal/src/host/Linux-SGX/db_main.c index 194fb62623..2b1a26789c 100644 --- a/Pal/src/host/Linux-SGX/db_main.c +++ b/Pal/src/host/Linux-SGX/db_main.c @@ -20,6 +20,7 @@ #include "pal_internal.h" #include "pal_linux.h" #include "pal_linux_defs.h" +#include "pal_linux_error.h" #include "pal_rtld.h" #include "pal_topology.h" #include "toml.h" @@ -621,6 +622,14 @@ noreturn void pal_linux_main(char* uptr_libpal_uri, size_t libpal_uri_len, char* ocall_exit(1, /*is_exitgroup=*/true); } + enum sgx_attestation_type attestation_type; + ret = parse_attestation_type(g_pal_public_state.manifest_root, &attestation_type); + if (ret < 0) { + log_error("Failed to parse attestation type: %d", unix_to_pal_error(ret)); + ocall_exit(1, /*is_exitgroup=*/true); + } + g_pal_public_state.attestation_type = attestation_type_to_str(attestation_type); + /* this should be placed *after all* initialize-from-manifest routines */ if ((ret = print_warnings_on_insecure_configs(parent)) < 0) { log_error("Cannot parse the manifest (while checking for insecure configurations)"); diff --git a/Pal/src/host/Linux-SGX/db_misc.c b/Pal/src/host/Linux-SGX/db_misc.c index 018acba087..1e61108555 100644 --- a/Pal/src/host/Linux-SGX/db_misc.c +++ b/Pal/src/host/Linux-SGX/db_misc.c @@ -15,6 +15,7 @@ #include "pal_error.h" #include "pal_internal.h" #include "pal_linux.h" +#include "pal_linux_error.h" #include "seqlock.h" #include "sgx_api.h" #include "sgx_attest.h" @@ -534,71 +535,38 @@ int _DkAttestationReport(const void* user_report_data, size_t* user_report_data_ int _DkAttestationQuote(const void* user_report_data, size_t user_report_data_size, void* quote, size_t* quote_size) { + int ret; + if (user_report_data_size != sizeof(sgx_report_data_t)) return -PAL_ERROR_INVAL; - int ret; - bool is_epid; - sgx_spid_t spid = {0}; + enum sgx_attestation_type attestation_type; + sgx_spid_t spid; bool linkable; - /* read sgx.ra_client_spid from manifest (must be hex string) */ - char* ra_client_spid_str = NULL; - ret = toml_string_in(g_pal_public_state.manifest_root, "sgx.ra_client_spid", - &ra_client_spid_str); + ret = parse_attestation_type(g_pal_public_state.manifest_root, &attestation_type); if (ret < 0) { - log_error("Cannot parse 'sgx.ra_client_spid'"); - return -PAL_ERROR_INVAL; + /* error was already printed by the called func */ + return unix_to_pal_error(ret); } - if (!ra_client_spid_str || strlen(ra_client_spid_str) == 0) { - /* No Software Provider ID (SPID) specified in the manifest, it is DCAP attestation -- - * for DCAP, spid and linkable arguments are ignored (we unset them for sanity) */ - is_epid = false; - linkable = false; - } else { - /* SPID specified in the manifest, it is EPID attestation -- read spid and linkable */ - is_epid = true; - - if (strlen(ra_client_spid_str) != sizeof(sgx_spid_t) * 2) { - log_error("Malformed 'sgx.ra_client_spid' value in the manifest: %s", - ra_client_spid_str); - free(ra_client_spid_str); - return -PAL_ERROR_INVAL; - } - - char* bytes = hex2bytes(ra_client_spid_str, strlen(ra_client_spid_str), spid, - sizeof(spid)); - if (!bytes) { - log_error("Malformed 'sgx.ra_client_spid' value in the manifest: %s", - ra_client_spid_str); - free(ra_client_spid_str); - return -PAL_ERROR_INVAL; - } - - /* read sgx.ra_client_linkable from manifest */ - ret = toml_bool_in(g_pal_public_state.manifest_root, "sgx.ra_client_linkable", - /*defaultval=*/false, &linkable); + if (attestation_type == SGX_ATTESTATION_EPID) { + ret = parse_attestation_epid_params(g_pal_public_state.manifest_root, &spid, &linkable); if (ret < 0) { - log_error("Cannot parse 'sgx.ra_client_linkable' (the value must be `true` or " - "`false`)"); - free(ra_client_spid_str); - return -PAL_ERROR_INVAL; + /* error was already printed by the called func */ + return unix_to_pal_error(ret); } } - free(ra_client_spid_str); - sgx_quote_nonce_t nonce; ret = _DkRandomBitsRead(&nonce, sizeof(nonce)); if (ret < 0) return ret; - char* pal_quote = NULL; + char* pal_quote = NULL; size_t pal_quote_size = 0; - - ret = sgx_get_quote(is_epid ? &spid : NULL, &nonce, user_report_data, linkable, &pal_quote, - &pal_quote_size); + ret = sgx_get_quote(attestation_type == SGX_ATTESTATION_EPID ? &spid : NULL, &nonce, + user_report_data, linkable, &pal_quote, &pal_quote_size); if (ret < 0) return ret; diff --git a/Pal/src/host/Linux-SGX/meson.build b/Pal/src/host/Linux-SGX/meson.build index bf7ea760d5..432c8c7171 100644 --- a/Pal/src/host/Linux-SGX/meson.build +++ b/Pal/src/host/Linux-SGX/meson.build @@ -52,6 +52,7 @@ pal_sgx_map = custom_target('pal.map', pal_sgx_lds = join_paths(meson.current_source_dir(), 'enclave.lds') libpal_sgx = shared_library('pal', + 'common_manifest_sgx_parser.c', 'db_devices.c', 'db_eventfd.c', 'db_events.c', @@ -125,6 +126,7 @@ libpal_sgx = shared_library('pal', # URTS (untrusted runtime) libpal_sgx_urts = executable('loader', + 'common_manifest_sgx_parser.c', 'sgx_enclave.c', 'sgx_entry.S', 'sgx_exception.c', diff --git a/Pal/src/host/Linux-SGX/pal_linux.h b/Pal/src/host/Linux-SGX/pal_linux.h index a547116a61..3753b82ba8 100644 --- a/Pal/src/host/Linux-SGX/pal_linux.h +++ b/Pal/src/host/Linux-SGX/pal_linux.h @@ -43,6 +43,25 @@ extern struct pal_linuxsgx_state { void* heap_max; } g_pal_linuxsgx_state; +enum sgx_attestation_type { + SGX_ATTESTATION_NONE, + SGX_ATTESTATION_EPID, + SGX_ATTESTATION_DCAP +}; + +static inline const char* attestation_type_to_str(enum sgx_attestation_type attestation_type) { + switch (attestation_type) { + case SGX_ATTESTATION_NONE: return "none"; + case SGX_ATTESTATION_EPID: return "epid"; + case SGX_ATTESTATION_DCAP: return "dcap"; + default: BUG(); + } +} + +int parse_attestation_type(toml_table_t* manifest_root, + enum sgx_attestation_type* out_attestation_type); +int parse_attestation_epid_params(toml_table_t* manifest_root, sgx_spid_t* out_spid, + bool* out_linkable); int init_child_process(int parent_stream_fd, PAL_HANDLE* out_parent, uint64_t* out_instance_id); diff --git a/Pal/src/host/Linux-SGX/sgx_internal.h b/Pal/src/host/Linux-SGX/sgx_internal.h index 7e52b54ea2..08d6521ba2 100644 --- a/Pal/src/host/Linux-SGX/sgx_internal.h +++ b/Pal/src/host/Linux-SGX/sgx_internal.h @@ -49,9 +49,7 @@ struct pal_enclave { unsigned long rpc_thread_num; unsigned long ssa_frame_size; bool nonpie_binary; - bool remote_attestation_enabled; - bool use_epid_attestation; /* Valid only if `remote_attestation_enabled` is true, selects - * EPID/DCAP attestation scheme. */ + enum sgx_attestation_type attestation_type; char* libpal_uri; /* Path to the PAL binary */ #ifdef DEBUG diff --git a/Pal/src/host/Linux-SGX/sgx_main.c b/Pal/src/host/Linux-SGX/sgx_main.c index efc3049405..cd50d6f97b 100644 --- a/Pal/src/host/Linux-SGX/sgx_main.c +++ b/Pal/src/host/Linux-SGX/sgx_main.c @@ -618,7 +618,6 @@ static int parse_loader_config(char* manifest, struct pal_enclave* enclave_info) int ret = 0; toml_table_t* manifest_root = NULL; char* dummy_sigfile_str = NULL; - char* sgx_ra_client_spid_str = NULL; char* profile_str = NULL; #ifdef DEBUG char* profile_mode_str = NULL; @@ -729,39 +728,12 @@ static int parse_loader_config(char* manifest, struct pal_enclave* enclave_info) goto out; } - bool sgx_remote_attestation_enabled; - ret = toml_bool_in(manifest_root, "sgx.remote_attestation", /*defaultval=*/false, - &sgx_remote_attestation_enabled); + ret = parse_attestation_type(manifest_root, &enclave_info->attestation_type); if (ret < 0) { - log_error("Cannot parse 'sgx.remote_attestation' (the value must be `true` or `false`)"); - ret = -EINVAL; - goto out; - } - enclave_info->remote_attestation_enabled = sgx_remote_attestation_enabled; - - ret = toml_string_in(manifest_root, "sgx.ra_client_spid", &sgx_ra_client_spid_str); - if (ret < 0) { - log_error("Cannot parse 'sgx.ra_client_spid'"); - ret = -EINVAL; + /* error is already printed by the called func */ goto out; } - bool sgx_ra_client_linkable_specified = - toml_key_exists(manifest_root, "sgx.ra_client_linkable"); - - if (!enclave_info->remote_attestation_enabled && - (sgx_ra_client_spid_str || sgx_ra_client_linkable_specified)) { - log_error( - "Detected EPID remote attestation parameters 'ra_client_spid' and/or " - "'ra_client_linkable' in the manifest but no 'remote_attestation' parameter. " - "Please add 'sgx.remote_attestation = true' to the manifest."); - ret = -EINVAL; - goto out; - } - - /* EPID is used if SPID is a non-empty string in manifest, otherwise DCAP/ECDSA */ - enclave_info->use_epid_attestation = sgx_ra_client_spid_str && strlen(sgx_ra_client_spid_str); - ret = toml_string_in(manifest_root, "sgx.profile.enable", &profile_str); if (ret < 0) { log_error("Cannot parse 'sgx.profile.enable' " @@ -913,7 +885,6 @@ static int parse_loader_config(char* manifest, struct pal_enclave* enclave_info) out: free(dummy_sigfile_str); - free(sgx_ra_client_spid_str); free(profile_str); #ifdef DEBUG free(profile_mode_str); @@ -982,10 +953,11 @@ static int load_enclave(struct pal_enclave* enclave, char* args, size_t args_siz return ret; sgx_target_info_t qe_targetinfo = {0}; - if (enclave->remote_attestation_enabled) { + if (enclave->attestation_type != SGX_ATTESTATION_NONE) { /* initialize communication with Quoting Enclave only if app requests attestation */ - bool is_epid = enclave->use_epid_attestation; - log_debug("Using SGX %s attestation", is_epid ? "EPID" : "DCAP/ECDSA"); + log_debug("Using SGX attestation type \"%s\"", + attestation_type_to_str(enclave->attestation_type)); + bool is_epid = enclave->attestation_type == SGX_ATTESTATION_EPID; ret = init_quoting_enclave_targetinfo(is_epid, &qe_targetinfo); if (ret < 0) return ret; diff --git a/Pal/src/host/Linux-SGX/sgx_platform.c b/Pal/src/host/Linux-SGX/sgx_platform.c index 6e769c5b12..a49a134b88 100644 --- a/Pal/src/host/Linux-SGX/sgx_platform.c +++ b/Pal/src/host/Linux-SGX/sgx_platform.c @@ -75,7 +75,7 @@ static int connect_aesm_service(void) { err: DO_SYSCALL(close, sock); - log_error("Cannot connect to aesm_service (tried " AESM_SOCKET_NAME_LEGACY " and " + log_error("Cannot connect to AESM service (tried " AESM_SOCKET_NAME_LEGACY " and " AESM_SOCKET_NAME_NEW " UNIX sockets).\nPlease check its status! (`service aesmd " "status` on Ubuntu)"); return ret; @@ -124,7 +124,7 @@ static int request_aesm_service(Request* req, Response** res) { free(res_buf); DO_SYSCALL(close, aesm_socket); if (ret < 0) { - log_error("Cannot communicate with aesm_service (read/write returned error %d).\n" + log_error("Cannot communicate with AESM service (read/write returned error %d).\n" "Please check its status! (`service aesmd status` on Ubuntu)", ret); } return ret; @@ -146,13 +146,15 @@ int init_quoting_enclave_targetinfo(bool is_epid, sgx_target_info_t* qe_targetin ret = -EPERM; if (!res->initquoteres) { - log_error("aesm_service returned wrong message"); + log_error("AESM service returned wrong message"); goto failed; } Response__InitQuoteResponse* r = res->initquoteres; if (r->errorcode != 0) { - log_error("aesm_service returned error: %d", r->errorcode); + log_error("AESM service returned error %d; this may indicate that infrastructure for " + "the EPID attestation requested by Gramine is missing on this machine", + r->errorcode); goto failed; } @@ -183,13 +185,15 @@ int init_quoting_enclave_targetinfo(bool is_epid, sgx_target_info_t* qe_targetin ret = -EPERM; if (!res->initquoteexres) { - log_error("aesm_service returned wrong message"); + log_error("AESM service returned wrong message"); goto failed; } Response__InitQuoteExResponse* r = res->initquoteexres; if (r->errorcode != 0) { - log_error("aesm_service returned error: %d", r->errorcode); + log_error("AESM service returned error %d; this may indicate that infrastructure for " + "the DCAP attestation requested by Gramine is missing on this machine", + r->errorcode); goto failed; } @@ -244,18 +248,18 @@ int retrieve_quote(const sgx_spid_t* spid, bool linkable, const sgx_report_t* re ret = -EPERM; if (!res->getquoteexres) { - log_error("aesm_service returned wrong message"); + log_error("AESM service returned wrong message"); goto out; } Response__GetQuoteExResponse* r = res->getquoteexres; if (r->errorcode != 0) { - log_error("aesm_service returned error: %d", r->errorcode); + log_error("AESM service returned error %d", r->errorcode); goto out; } if (!r->has_quote || r->quote.len < sizeof(sgx_quote_t)) { - log_error("aesm_service returned invalid quote"); + log_error("AESM service returned invalid quote"); goto out; } @@ -282,18 +286,18 @@ int retrieve_quote(const sgx_spid_t* spid, bool linkable, const sgx_report_t* re ret = -EPERM; if (!res->getquoteres) { - log_error("aesm_service returned wrong message"); + log_error("AESM service returned wrong message"); goto out; } Response__GetQuoteResponse* r = res->getquoteres; if (r->errorcode != 0) { - log_error("aesm_service returned error: %d", r->errorcode); + log_error("AESM service returned error %d", r->errorcode); goto out; } if (!r->has_quote || r->quote.len < sizeof(sgx_quote_t)) { - log_error("aesm_service returned invalid quote"); + log_error("AESM service returned invalid quote"); goto out; } diff --git a/python/graminelibos/manifest.py b/python/graminelibos/manifest.py index a28ab99e8e..084d662765 100644 --- a/python/graminelibos/manifest.py +++ b/python/graminelibos/manifest.py @@ -89,7 +89,7 @@ def __init__(self, manifest_str): sgx.setdefault('thread_num', DEFAULT_THREAD_NUM) sgx.setdefault('isvprodid', 0) sgx.setdefault('isvsvn', 0) - sgx.setdefault('remote_attestation', False) + sgx.setdefault('remote_attestation', "none") sgx.setdefault('debug', False) sgx.setdefault('require_avx', False) sgx.setdefault('require_avx512', False) diff --git a/python/graminelibos/sgx_sign.py b/python/graminelibos/sgx_sign.py index 43c0c081bb..518f3b6a33 100644 --- a/python/graminelibos/sgx_sign.py +++ b/python/graminelibos/sgx_sign.py @@ -488,14 +488,18 @@ def get_mrenclave_and_manifest(manifest_path, libpal, verbose=False): print(f' attr.xfrm: {attr["xfrms"]:#x}') print(f' misc_select: {attr["misc_select"]:#x}') - if manifest_sgx['remote_attestation']: + print('SGX remote attestation:') + attestation_type = manifest_sgx.get('remote_attestation', 'none') + if attestation_type == "none": + print(' None') + elif attestation_type == "dcap": + print(' DCAP/ECDSA') + elif attestation_type == "epid": spid = manifest_sgx.get('ra_client_spid', '') linkable = manifest_sgx.get('ra_client_linkable', False) - print('SGX remote attestation:') - if not spid: - print(' DCAP/ECDSA') - else: - print(f' EPID (spid = {spid}, linkable = {linkable})') + print(f' EPID (spid = `{spid}`, linkable = {linkable})') + else: + print(' ') # Populate memory areas memory_areas = get_memory_areas(attr, libpal)