From 22f4ec991ba0ae4cb96cf7946019b47d6e74f961 Mon Sep 17 00:00:00 2001 From: Bruno Vavala Date: Tue, 9 Apr 2024 01:54:20 +0000 Subject: [PATCH 1/3] Several updates to fix and simplify support for SGX A new docker build target is added to build the services to run in SGX. The resulting image is clearly typed/tagged as pdo_service_sgx to distinguish it from non-SGX builds. Also, base images are now SGX-MODE agnostic. 3 new scripts are added for handling SGX keys in docker builds. First, IAS certificates are retrieved by the host (not by the docker container) and transferred to the container through the "repository" before the build starts. Second, the enclave signing key is similarly checked for on (or directly passed by) the host, and transferred to the container through the "repository" before the build starts. Third, at run time, the necessary SGX keys are transferred from the host to the container through the xfer folder. The testing support is updated to pass the required SGX volumes and devices. Also, current small hacks to work behind a proxy are extended to support also the SGX-based image behind a proxy. The environment variables related to SPID, SPID_API_KEY and proxy are removed. All the material is passed to the build or at runtime through files, and proxy configuration happens through docker config settings (as usual) -- without forcing specific configurations, except for the small hack above. As a result the eservice configuration also gets simplified by reducing and merging the enclave.toml with the eservice.toml. Additional clean up will follow in later icommits. The documentation is updated to provide details on using and testing with SGX-based builds. Signed-off-by: Bruno Vavala --- bin/lib/common_service.sh | 2 +- build/Makefile | 24 +++---- build/__tools__/verify-pre-build.sh | 5 -- build/cmake/SGX.cmake | 6 +- build/template/eservice.toml | 17 +++++ build/template/pservice.toml | 17 +++++ .../crypto/trusted/enclave/CMakeLists.txt | 2 +- docker/Makefile | 49 ++++++++++++- docker/README.md | 35 ++++++++++ docker/pdo_services.dockerfile | 3 + docker/pdo_services_base.dockerfile | 12 ++-- docker/test-sgx.yaml | 33 +++++++++ docker/tools/copy_enclave_signing_key.sh | 58 +++++++++++++++ docker/tools/copy_sgx_keys.sh | 70 +++++++++++++++++++ docker/tools/environment.sh | 18 +---- docker/tools/prepare_ias_certificates.sh | 51 ++++++++++++++ docker/tools/run_services_tests.sh | 8 ++- docker/tools/start_services.sh | 12 +++- docs/install.md | 14 +++- docs/usage.md | 16 +++-- eservice/bin/register-with-ledger.sh | 64 ++++++++--------- eservice/docs/test-scripts.md | 4 +- eservice/lib/libpdo_enclave/CMakeLists.txt | 2 +- eservice/pdo/eservice/pdo_enclave.py | 22 +++--- eservice/pdo/eservice/scripts/EServiceCLI.py | 16 ++++- .../scripts/EServiceEnclaveInfoCLI.py | 45 +++++++----- eservice/pdo/eservice/utility/ias_client.py | 7 +- eservice/tests/test-secrets.py | 15 +++- pservice/lib/libpdo_enclave/CMakeLists.txt | 2 +- pservice/pdo/pservice/pdo_enclave.py | 16 +++-- pservice/pdo/pservice/scripts/PServiceCLI.py | 14 ++++ pservice/pdo/pservice/utility/ias_client.py | 7 +- python/pdo/common/config.py | 9 +-- python/pdo/scripts/ConfigureCLI.py | 3 - python/pdo/test/contract.py | 2 +- python/pdo/test/request.py | 2 +- 36 files changed, 528 insertions(+), 154 deletions(-) create mode 100644 docker/test-sgx.yaml create mode 100755 docker/tools/copy_enclave_signing_key.sh create mode 100755 docker/tools/copy_sgx_keys.sh create mode 100755 docker/tools/prepare_ias_certificates.sh diff --git a/bin/lib/common_service.sh b/bin/lib/common_service.sh index bceb4937..37e78efd 100644 --- a/bin/lib/common_service.sh +++ b/bin/lib/common_service.sh @@ -125,7 +125,7 @@ service_start() { ${F_LOGLEVEL} 2> $EFILE > $OFILE & echo $! > ${F_LOGDIR}/${IDENTITY}.pid else - ${F_SERVICE_CMD} --identity ${IDENTITY} --config ${IDENTITY}.toml enclave.toml --config-dir ${F_CONFDIR} \ + ${F_SERVICE_CMD} --identity ${IDENTITY} --config ${IDENTITY}.toml --config-dir ${F_CONFDIR} \ ${F_LEDGERURL} ${F_LOGLEVEL} 2> $EFILE > $OFILE & echo $! > ${F_LOGDIR}/${IDENTITY}.pid fi diff --git a/build/Makefile b/build/Makefile index 2f354557..335028ee 100644 --- a/build/Makefile +++ b/build/Makefile @@ -21,8 +21,8 @@ ifndef PDO_INSTALL_ROOT $(error Incomplete configuration, PDO_INSTALL_ROOT is not defined) endif -ifndef PDO_ENCLAVE_CODE_SIGN_PEM -$(error Incomplete configuration, PDO_ENCLAVE_CODE_SIGN_PEM is not defined) +ifndef PDO_SGX_KEY_ROOT +$(error Incomplete configuration, PDO_SGX_KEY_ROOT is not defined) endif ifndef SGX_MODE @@ -43,7 +43,6 @@ SRCDIR ?= $(abspath $(SCRIPTDIR)/..) BUILD = $(abspath $(SCRIPTDIR)/__tools__/build.sh) VERIFY_PRE_BUILD = $(abspath $(SCRIPTDIR)/__tools__/verify-pre-build.sh) -VERIFY_PRE_CONF = $(abspath $(SCRIPTDIR)/__tools__/verify-pre-conf.sh) CLEAN = $(abspath $(SCRIPTDIR)/__tools__/clean.sh) TESTSCRIPT = $(abspath $(SCRIPTDIR)/__tools__/run-tests.sh) BENCHMARKSCRIPT = $(abspath $(SCRIPTDIR)/__tools__/run-benchmarks.sh) @@ -95,9 +94,6 @@ $(DSTDIR) : verify-pre-build : $(VERIFY_PRE_BUILD) -verify-pre-config : - $(VERIFY_PRE_CONF) - build : $(PYTHON_DIR) . $(abspath $(DSTDIR)/bin/activate) && $(BUILD) @@ -106,16 +102,16 @@ verified-build : verify-pre-build rebuild : clean-build build $(CONDITIONAL_REGISTER_TARGET) -system-keys : ${PDO_ENCLAVE_CODE_SIGN_PEM} +system-keys : ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem -${PDO_ENCLAVE_CODE_SIGN_PEM} : - openssl genrsa -3 -out ${PDO_ENCLAVE_CODE_SIGN_PEM} 3072 +${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem : + openssl genrsa -3 -out ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem 3072 # SERVICES_COUNT is the number of services of each type to create # First value is the number of eservices, then pservices, then # sservices, 5 of each is the default SERVICES_COUNT ?= 5 5 5 -SERVICES_CONF_TEMPLATES = $(addprefix $(SCRIPTDIR)/template/, eservice.toml pservice.toml enclave.toml) +SERVICES_CONF_TEMPLATES = $(addprefix $(SCRIPTDIR)/template/, eservice.toml pservice.toml) SERVICES_CONF_TARGET = $(DSTDIR)/opt/pdo/.services_configured $(SERVICES_CONF_TARGET) : $(PYTHON_DIR) $(SERVICE_CONF_TEMPLATES) @@ -125,18 +121,18 @@ $(SERVICES_CONF_TARGET) : $(PYTHON_DIR) $(SERVICE_CONF_TEMPLATES) config-services : $(SERVICES_CONF_TARGET) -verified-config : verify-pre-config +verified-config : ${MAKE} config config : config-services config-client -force-config : verify-pre-config +force-config : - rm -f $(SERVICES_CONF_TARGET) $(CLIENT_CONF_TARGET) ${MAKE} config ifeq ($(SGX_MODE),HW) register : $(PYTHON_DIR) - @ echo registering enclave and IAS public key on the ledger + @ echo Register the enclave registration policy on the ledger . $(abspath $(DSTDIR)/bin/activate) && $(SRCDIR)/eservice/bin/register-with-ledger.sh else @@ -171,6 +167,6 @@ benchmark : $(PYTHON_DIR) .PHONY : all environment register system-keys .PHONY : build rebuild verified-build verify-pre-build .PHONY : clean clean-build clean-install -.PHONY : config config-services force-config verified-config verify-pre-config +.PHONY : config config-services force-config verified-config .PHONY : client build-client config-client .PHONY : benchmark test diff --git a/build/__tools__/verify-pre-build.sh b/build/__tools__/verify-pre-build.sh index 52c33fae..538a6896 100755 --- a/build/__tools__/verify-pre-build.sh +++ b/build/__tools__/verify-pre-build.sh @@ -41,7 +41,6 @@ yell --------------- CONFIG AND ENVIRONMENT PRE-BUILD CHECK --------------- : "${PDO_INSTALL_ROOT:-$(warn Missing environment variable PDO_INSTALL_ROOT)}" : "${PDO_HOME:-$(warn Missing environment variable PDO_HOME)}" -: "${PDO_ENCLAVE_CODE_SIGN_PEM:-$(warn Missing environment variable PDO_ENCLAVE_CODE_SIGN_PEM)}" ([ ! -z "${SGX_SSL}" ] && [ -f ${SGX_SSL}/include/openssl/err.h ] ) || warn "Missing or invalid environment variable SGX_SSL" ([ ! -z "${SGX_SDK}" ] && [ -f ${SGX_SDK}/include/sgx.h ] ) || warn "Missing or invalid environment variable SGX_SDK" : "${SGX_MODE:-$(warn Missing environment variable SGX_MODE, set it to HW or SIM)}" @@ -59,8 +58,4 @@ if [ ! -d "${PDO_INSTALL_ROOT}" ]; then warn "PDO_INSTALL_ROOT directory does not exist" fi -if [ ! -f "${PDO_ENCLAVE_CODE_SIGN_PEM}" ]; then - warn "PDO_ENCLAVE_CODE_SIGN_PEM file does not exist" -fi - exit $F_VERIFIED diff --git a/build/cmake/SGX.cmake b/build/cmake/SGX.cmake index f9b3665e..d69b522e 100644 --- a/build/cmake/SGX.cmake +++ b/build/cmake/SGX.cmake @@ -16,10 +16,10 @@ # Environment Variables ################################################################################ -IF (NOT DEFINED ENV{PDO_ENCLAVE_CODE_SIGN_PEM}) - MESSAGE(FATAL_ERROR "PDO_ENCLAVE_CODE_SIGN_PEM not defined") +IF (NOT DEFINED ENV{PDO_SGX_KEY_ROOT}) + MESSAGE(FATAL_ERROR "PDO_SGX_KEY_ROOT not defined") ENDIF() -SET(PDO_ENCLAVE_CODE_SIGN_PEM "$ENV{PDO_ENCLAVE_CODE_SIGN_PEM}") +SET(PDO_SGX_KEY_ROOT "$ENV{PDO_SGX_KEY_ROOT}") IF (NOT DEFINED ENV{SGX_MODE}) MESSAGE(FATAL_ERROR "SGX_MODE not defined") diff --git a/build/template/eservice.toml b/build/template/eservice.toml index 5a40516a..1dba95df 100644 --- a/build/template/eservice.toml +++ b/build/template/eservice.toml @@ -72,3 +72,20 @@ DataPath = "${data}" # BaseName is the root of the name used to store data # about the enclave. A 'enc' extension will be added BaseName = "${identity}" + +# -------------------------------------------------- +# EnclaveModule -- configuration of the SGX contract enclave +# -------------------------------------------------- +[EnclaveModule] + +# Number of available enclave workers to service requests +NumberOfEnclaves = '7' + +# ias_url is the URL of the Intel Attestation Service (IAS) server. The +# example server is for debug enclaves only, +# the production url is without the trailing '/dev' +ias_url = 'https://api.trustedservices.intel.com/sgx/dev' + +# sgx key root folder configuration +sgx_key_root = "${sgx_key_root}" + diff --git a/build/template/pservice.toml b/build/template/pservice.toml index f22a351f..5e4b204b 100644 --- a/build/template/pservice.toml +++ b/build/template/pservice.toml @@ -68,3 +68,20 @@ DataPath = "${data}" # BaseName is the root of the name used to store data # about the enclave. A 'enc' extension will be added BaseName = "${identity}" + +# -------------------------------------------------- +# EnclaveModule -- configuration of the SGX contract enclave +# -------------------------------------------------- +[EnclaveModule] + +# Number of available enclave workers to service requests +NumberOfEnclaves = '7' + +# ias_url is the URL of the Intel Attestation Service (IAS) server. The +# example server is for debug enclaves only, +# the production url is without the trailing '/dev' +ias_url = 'https://api.trustedservices.intel.com/sgx/dev' + +# sgx key root folder configuration +sgx_key_root = "${sgx_key_root}" + diff --git a/common/tests/crypto/trusted/enclave/CMakeLists.txt b/common/tests/crypto/trusted/enclave/CMakeLists.txt index d368fb0c..c22237c4 100644 --- a/common/tests/crypto/trusted/enclave/CMakeLists.txt +++ b/common/tests/crypto/trusted/enclave/CMakeLists.txt @@ -41,4 +41,4 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${COMMON_TRUSTED_LIBS}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} -Wl,--end-group) SGX_PREPARE_TRUSTED_LINK(${PROJECT_NAME}) -SGX_SIGN_ENCLAVE(${PROJECT_NAME} ${PDO_ENCLAVE_CODE_SIGN_PEM} ${ENCLAVE_CONFIG}) +SGX_SIGN_ENCLAVE(${PROJECT_NAME} ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem ${ENCLAVE_CONFIG}) diff --git a/docker/Makefile b/docker/Makefile index 9137b352..71418e18 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -50,7 +50,9 @@ DOCKER_BUILDARGS += --build-arg UID=$(PDO_USER_UID) DOCKER_BUILDARGS += --build-arg GID=$(PDO_GROUP_UID) DOCKER_ARGS = $(DOCKER_BUILDARGS) -IMAGES=base client services_base services ccf_base ccf +IAS_CERTIFICATES=$(DOCKER_DIR)/repository/common/crypto/verify_ias_report/ias-certificates.txt + +IMAGES=base client services_base services services_sgx ccf_base ccf # for the most part this is just used to force rebuild when the # PDO repository has changed @@ -71,6 +73,13 @@ build_% : repository --tag pdo_$*:$(PDO_VERSION) \ --file '$(DOCKER_DIR)'/pdo_$*.dockerfile . +sgx_build_services : $(IAS_CERTIFICATES) repository build_services_base + docker build $(DOCKER_ARGS) \ + --build-arg PDO_VERSION=$(PDO_VERSION) \ + --build-arg SGX_MODE=HW \ + --tag pdo_services_sgx:$(PDO_VERSION) \ + --file $(DOCKER_DIR)/pdo_services.dockerfile . + # docker build dependencies build_client: build_base build_services: build_services_base @@ -104,6 +113,11 @@ stop_services : stop_client : - docker rm -f client_container +$(IAS_CERTIFICATES) : repository + # the script prepares the certificates from the source repo + # and moves only the necessary artifacts to the destination repo (absolute path required) + $(DOCKER_DIR)/tools/prepare_ias_certificates.sh "$(PDO_SOURCE_ROOT)" $(DOCKER_DIR)/$< + # ----------------------------------------------------------------- # We need a repository with the source for the branch we are going # to build. In theory this could just be a copy of the local source @@ -112,8 +126,14 @@ stop_client : # performance requirements are relatively low. # ----------------------------------------------------------------- repository : + # clone the repo git clone --single-branch --branch $(PDO_BRANCH) --recurse-submodules '$(PDO_REPO)' repository + # Prepare enclave signing key (if any, this goes in the repo itself). + # This is effective only in HW mode builds. + # PDO_SGX_KEY_ROOT is an optional parameter (either set in environment or empty) + $(DOCKER_DIR)/tools/copy_enclave_signing_key.sh "$(PDO_SOURCE_ROOT)" repository "${PDO_SGX_KEY_ROOT}" + clean_repository : rm -rf repository @@ -130,12 +150,35 @@ TEST_FILES += -f services_base.yaml TEST_FILES += -f ccf_base.yaml TEST_FILES += -f test.yaml +TEST_SGX_FILES = ${TEST_FILES} +TEST_SGX_FILES += -f test-sgx.yaml + +SGX_DEVICE_PATH=$(shell if [ -e "/dev/isgx" ]; \ + then echo "/dev/isgx"; \ + elif [ -e "/dev/sgx/enclave" ]; \ + then echo "/dev/sgx/enclave"; \ + else echo "ERROR: NO SGX DEVICE FOUND"; \ + fi) + +DOCKER_COMPOSE_SGX := env SGX_DEVICE_PATH=${SGX_DEVICE_PATH} docker-compose + build_test : repository build_services build_ccf build_client test : clean_config clean_repository build_test stop_all PDO_VERSION=$(PDO_VERSION) docker-compose $(TEST_FILES) up --abort-on-container-exit PDO_VERSION=$(PDO_VERSION) docker-compose $(TEST_FILES) down +sgx_build_test : repository sgx_build_services build_ccf build_client + +sgx_keys : + # Prepare sgx keys. + # PDO_SGX_KEY_ROOT is an optional parameter (either set in environment or empty) + $(DOCKER_DIR)/tools/copy_sgx_keys.sh "$(PDO_SOURCE_ROOT)" "$(DOCKER_DIR)" "${PDO_SGX_KEY_ROOT}" + +sgx_test : clean_config clean_repository sgx_build_test stop_all sgx_keys + PDO_VERSION=$(PDO_VERSION) $(DOCKER_COMPOSE_SGX) $(TEST_SGX_FILES) up --abort-on-container-exit + PDO_VERSION=$(PDO_VERSION) $(DOCKER_COMPOSE_SGX) $(TEST_SGX_FILES) down + # ----------------------------------------------------------------- # Cleaning is a bit interesting because the containers don't go away # unless they are told to very nicely. Until they go away they hold onto @@ -151,12 +194,16 @@ clean_images : $(addprefix clean_,$(IMAGES)) clean_config : rm -f '$(DOCKER_DIR)'/xfer/ccf/keys/*.pem '$(DOCKER_DIR)'/xfer/ccf/etc/*.toml rm -f '$(DOCKER_DIR)'/xfer/services/keys/*.pem '$(DOCKER_DIR)'/xfer/services/etc/*.toml + rm -f '$(DOCKER_DIR)'/xfer/services/keys/sgx/*.pem '$(DOCKER_DIR)'/xfer/services/keys/sgx/*.txt rm -f '$(DOCKER_DIR)'/xfer/services/etc/site.psh + # clean the artifacts of the prepare_ias_certificates target + rm -f $(IAS_CERTIFICATES) clean : clean_images clean_config clean_repository .PHONY: clean clean_images clean_config clean_repository .PHONY: build_test test +.PHONY: sgx_build_test sgx_test sgx_keys .PHONY: run_ccf run_client run_services # ----------------------------------------------------------------- diff --git a/docker/README.md b/docker/README.md index dc532f52..b8c21df6 100644 --- a/docker/README.md +++ b/docker/README.md @@ -79,6 +79,17 @@ as services in detached mode. The last for the client will run an interactive shell in the client container. See below for information on how to use the client container. +### Build for SGX ### + +For the contract enclave to run in SGX hardware mode, the services +image must be built using the following target: +```bash + make sgx_build_services +``` +This will create the `pdo_service_sgx` image. Inside the image, +the `SGX_MODE=HW` environment variable further indicates that the +service were built to run in SGX. + ## Pattern: Local Development in a Container ## @@ -246,6 +257,30 @@ with the PDO tool `pdo-configure-services`. --name ${USER}_services_container pdo_services --mode copy ``` +#### PDO Services Deployment Using SGX #### + +There are a few _additional_ considerations when using the services with SGX. + +Before starting the container, make sure that the SGX collateral is available +as described [here](../docs/install). + +Also, recall that the attestation policy on the ledger has to be set once by the +first eservice of a ledger consortium member. Hence, the first service container +that is deputed to perform such registration must be instructed to do so. +```bash + docker run -v $(SCRIPT_DIR)/xfer/:/project/pdo/xfer --network host \ + -v :/var/run/aesmd --device=:/dev/sgx/enclave \ + --name ${USER}_services_container pdo_services_sgx --register +``` +This updated command allows to trigger the registration step right before +starting the services. The policy registration must happen before enclaves are +registered (or any enclave registration will fail). + +Finally, the _same_ SGX collateral must be made available to all service containers. +At enclave registration time, this will allow the eservice to generate the right +quote (and attestation verification report) that meets the attestation policy +originally registered with the PDO Transaction Processor. + ### PDO Client Deployment ### The client image creates an interactive environment for connecting diff --git a/docker/pdo_services.dockerfile b/docker/pdo_services.dockerfile index 1bb4a139..692e6427 100644 --- a/docker/pdo_services.dockerfile +++ b/docker/pdo_services.dockerfile @@ -27,6 +27,9 @@ FROM pdo_services_base:${PDO_VERSION} # ----------------------------------------------------------------- ARG REBUILD=0 +ARG SGX_MODE=SIM +ENV SGX_MODE $SGX_MODE + ARG PDO_DEBUG_BUILD=0 ENV PDO_DEBUG_BUILD=${PDO_DEBUG_BUILD} diff --git a/docker/pdo_services_base.dockerfile b/docker/pdo_services_base.dockerfile index ef813eee..a039fe6f 100644 --- a/docker/pdo_services_base.dockerfile +++ b/docker/pdo_services_base.dockerfile @@ -24,9 +24,6 @@ ARG SGX=2.22 ARG OPENSSL=3.0.12 ARG SGXSSL=3.0_Rev1 -ARG SGX_MODE=SIM -ENV SGX_MODE $SGX_MODE - RUN echo "deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu ${UBUNTU_NAME} main" >> /etc/apt/sources.list \ && wget -qO - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | apt-key add - \ && apt-get update \ @@ -71,17 +68,16 @@ ENV PATH="/opt/intel/sgxsdk.extras/external/toolset/ubuntu${UBUNTU_VERSION}:${PA # ----------------------------------------------------------------- # SGXSSL -# Note that we build sgxssl with SIM mode; the SGX_MODE only changes -# the mode for running tests and we do not want the tests run in HW -# mode +# Note that the SGX_MODE variable only determines the mode for +# running tests. We do not want the tests to run in HW mode here. +# This allows us to keep this image mode-agnostic. # ----------------------------------------------------------------- WORKDIR /tmp RUN . /opt/intel/sgxsdk/environment \ && git clone --depth 1 --branch ${SGXSSL} 'https://github.com/intel/intel-sgx-ssl.git' \ && wget -q -P /tmp/intel-sgx-ssl/openssl_source https://www.openssl.org/source/openssl-${OPENSSL}.tar.gz \ && cd /tmp/intel-sgx-ssl/Linux \ - && if [ $SGX_MODE = SIM ] ; then SKIP_INTELCPU_CHECK=TRUE ; else SKIP_INTELCPU_CHECK=FALSE ; fi \ - && bash -c "make SKIP_INTELCPU_CHECK=$SKIP_INTELCPU_CHECK SGX_MODE=$SGX_MODE NO_THREADS=1 DESTDIR=/opt/intel/sgxssl VERBOSE=0 all &> /dev/null" \ + && bash -c "make SKIP_INTELCPU_CHECK=TRUE SGX_MODE=SIM NO_THREADS=1 DESTDIR=/opt/intel/sgxssl VERBOSE=0 all &> /dev/null" \ && make install \ && make clean \ && rm -rf /tmp/intel-sgx-ssl diff --git a/docker/test-sgx.yaml b/docker/test-sgx.yaml new file mode 100644 index 00000000..5b1a7d53 --- /dev/null +++ b/docker/test-sgx.yaml @@ -0,0 +1,33 @@ +# Copyright 2024 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------------------------ +version: "3.4" + +services: + ccf_container: + environment: + - SGX_MODE=HW + + services_container: + environment: + # the PDO_FORCE_IAS_PROXY is a small hack that is used to force IAS connections + # through a proxy when one such proxy must be used. + # If the variable is defined in the host environment, it is propagated to the containers. + - PDO_FORCE_IAS_PROXY=${PDO_FORCE_IAS_PROXY:-false} + image: pdo_services_sgx:${PDO_VERSION:-latest} + volumes: + - /var/run/aesmd:/var/run/aesmd + devices: + - ${SGX_DEVICE_PATH:-/dev/isgx}:${SGX_DEVICE_PATH:-/dev/isgx} + diff --git a/docker/tools/copy_enclave_signing_key.sh b/docker/tools/copy_enclave_signing_key.sh new file mode 100755 index 00000000..ef6bc7bc --- /dev/null +++ b/docker/tools/copy_enclave_signing_key.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Copyright 2024 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# This script copies the enclave signing key on the host (if any) for the docker container build. +# environment.sh is not imported, as this script is meant to run on the host. +# Note: the key (if any) is copied into the default folder for HW mode builds; +# so for SIM mode builds, this will have no effect. + +if [ $# != 2 ] && [ $# != 3 ]; then + echo "$(basename $0 ' [ ${PDO_SGX_KEY_ROOT} ]')" + echo "PDO source and dest paths are required, PDO_SGX_KEY_ROOT is optional" + exit 1 +fi + +PDO_SOURCE_ROOT=$1 +PDO_DEST_ROOT=$2 +PDO_SGX_KEY_ROOT=$3 + +source ${PDO_SOURCE_ROOT}/bin/lib/common.sh + +# If an enclave signing key is available on the host, copy that under build/keys in the repo +# Note: on the host, the key must be in ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem, +# and the env variable must be defined. +# Note: in the docker container, the host key (or a new key) will be placed on the same path, +# but the PDO_SGX_KEY_ROOT default value is defined in docker/tools/environment.sh + +KEY_REL_PATH="build/keys/sgx_mode_hw/enclave_code_sign.pem" + +if [ ! -z "${PDO_SGX_KEY_ROOT}" ] && [ -e "${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem" ]; then + yell "Enclave signing key: using host-provided key: ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem" + yell "Enclave signing key: copying it to ${PDO_DEST_ROOT}/${KEY_REL_PATH}" + try cp ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem ${PDO_DEST_ROOT}/${KEY_REL_PATH} +else + yell "Enclave signing key: none available, now checking default path ${PDO_SOURCE_ROOT}/${KEY_REL_PATH}" + if [ -e "${PDO_SOURCE_ROOT}/${KEY_REL_PATH}" ]; then + yell "Enclave signing key: key available, copying it to ${PDO_DEST_ROOT}/${KEY_REL_PATH}" + try cp ${PDO_SOURCE_ROOT}/${KEY_REL_PATH} ${PDO_DEST_ROOT}/${KEY_REL_PATH} + else + yell "Enclave signing key: no default key, a new one will be generated" + fi +fi + +exit 0 + diff --git a/docker/tools/copy_sgx_keys.sh b/docker/tools/copy_sgx_keys.sh new file mode 100755 index 00000000..4b6914b6 --- /dev/null +++ b/docker/tools/copy_sgx_keys.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Copyright 2024 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# This script prepares the sgx keys on the host for the docker container build. +# environment.sh is not imported, as this script is meant to run on the host. + +if [ $# != 2 ] && [ $# != 3 ]; then + echo "$(basename $0 '${PDO_SOURCE_ROOT} ${DOCKER_DIR} [ ${PDO_SGX_KEY_ROOT} ]')" + echo "PDO_SOURCE_ROOT and DOCKER_DIR are required, PDO_SGX_KEY_ROOT is optional" + exit 1 +fi + +PDO_SOURCE_ROOT=$1 +DOCKER_DIR=$2 +PDO_SGX_KEY_ROOT=$3 + +source ${PDO_SOURCE_ROOT}/bin/lib/common.sh + +# check for sgx keys in PDO_SGX_KEY_ROOT and copy that in xfer +# or, copy anything in the default folder to xfer + +if [ ! -z "${PDO_SGX_KEY_ROOT}" ]; then + # PDO_SGX_KEY_ROOT is set + yell "SGX keys: checking for source SGX keys in ${PDO_SGX_KEY_ROOT}" + if [ ! -f ${PDO_SGX_KEY_ROOT}/sgx_spid_api_key.txt ] || + [ ! -f ${PDO_SGX_KEY_ROOT}/sgx_spid.txt ] || + [ ! -f ${PDO_SGX_KEY_ROOT}/sgx_ias_key.pem ]; then + die "SGX keys: missing - check PDO_SGX_KEY_ROOT and SGX keys in it" + fi + + yell "SGX keys: found ... copying them to docker" + try cp ${PDO_SGX_KEY_ROOT}/* ${DOCKER_DIR}/xfer/services/keys/sgx/ + +else + yell "SGX keys: PDO_SGX_KEY_ROOT undefined" + yell "SGX keys: copying default folder ${PDO_SOURCE_ROOT}/build/keys/sgx_mode_hw/ to docker" + # copy anything in the default folder, and ignore errors if no keys exist + ls ${PDO_SOURCE_ROOT}/build/keys/sgx_mode_hw/* + cp ${PDO_SOURCE_ROOT}/build/keys/sgx_mode_hw/* ${DOCKER_DIR}/xfer/services/keys/sgx/ 2>/dev/null + echo $? + ls ${DOCKER_DIR}/xfer/services/keys/sgx/ +fi + +# test sgx keys availability in xfer +# this succeeds if it was copied above, or if it was already in place +yell "SGX keys: checking for SGX keys in docker" +if [ ! -f ${DOCKER_DIR}/xfer/services/keys/sgx/sgx_spid_api_key.txt ] || + [ ! -f ${DOCKER_DIR}/xfer/services/keys/sgx/sgx_spid.txt ] || + [ ! -f ${DOCKER_DIR}/xfer/services/keys/sgx/sgx_ias_key.pem ]; then + yell "SGX keys: not found in docker -- set PDO_SGX_KEY_ROOT and check sgx keys" + exit 1 +fi +yell "SGX keys: docker-ready" + +exit 0 + diff --git a/docker/tools/environment.sh b/docker/tools/environment.sh index c0850b12..f6407b12 100755 --- a/docker/tools/environment.sh +++ b/docker/tools/environment.sh @@ -44,23 +44,7 @@ fi export XFER_DIR=${XFER_DIR:-/project/pdo/xfer} -# if the container is running HW mode, then we will grab the -# SGX keys from the xfer directory; we know that the default -# keys must be overridden -if [ ${SGX_MODE} == "HW" ]; then - export PDO_SGX_KEY_ROOT=${XFER_DIR}/services/keys/sgx -else - export PDO_SGX_KEY_ROOT=${PDO_SOURCE_ROOT}/build/keys/sgx_mode_${SGX_MODE,,} -fi - -# this variable is needed for the build for signing the -# eservice and pservice enclaves -export PDO_ENCLAVE_CODE_SIGN_PEM=${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem - -# these are only used for configuration and registration -# they are not used at build or run time -export PDO_SPID="$(cat ${PDO_SGX_KEY_ROOT}/sgx_spid.txt)" -export PDO_SPID_API_KEY="$(cat ${PDO_SGX_KEY_ROOT}/sgx_spid_api_key.txt)" +export PDO_SGX_KEY_ROOT=${PDO_SOURCE_ROOT}/build/keys/sgx_mode_${SGX_MODE,,} # set up the ccf directories, ccf_base is where the ccf # core is installed, ccf_pdo_dir is where the pdo tp diff --git a/docker/tools/prepare_ias_certificates.sh b/docker/tools/prepare_ias_certificates.sh new file mode 100755 index 00000000..4d67af06 --- /dev/null +++ b/docker/tools/prepare_ias_certificates.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Copyright 2024 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# This script prepares the IAS certificate that is necessary for build in HW mode. +# The certificate is downloaded in the repo before the docker build, thus becoming +# part of the "repository". The docker build will then clone the repository in the +# container. As the certificate will be avialable, the build inside docker will not +# attempt to retrieve it. + +if [ $# != 2 ] ; then + echo "$(basename $0 '$ /dev/null + # ----------------------------------------------------------------- yell configure services for host $PDO_HOSTNAME and ledger $PDO_LEDGER_URL # ----------------------------------------------------------------- @@ -56,7 +62,7 @@ yell check for registration # ----------------------------------------------------------------- # this probably requires additional CCF keys, need to test this if [ "$SGX_MODE" == "HW" ]; then - if [ ! -f ${XFER}/ccf/keys/memberccf_privk.pem ] ; then + if [ ! -f ${XFER_DIR}/ccf/keys/memberccf_privk.pem ] ; then die unable to locate CCF policies keys fi diff --git a/docker/tools/start_services.sh b/docker/tools/start_services.sh index 11f21926..b7bf6853 100755 --- a/docker/tools/start_services.sh +++ b/docker/tools/start_services.sh @@ -82,6 +82,16 @@ check_pdo_runtime_env export no_proxy=$PDO_HOSTNAME,$PDO_LEDGER_ADDRESS,$no_proxy export NO_PROXY=$PDO_HOSTNAME,$PDO_LEDGER_ADDRESS,$NO_PROXY +# ----------------------------------------------------------------- +yell copy sgx keys +# ----------------------------------------------------------------- +# copy any keys in the SGX directory, ignore any errors if no keys exist +cp ${XFER_DIR}/services/keys/sgx/* ${PDO_SGX_KEY_ROOT} 2>/dev/null + +# ----------------------------------------------------------------- +yell Register with ledger: ${F_REGISTER} +# ----------------------------------------------------------------- + # ----------------------------------------------------------------- # Handle the configuration of the services # ----------------------------------------------------------------- @@ -115,7 +125,7 @@ try cp ${XFER_DIR}/ccf/keys/networkcert.pem ${PDO_LEDGER_KEY_ROOT}/ yell register the enclave if necessary # ----------------------------------------------------------------- if [ "${F_REGISTER,,}" == 'yes' ]; then - if [ ! -f ${XFER}/ccf/keys/memberccf_privk.pem ] ; then + if [ ! -f ${XFER_DIR}/ccf/keys/memberccf_privk.pem ] ; then die unable to locate CCF policies keys fi diff --git a/docs/install.md b/docs/install.md index 3943125b..969a6a57 100644 --- a/docs/install.md +++ b/docs/install.md @@ -115,13 +115,19 @@ to create the client authentication key. The key will be available from your profile page. Now organize your data as follows under the `${PDO_SGX_KEY_ROOT}` folder -(the default folder is `${PDO_SOURCE_ROOT}/build/keys/sgx_mode_${SGX_MODE,,}`, +(the default folder is `${PDO_SOURCE_ROOT}/build/keys/sgx_mode_hw`, or you can define yours with `export PDO_SGX_KEY_ROOT=`): -* save your SPID in `${PDO_SGX_KEY_ROOT}/sgx_spid_api_key.txt` +* save your SPID in `${PDO_SGX_KEY_ROOT}/sgx_spid.txt` * save your API key in `${PDO_SGX_KEY_ROOT}/sgx_spid_api_key.txt` * save the IAS root CA certificate in `${PDO_SGX_KEY_ROOT}/sgx_ias_key.pem` (`wget https://certificates.trustedservices.intel.com/Intel_SGX_Attestation_RootCA.pem -O ${PDO_SGX_KEY_ROOT}/sgx_ias_key.pem`) +#### (optional) Set the path to an existing enclave code signing key + +At build time, an enclave code signing key is required to sign the contract enclave. +If one such key is available, it can be used by organizing it as follows: +* save the enclave code signing key in `${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem` + #### Install the SGX Kernel Driver (Hardware Support) SGX can run in either simulation or hardware mode. No kernel driver is @@ -178,7 +184,9 @@ To validate that your SGX HW installation & and corresponding PDO configuration is working properly, the easiest way is to install docker as discussed below and then run ```bash - make SGX_MODE=HW -C docker test +. build/common-config.sh + +make -C docker sgx_test ``` This will build PDO and automatically execute the tests described in the Section [Validate the Installation](usage.md#validating) in HW mode. diff --git a/docs/usage.md b/docs/usage.md index a97353b3..855dee4e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -41,10 +41,6 @@ configuration file: | `sservice` | state storage service associated with an enclave service | [`sservice.toml`](../build/opt/pdo/templates/sservice.toml) | | `pdo-shell` | the PDO client shell for creating contracts and invoking methods | [`pcontract.toml`](../build/opt/pdo/templates/pcontract.toml) | -For simplicity in installation, the file `enclave.toml` in the -`${PDO_HOME}/etc` directory contains the configuration for the accessing -the Intel Attestation Service. - In addition, most provided `pdo-shell` scripts use the service configuration information found in [`${PDO_HOME}/etc/site.psh`](../build/opt/pdo/templates/site.psh). @@ -62,6 +58,18 @@ Using PDO requires a running instance of a ledger. Documentation for building, installing and running [Microsoft CCF](../ledgers/ccf/README.md) is available. +PDO provides a script to start and configure the ledger (see `ledgers/ccf/scripts/start_ccf_network.sh`). +If `"${SGX_MODE}" == "SIM"`, the script configures the PDO TP to skip attestation checks. +If `"${SGX_MODE}" == "HW"`, the script configures the PDO TP to enforce attestation checks. +In this case, a policy must be registered (see [README](../ledgers/ccf/README.md)). + +# Register the attestation policy with the ledger + +The registration of the attestation policy is required if `"${SGX_MODE}" == "HW"`, and irrelevant otherwise. +PDO provides the `private-data-objects/eservice/bin/register-with-ledger.sh` script to automate this procedure. +The script is meant to be use by a member of the ledger consortium, at the eservice side, +once the contract enclave's MRENCLAVE is available (i.e., once enclave build is completed). + # Validate the Installation The easiest way to validate that your installation is correct is to run diff --git a/eservice/bin/register-with-ledger.sh b/eservice/bin/register-with-ledger.sh index fdd85526..d2432057 100755 --- a/eservice/bin/register-with-ledger.sh +++ b/eservice/bin/register-with-ledger.sh @@ -21,10 +21,11 @@ ETCDIR=${DSTDIR}/opt/pdo/etc/ ESERVICE_IDENTITY=eservice1 ESERVICE_TOML=${ESERVICE_IDENTITY}.toml -ENCLAVE_TOML=enclave.toml -PDO_IAS_SIGNING_CERT_PATH=${PDO_SGX_KEY_ROOT}/ias_signing.cert -PDO_IAS_KEY_PEM=${PDO_SGX_KEY_ROOT}/sgx_ias_key.pem +SGX_KEY_ROOT=${PDO_SGX_KEY_ROOT:-${SRCDIR}/build/keys/sgx_mode_${SGX_MODE,,}} + +IAS_SIGNING_CERT_PATH=${SGX_KEY_ROOT}/ias_signing.cert +IAS_KEY_PEM=${SGX_KEY_ROOT}/sgx_ias_key.pem eservice_enclave_info_file=$(mktemp /tmp/pdo-test.XXXXXXXXX) @@ -39,41 +40,35 @@ function cleanup { trap cleanup EXIT -#Set SPID to parameter if passed -SPID=$PDO_SPID -if (( "$#" == 1 )) ; then - SPID=$1 -fi - function DeriveIasPublicKey { - try test -e ${PDO_IAS_SIGNING_CERT_PATH} - try openssl x509 -pubkey -noout -in ${PDO_IAS_SIGNING_CERT_PATH} > ${PDO_IAS_KEY_PEM} + yell Derive IAS public to be registered on the ledger + try test -e ${IAS_SIGNING_CERT_PATH} + try openssl x509 -pubkey -noout -in ${IAS_SIGNING_CERT_PATH} > ${IAS_KEY_PEM} + yell IAS public derived in ${IAS_KEY_PEM} } -# Store MR_ENCLAVE & MR_BASENAME to eservice_enclave_info_file -# Note: an alternative way without any enclave invocations would be the following. -# -# if [ -z "${SPID}" -o ${#SPID} != 32 ]; then -# echo "No valid (length 32) SPID pass as argument or PDO_SPID environment variable" -# exit 1 -# fi -# perl -0777 -ne 'if (/metadata->enclave_css.body.enclave_hash.m:([a-fx0-9 \n]+)/) { $eh = $1; $eh=~s/0x| |\n//g; $eh=~tr/a-z/A-Z/; $bn="'${SPID}'"; $bn .= "0" x (64 - length $bn); print "MRENCLAVE:${eh}\nBASENAME:${bn}\n"; }' ./build/lib/libpdo-enclave.signed.so.meta > $eservice_enclave_info_file -# # Note: group id is always zero, hence the zero-padding ... -# -# This would also allow removing in eservice/pservice the code related to CreateErsatzEnclaveReport and GetEnclave Characteristics -# However, getting basename via enclave invocation & quote is somewhat cleaner than below .. function Store { - : "${SPID:?Need PDO_SPID environment variable set or passed in for valid MR_BASENAME}" try test -e ${ETCDIR}/${ESERVICE_TOML} - try test -e ${ETCDIR}/${ENCLAVE_TOML} yell Download IAS certificates and Compute the enclave information - try eservice-enclave-info \ - --spid ${SPID} \ - --save ${eservice_enclave_info_file} \ - --loglevel warn \ - --identity ${ESERVICE_IDENTITY} \ - --config ${ESERVICE_TOML} ${ENCLAVE_TOML} \ - --config-dir ${ETCDIR} + if [ "${PDO_FORCE_IAS_PROXY}" == "true" ]; then + yell PDO_FORCE_IAS_PROXY is true + NO_PROXY='' no_proxy='' try eservice-enclave-info \ + --save ${eservice_enclave_info_file} \ + --loglevel info \ + --logfile __screen__ \ + --identity ${ESERVICE_IDENTITY} \ + --config ${ESERVICE_TOML} \ + --config-dir ${ETCDIR} + else + try eservice-enclave-info \ + --save ${eservice_enclave_info_file} \ + --loglevel info \ + --logfile __screen__ \ + --identity ${ESERVICE_IDENTITY} \ + --config ${ESERVICE_TOML} \ + --config-dir ${ETCDIR} + fi + yell Enclave info are ready } # Registers MR_ENCLAVE & BASENAMES with Ledger @@ -85,13 +80,14 @@ function Register { VAR_BASENAME=$(grep -o 'BASENAME:.*' ${eservice_enclave_info_file} | cut -f2- -d:) : "${PDO_LEDGER_URL:?Registration failed! PDO_LEDGER_URL environment variable not set}" - : "PDO_IAS_KEY_PEM" "${PDO_IAS_KEY_PEM:?Registration failed! PDO_IAS_KEY_PEM environment variable not set}" + : "IAS_KEY_PEM" "${IAS_KEY_PEM:?Registration failed! PDO_IAS_KEY_PEM environment variable not set}" if [ ${PDO_LEDGER_TYPE} == "ccf" ]; then + yell Register enclave with CCF ledger: mrenclave=${VAR_MRENCLAVE} basename=${VAR_BASENAME} source ${PDO_INSTALL_ROOT}/bin/activate try ${PDO_INSTALL_ROOT}/bin/ccf_set_expected_sgx_measurements \ --logfile __screen__ --loglevel INFO --mrenclave ${VAR_MRENCLAVE} \ - --basename ${VAR_BASENAME} --ias-public-key "$(cat $PDO_IAS_KEY_PEM)" + --basename ${VAR_BASENAME} --ias-public-key "$(cat $IAS_KEY_PEM)" else die unsupported ledger ${PDO_LEDGER_TYPE} fi diff --git a/eservice/docs/test-scripts.md b/eservice/docs/test-scripts.md index a2c38bd1..fff27e28 100644 --- a/eservice/docs/test-scripts.md +++ b/eservice/docs/test-scripts.md @@ -66,10 +66,8 @@ The following configuration variables can be specified: will send all logging information to the console * ``EnclaveModule`` - * ``spid`` -- a 32-digit hex string tied to the enclave implementation * ``ias_url`` -- URL of the Intel Attestation Service (IAS) server (ignored) - * ``https_proxy`` -- proxy used to contact IAS server (ignored) - * ``spid_api_key`` -- the api key corresponding to spid (ignored) + * ``sgx_key_root`` -- folder containing the sgx keys (ignored) * ``contract`` -- the base name of the contract to use, this is expected to reference a file found in ``SourceSearchPath`` diff --git a/eservice/lib/libpdo_enclave/CMakeLists.txt b/eservice/lib/libpdo_enclave/CMakeLists.txt index 396959e3..9bea66ca 100644 --- a/eservice/lib/libpdo_enclave/CMakeLists.txt +++ b/eservice/lib/libpdo_enclave/CMakeLists.txt @@ -43,5 +43,5 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${COMMON_TRUSTED_LIBS}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} -Wl,--end-group) SGX_PREPARE_TRUSTED_LINK(${PROJECT_NAME}) -SGX_SIGN_ENCLAVE(${PROJECT_NAME} ${PDO_ENCLAVE_CODE_SIGN_PEM} ${PROJECT_CONFIG}) +SGX_SIGN_ENCLAVE(${PROJECT_NAME} ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem ${PROJECT_CONFIG}) SGX_DEPLOY_FILES(${PROJECT_NAME} eservice) diff --git a/eservice/pdo/eservice/pdo_enclave.py b/eservice/pdo/eservice/pdo_enclave.py index 468af67e..9228ca7a 100644 --- a/eservice/pdo/eservice/pdo_enclave.py +++ b/eservice/pdo/eservice/pdo_enclave.py @@ -16,6 +16,7 @@ import json import time import toml +from pathlib import Path from ssl import SSLError from requests.exceptions import Timeout @@ -137,7 +138,7 @@ def initialize_with_configuration(config) : enclave.SetLogger(logger) # Ensure that the required keys are in the configuration - valid_keys = set(['spid', 'ias_url', 'spid_api_key']) + valid_keys = set(['ias_url', 'sgx_key_root']) found_keys = set(config.keys()) missing_keys = valid_keys.difference(found_keys) @@ -148,20 +149,25 @@ def initialize_with_configuration(config) : '{}'.format( ', '.join(sorted(list(missing_keys))))) - num_of_enclaves = int(config.get('num_of_enclaves', 1)) + NumberOfEnclaves = int(config.get('NumberOfEnclaves', 1)) + + try: + spid = Path(os.path.join(config['sgx_key_root'], "sgx_spid.txt")).read_text().strip() + spid_api_key = Path(os.path.join(config['sgx_key_root'], "sgx_spid_api_key.txt")).read_text().strip() + except Exception as e : + raise Exception("Unable to access SGX keys: {}".format(str(e))) if not _ias: _ias = \ ias_client.IasClient( IasServer = config['ias_url'], - SpidApiKey = config['spid_api_key'], - Spid = config['spid'], - HttpsProxy = config.get('https_proxy', "")) + SpidApiKey = spid_api_key, + Spid = spid) if not _pdo: signed_enclave = __find_enclave_library(config) logger.debug("Attempting to load enclave at: %s", signed_enclave) - _pdo = enclave.pdo_enclave_info(signed_enclave, config['spid'], num_of_enclaves) + _pdo = enclave.pdo_enclave_info(signed_enclave, spid, NumberOfEnclaves) logger.info("Basename: %s", get_enclave_basename()) logger.info("MRENCLAVE: %s", get_enclave_measurement()) @@ -232,8 +238,8 @@ def get_enclave_service_info(spid, config=None) : signed_enclave = __find_enclave_library(None) logger.debug("Attempting to load enclave at: %s", signed_enclave) - num_of_enclaves = 1 - pdo = enclave.pdo_enclave_info(signed_enclave, spid, num_of_enclaves) + NumberOfEnclaves = 1 + pdo = enclave.pdo_enclave_info(signed_enclave, spid, NumberOfEnclaves) if pdo is None : raise Exception('unable to load the enclave') diff --git a/eservice/pdo/eservice/scripts/EServiceCLI.py b/eservice/pdo/eservice/scripts/EServiceCLI.py index e26d72e4..d52d7cbc 100644 --- a/eservice/pdo/eservice/scripts/EServiceCLI.py +++ b/eservice/pdo/eservice/scripts/EServiceCLI.py @@ -246,7 +246,7 @@ def Main() : config_map = pconfig.build_configuration_map() # parse out the configuration file first - conffiles = [ 'eservice.toml', 'enclave.toml' ] + conffiles = [ 'eservice.toml' ] confpaths = [ ".", "./etc", config_map['etc'] ] parser = argparse.ArgumentParser() @@ -271,6 +271,8 @@ def Main() : parser.add_argument('--enclave-save', help='Name of the directory where enclave data will be save', type=str) parser.add_argument('--enclave-path', help='Directories to search for the enclave data file', type=str, nargs = '+') + parser.add_argument('--sgx-key-root', help='Path to SGX key root folder', type = str) + options = parser.parse_args() # first process the options necessary to load the default configuration @@ -355,6 +357,18 @@ def Main() : port = config['StorageService'].get('HttpPort',7201) config['StorageService']['URL'] = "http://{0}:{1}".format(host, port) + # set up the default enclave module configuration (if necessary) + if config.get('EnclaveModule') is None : + config['EnclaveModule'] = { + 'NumberOfEnclaves' : 7, + 'ias_url' : 'https://api.trustedservices.intel.com/sgx/dev', + 'sgx_key_root' : os.environ.get('PDO_SGX_KEY_ROOT', '.') + } + + # override the enclave module configuration (if options are specified) + if options.sgx_key_root : + config['EnclaveModule']['sgx_key_root'] = options.sgx_key_root + # GO! LocalMain(config) diff --git a/eservice/pdo/eservice/scripts/EServiceEnclaveInfoCLI.py b/eservice/pdo/eservice/scripts/EServiceEnclaveInfoCLI.py index 7a6b977f..ae0f9680 100644 --- a/eservice/pdo/eservice/scripts/EServiceEnclaveInfoCLI.py +++ b/eservice/pdo/eservice/scripts/EServiceEnclaveInfoCLI.py @@ -18,6 +18,7 @@ import sys import argparse import json +from pathlib import Path import pdo.common.config as pconfig import pdo.common.logger as plogger @@ -30,15 +31,18 @@ import time + + # ----------------------------------------------------------------- # ----------------------------------------------------------------- -def GetBasename(spid, save_path, config) : +def GetBasename(save_path, config) : attempts = 0 while True : try : logger.debug('initialize the enclave') - enclave_config = {} - info = pdo_enclave_helper.get_enclave_service_info(spid, config=enclave_config) + enclave_config = config.get('EnclaveModule') + spid = Path(os.path.join(enclave_config['sgx_key_root'], "sgx_spid.txt")).read_text().strip() + info = pdo_enclave_helper.get_enclave_service_info(spid) logger.info('save MR_ENCLAVE and MR_BASENAME to %s', save_path) with open(save_path, "w") as file : @@ -71,7 +75,7 @@ def GetIasCertificates(config) : # (signup info are not relevant here) # the creation of signup info includes getting a verification report from IAS try : - enclave_config = config['EnclaveModule'] + enclave_config = config.get('EnclaveModule') pdo_enclave.initialize_with_configuration(enclave_config) except Exception as e : logger.error("unable to initialize a new enclave; %s", str(e)) @@ -86,14 +90,10 @@ def GetIasCertificates(config) : ias_certificates = pd_dict['certificates'] # dump the IAS certificates in the respective files - IasKeysPath = os.environ.get("PDO_SGX_KEY_ROOT") - - IasRootCACertificate_FilePath = os.path.join(IasKeysPath, "ias_root_ca.cert") - with open(IasRootCACertificate_FilePath, "w+") as file : + with open(os.path.join(enclave_config['sgx_key_root'], "ias_root_ca.cert"), "w+") as file : file.write("{0}".format(ias_certificates[1])) - IasAttestationVerificationCertificate_FilePathname = os.path.join(IasKeysPath, "ias_signing.cert") - with open(IasAttestationVerificationCertificate_FilePathname, "w+") as file : + with open(os.path.join(enclave_config['sgx_key_root'], "ias_signing.cert"), "w+") as file : file.write("{0}".format(ias_certificates[0])) except Exception as e : @@ -104,8 +104,8 @@ def GetIasCertificates(config) : # do a clean shutdown of enclave pdo_enclave.shutdown() -def LocalMain(config, spid, save_path) : - GetBasename(spid, save_path, config) +def LocalMain(config, save_path) : + GetBasename(save_path, config) GetIasCertificates(config) sys.exit(0) @@ -119,7 +119,7 @@ def Main() : config_map = pconfig.build_configuration_map() # parse out the configuration file first - conffiles = [ 'eservice.toml', 'enclave.toml' ] + conffiles = [ 'eservice.toml' ] confpaths = [ ".", "./etc", config_map['etc'] ] parser = argparse.ArgumentParser() @@ -127,7 +127,7 @@ def Main() : parser.add_argument('--config-dir', help='directory to search for configuration files', nargs = '+') parser.add_argument('--identity', help='Identity to use for the process', required = True, type = str) - parser.add_argument('--spid', help='SPID to generate enclave basename', type=str) + parser.add_argument('--sgx-key-root', help='Path to SGX key root folder', type = str) parser.add_argument('--save', help='Where to save MR_ENCLAVE and BASENAME', type=str) parser.add_argument('--logfile', help='Name of the log file, __screen__ for standard output', type=str) @@ -145,9 +145,6 @@ def Main() : if options.save : save_path = options.save - if options.spid : - spid = options.spid - config_map['identity'] = options.identity try : config = pconfig.parse_configuration_files(conffiles, confpaths, config_map) @@ -169,8 +166,20 @@ def Main() : sys.stdout = plogger.stream_to_logger(logging.getLogger('STDOUT'), logging.DEBUG) sys.stderr = plogger.stream_to_logger(logging.getLogger('STDERR'), logging.WARN) + # set up the default enclave module configuration (if necessary) + if config.get('EnclaveModule') is None : + config['EnclaveModule'] = { + 'NumberOfEnclaves' : 7, + 'ias_url' : 'https://api.trustedservices.intel.com/sgx/dev', + 'sgx_key_root' : os.environ.get('PDO_SGX_KEY_ROOT', '.') + } + + # override the enclave module configuration (if options are specified) + if options.sgx_key_root : + config['EnclaveModule']['sgx_key_root'] = options.sgx_key_root + # GO! - LocalMain(config, spid, save_path) + LocalMain(config, save_path) ## ----------------------------------------------------------------- ## Entry points diff --git a/eservice/pdo/eservice/utility/ias_client.py b/eservice/pdo/eservice/utility/ias_client.py index f67e205d..660c2f58 100644 --- a/eservice/pdo/eservice/utility/ias_client.py +++ b/eservice/pdo/eservice/utility/ias_client.py @@ -32,10 +32,6 @@ class IasClient(object): def __init__(self, **kwargs): logger.info("IAS settings:") - self._proxies = {} - if "HttpsProxy" in kwargs: - self._proxies["https"] = kwargs["HttpsProxy"] - logger.info("Proxy: " + self._proxies["https"]) if "Spid" in kwargs: self._spid = kwargs["Spid"] logger.info("SPID: " + self._spid) @@ -65,7 +61,7 @@ def get_signature_revocation_lists(self, url = self._ias_url + path + gid[0:8] logger.debug("Fetching SigRL from: %s", url) - result = requests.get(url, proxies=self._proxies, + result = requests.get(url, headers={'Ocp-Apim-Subscription-Key': self._spid_api_key}) if result.status_code != requests.codes.ok: logger.debug("get_signature_revocation_lists HTTP Error code : %d", @@ -90,7 +86,6 @@ def post_verify_attestation(self, quote, manifest=None, nonce=None): logger.debug("Posting attestation verification request to: %s\n", url) result = requests.post(url, json=json, - proxies=self._proxies, headers={'Ocp-Apim-Subscription-Key': self._spid_api_key}, timeout=self._timeout) logger.debug("result headers: %s\n", result.headers) diff --git a/eservice/tests/test-secrets.py b/eservice/tests/test-secrets.py index fed2b25e..ab7d45eb 100644 --- a/eservice/tests/test-secrets.py +++ b/eservice/tests/test-secrets.py @@ -60,7 +60,7 @@ def ErrorShutdown() : # ----------------------------------------------------------------- # ----------------------------------------------------------------- config_map = pconfig.build_configuration_map() -conffiles = [ 'pcontract.toml', 'enclave.toml', 'eservice1.toml' ] +conffiles = [ 'pcontract.toml', 'eservice1.toml' ] confpaths = [ ".", "./etc", config_map['etc'] ] import argparse @@ -69,6 +69,7 @@ def ErrorShutdown() : parser.add_argument('--config-dir', help='configuration file', nargs = '+') parser.add_argument('--loglevel', help='Set the logging level', default='INFO') parser.add_argument('--logfile', help='Name of the log file', default='__screen__') +parser.add_argument('--sgx-key-root', help='Path to SGX key root folder', type = str) options = parser.parse_args() config_map['identity'] = 'test-secrets' @@ -100,6 +101,18 @@ def ErrorShutdown() : logger.error('failed to initialize the block store; %s', str(e)) ErrorShutdown() +# set up the default enclave module configuration (if necessary) +if config.get('EnclaveModule') is None : + config['EnclaveModule'] = { + 'NumberOfEnclaves' : 7, + 'ias_url' : 'https://api.trustedservices.intel.com/sgx/dev', + 'sgx_key_root' : os.environ.get('PDO_SGX_KEY_ROOT', '.') + } + +# override the enclave module configuration (if options are specified) +if options.sgx_key_root : + config['EnclaveModule']['sgx_key_root'] = options.sgx_key_root + # ----------------------------------------------------------------- # ----------------------------------------------------------------- plogger.setup_loggers({'LogLevel' : options.loglevel.upper(), 'LogFile' : options.logfile}) diff --git a/pservice/lib/libpdo_enclave/CMakeLists.txt b/pservice/lib/libpdo_enclave/CMakeLists.txt index 2465eae0..75acfdd8 100644 --- a/pservice/lib/libpdo_enclave/CMakeLists.txt +++ b/pservice/lib/libpdo_enclave/CMakeLists.txt @@ -49,5 +49,5 @@ TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${COMMON_TRUSTED_LIBS}) TARGET_LINK_LIBRARIES(${PROJECT_NAME} -Wl,--end-group) SGX_PREPARE_TRUSTED_LINK(${PROJECT_NAME}) -SGX_SIGN_ENCLAVE(${PROJECT_NAME} ${PDO_ENCLAVE_CODE_SIGN_PEM} ${PROJECT_CONFIG}) +SGX_SIGN_ENCLAVE(${PROJECT_NAME} ${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem ${PROJECT_CONFIG}) SGX_DEPLOY_FILES(${PROJECT_NAME} pservice) diff --git a/pservice/pdo/pservice/pdo_enclave.py b/pservice/pdo/pservice/pdo_enclave.py index c0b4b57b..bdb8e945 100644 --- a/pservice/pdo/pservice/pdo_enclave.py +++ b/pservice/pdo/pservice/pdo_enclave.py @@ -16,6 +16,7 @@ import json import time import toml +from pathlib import Path from ssl import SSLError from requests.exceptions import Timeout @@ -132,7 +133,7 @@ def initialize_with_configuration(config) : enclave._SetLogger(logger) # Ensure that the required keys are in the configuration - valid_keys = set(['spid', 'ias_url', 'spid_api_key']) + valid_keys = set(['ias_url', 'sgx_key_root']) found_keys = set(config.keys()) missing_keys = valid_keys.difference(found_keys) @@ -143,18 +144,23 @@ def initialize_with_configuration(config) : '{}'.format( ', '.join(sorted(list(missing_keys))))) + try: + spid = Path(os.path.join(config['sgx_key_root'], "sgx_spid.txt")).read_text().strip() + spid_api_key = Path(os.path.join(config['sgx_key_root'], "sgx_spid_api_key.txt")).read_text().strip() + except Exception as e : + raise Exception("Unable to access SGX keys: {}".format(str(e))) + if not _ias: _ias = \ ias_client.IasClient( IasServer = config['ias_url'], - SpidApiKey = config['spid_api_key'], - Spid = config['spid'], - HttpsProxy = config.get('https_proxy', "")) + SpidApiKey = spid_api_key, + Spid = spid) if not _pdo: signed_enclave = __find_enclave_library(config) logger.debug("Attempting to load enclave at: %s", signed_enclave) - _pdo = enclave.pdo_enclave_info(signed_enclave, config['spid']) + _pdo = enclave.pdo_enclave_info(signed_enclave, spid) logger.info("Basename: %s", get_enclave_basename()) logger.info("MRENCLAVE: %s", get_enclave_measurement()) diff --git a/pservice/pdo/pservice/scripts/PServiceCLI.py b/pservice/pdo/pservice/scripts/PServiceCLI.py index 0a1340ba..74f8ede1 100644 --- a/pservice/pdo/pservice/scripts/PServiceCLI.py +++ b/pservice/pdo/pservice/scripts/PServiceCLI.py @@ -446,6 +446,8 @@ def Main() : parser.add_argument('--provisioning-path', help='Directories to search for the enclave data file', type=str, nargs='+') parser.add_argument('--provisioning-data', help='Name of the file containing enclave sealed storage', type=str) + parser.add_argument('--sgx-key-root', help='Path to SGX key root folder', type = str) + options = parser.parse_args() # first process the options necessary to load the default configuration @@ -521,6 +523,18 @@ def Main() : if options.provisioning_path : config['ProvisioningData']['SearchPath'] = options.provisioning_path + # set up the default enclave module configuration (if necessary) + if config.get('EnclaveModule') is None : + config['EnclaveModule'] = { + 'NumberOfEnclaves' : 7, + 'ias_url' : 'https://api.trustedservices.intel.com/sgx/dev', + 'sgx_key_root' : os.environ.get('PDO_SGX_KEY_ROOT', '.') + } + + # override the enclave module configuration (if options are specified) + if options.sgx_key_root : + config['EnclaveModule']['sgx_key_root'] = options.sgx_key_root + # GO! LocalMain(config) diff --git a/pservice/pdo/pservice/utility/ias_client.py b/pservice/pdo/pservice/utility/ias_client.py index 38168934..0e31a84f 100644 --- a/pservice/pdo/pservice/utility/ias_client.py +++ b/pservice/pdo/pservice/utility/ias_client.py @@ -30,10 +30,6 @@ class IasClient(object): def __init__(self, **kwargs): logger.info("IAS settings:") - self._proxies = {} - if "HttpsProxy" in kwargs: - self._proxies["https"] = kwargs["HttpsProxy"] - logger.info("Proxy: " + self._proxies["https"]) if "Spid" in kwargs: self._spid = kwargs["Spid"] logger.info("SPID: " + self._spid) @@ -63,7 +59,7 @@ def get_signature_revocation_lists(self, url = self._ias_url + path + gid[0:8] logger.debug("Fetching SigRL from: %s", url) - result = requests.get(url, proxies=self._proxies, + result = requests.get(url, headers={'Ocp-Apim-Subscription-Key': self._spid_api_key}) if result.status_code != requests.codes.ok: logger.debug("get_signature_revocation_lists HTTP Error code : %d", @@ -88,7 +84,6 @@ def post_verify_attestation(self, quote, manifest=None, nonce=None): logger.debug("Posting attestation verification request to: %s\n", url) result = requests.post(url, json=json, - proxies=self._proxies, headers={'Ocp-Apim-Subscription-Key': self._spid_api_key}, timeout=self._timeout) logger.debug("result headers: %s\n", result.headers) diff --git a/python/pdo/common/config.py b/python/pdo/common/config.py index b60c8088..fb2a24bd 100644 --- a/python/pdo/common/config.py +++ b/python/pdo/common/config.py @@ -187,8 +187,6 @@ def build_configuration_map(**kwargs) : # these are effectively required by common-config, but clients dont # need them and we should be able to set reasonable defaults - SPID = os.environ.get("PDO_SPID", "DEADBEEF00000000DEADBEEF00000000") - SPID_API_KEY = os.environ.get("PDO_SPID_API_KEY", "deadbeef00000000deadbeef00000000") SGX_MODE = os.environ.get("SGX_MODE", "SIM") ContractHost = kwargs.get('host') or os.environ.get("PDO_HOSTNAME", os.environ.get("HOSTNAME", "localhost")) @@ -208,8 +206,9 @@ def build_configuration_map(**kwargs) : ContractData = os.path.join(ContractHome, "data") Interpreter = kwargs.get('interpreter') or os.environ.get("PDO_INTERPRETER", "wawaka") LedgerKeyRoot = kwargs.get('ledger_key_root') or os.environ.get("PDO_LEDGER_KEY_ROOT", os.path.join(ContractKeys, "ledger")) - HttpsProxy = os.environ.get("https_proxy", "") EserviceKeyFormat = 'pem' + SgxKeyRoot = os.environ.get('PDO_SGX_KEY_ROOT', ContractKeys) + config_map = { 'data' : ContractData, @@ -227,10 +226,8 @@ def build_configuration_map(**kwargs) : 'ledger_host_name' : LedgerHostName, 'ledger_type': LedgerType, 'ledger_key_root' : LedgerKeyRoot, - 'proxy' : HttpsProxy, 'sgx_mode' : SGX_MODE, - 'spid' : SPID, - 'spid_api_key' : SPID_API_KEY + 'sgx_key_root': SgxKeyRoot } return config_map diff --git a/python/pdo/scripts/ConfigureCLI.py b/python/pdo/scripts/ConfigureCLI.py index ba00c737..6fc4bfd1 100644 --- a/python/pdo/scripts/ConfigureCLI.py +++ b/python/pdo/scripts/ConfigureCLI.py @@ -134,9 +134,6 @@ def configure_services() : for n in range(1, options.count[2]+1) : expand_service(options, 'pservice', 'ProvisioningService', n) - # Generate enclave configuration file - expand_helper(options, 'enclave.toml') - filename = os.path.join(options.output_directory, 'etc', 'site.toml') with open(filename, 'w') as outfile: toml.dump(site_information, outfile) diff --git a/python/pdo/test/contract.py b/python/pdo/test/contract.py index ac57ca69..e81aaf77 100644 --- a/python/pdo/test/contract.py +++ b/python/pdo/test/contract.py @@ -541,7 +541,7 @@ def Main() : config_map = pconfig.build_configuration_map() # parse out the configuration file first - conffiles = [ 'pcontract.toml', 'enclave.toml', 'eservice1.toml' ] + conffiles = [ 'pcontract.toml', 'eservice1.toml' ] confpaths = [ ".", "./etc", config_map['etc'] ] parser = argparse.ArgumentParser() diff --git a/python/pdo/test/request.py b/python/pdo/test/request.py index cab13511..268872ec 100644 --- a/python/pdo/test/request.py +++ b/python/pdo/test/request.py @@ -469,7 +469,7 @@ def Main() : config_map = pconfig.build_configuration_map() # parse out the configuration file first - conffiles = [ 'pcontract.toml', 'enclave.toml', 'eservice1.toml' ] + conffiles = [ 'pcontract.toml', 'eservice1.toml' ] confpaths = [ ".", "./etc", config_map['etc'] ] parser = argparse.ArgumentParser() From 0e9d2d30eeee7186f221ca49e4c1e1342079ab18 Mon Sep 17 00:00:00 2001 From: Bruno Vavala Date: Tue, 9 Apr 2024 01:59:21 +0000 Subject: [PATCH 2/3] Clean up configuration files Remove the expand-config script as it's unused. Remove verify-pre-conf as it is now obsolete. Update common config to remove unused/unecessary variables. Remove the enclave.toml files and other obsolete toml. Update the documentation to remove unused variables. Signed-off-by: Bruno Vavala --- build/__tools__/expand-config | 173 ----------------------------- build/__tools__/verify-pre-conf.sh | 53 --------- build/cmake/Test.cmake | 4 +- build/common-config.sh | 45 +------- build/template/enclave.toml | 35 ------ docs/environment.md | 60 +--------- eservice/etc/sample_eservice.toml | 96 ---------------- eservice/setup.py | 4 +- 8 files changed, 11 insertions(+), 459 deletions(-) delete mode 100755 build/__tools__/expand-config delete mode 100755 build/__tools__/verify-pre-conf.sh delete mode 100644 build/template/enclave.toml delete mode 100644 eservice/etc/sample_eservice.toml diff --git a/build/__tools__/expand-config b/build/__tools__/expand-config deleted file mode 100755 index 34388460..00000000 --- a/build/__tools__/expand-config +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2018 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Return the number of registered endpoints in the exit status -""" - -import os -import socket -import sys -import toml -from string import Template -import re - -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -def expand_expressions(text, variable_map) : - """expand expressions found in a string, an expression is given - in a ${{expr}}. For example, ${{port+5}} will expand to 7005 if - port is set to 7000 in the variable_map. - - :param string text: template text - :param dict variable_map: dictionary of variable bindings - "returns string: text with expressions evaluated. - """ - for item in re.findall(r'\${{(.*)}}', text, re.MULTILINE) : - exp = '${{%s}}' % item - val = str(eval(item, variable_map)) - text = text.replace(exp, val) - - return text - -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -def parse_configuration_file(filename, variable_map) : - """ - Parse a configuration file expanding variable references - using the Python Template library (variables are $var format) - - :param string filename: name of the configuration file - :param dict variable_map: dictionary of expansions to use - :returns dict: dictionary of configuration information - """ - - cpattern = re.compile('##.*$') - - with open(filename) as fp : - lines = fp.readlines() - - text = "" - for line in lines : - text += re.sub(cpattern, '', line) + ' ' - - if variable_map : - text = expand_expressions(text, variable_map) - text = Template(text).safe_substitute(variable_map) - - return toml.loads(text) - - -## ----------------------------------------------------------------- -try : - ContractHome = os.environ["PDO_HOME"] - LedgerURL = os.environ["PDO_LEDGER_URL"] - LedgerType = os.environ["PDO_LEDGER_TYPE"] - SPID = os.environ["PDO_SPID"] - SPID_API_KEY = os.environ["PDO_SPID_API_KEY"] -except KeyError as ke : - print("incomplete configuration, missing definition of {0}".format(str(ke))) - sys.exit(-1) - -#deduce eservice key format based on ledger type -if LedgerType == 'ccf': - EserviceKeyFormat = 'pem' -else: - print("Cannot configure eservice keys. Invalid ledger type, Must be 'ccf'" ) - sys.exit(-1) - -ContractHost = os.environ.get("PDO_HOSTNAME", os.environ.get("HOSTNAME", "localhost")) -ContractHostAddress = socket.gethostbyname(ContractHost) -ContractEtc = os.path.join(ContractHome, "etc") -ContractKeys = os.path.join(ContractHome, "keys") -ContractLogs = os.path.join(ContractHome, "logs") -ContractData = os.path.join(ContractHome, "data") -LedgerKeyRoot = os.environ.get("PDO_LEDGER_KEY_ROOT", os.path.join(ContractEtc, "keys", "ledger")) -HttpsProxy = os.environ.get("https_proxy", "") - -config_map = { - 'data' : ContractData, - 'etc' : ContractEtc, - 'home' : ContractHome, - 'host' : ContractHost, - 'host_address' : ContractHostAddress, - 'keys' : ContractKeys, - 'logs' : ContractLogs, - 'ledger' : LedgerURL, - 'ledger_type': LedgerType, - 'ledger_key_root' : LedgerKeyRoot, - 'eservice_key_format': EserviceKeyFormat, - 'proxy' : HttpsProxy, - 'spid' : SPID, - 'spid_api_key' : SPID_API_KEY -} - -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -def expand_single(options) : - filename = os.path.join(options.template_directory, options.template) - config = parse_configuration_file(filename, config_map) - - filename = os.path.join(options.output_directory, options.file) - with open(filename, 'w') as outfile: - toml.dump(config, outfile) - -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -def expand_multiple(options, n) : - node = options.file_base + str(n) - node_map = config_map.copy() - - node_map['identity'] = node - node_map['_count_'] = n - - filename = os.path.join(options.template_directory, options.template) - config = parse_configuration_file(filename, node_map) - - filename = os.path.join(options.output_directory, node + '.toml') - with open(filename, 'w') as outfile: - toml.dump(config, outfile) - -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -import argparse - -parser = argparse.ArgumentParser(description='Script to generate configuration files from a template') - -parser.add_argument('--template', help='Name of the base configuration file to use', default='template.js') -parser.add_argument('--template-directory', help='Directory in which the template configuration will be found', default='etc/templates') -parser.add_argument('--output-directory', help='Name of the directory where generated configuration files are written', default='etc') -parser.add_argument('--set', help='Specify arbitrary configuration options', nargs=2, action='append') - -subparsers = parser.add_subparsers(dest='command') -expand_parser = subparsers.add_parser('single', help='expand a template into a single file') -expand_parser.add_argument('--file', help='Base for node names', required=True) - -multi_parser = subparsers.add_parser('multiple', help='expand a template into multiple files') -multi_parser.add_argument('--file-base', help='Base for file names', required=True) -multi_parser.add_argument('--count', help='Number of validators to configure', default=9, type=int) - -options = parser.parse_args() - -if options.set : - for (k, v) in options.set : config_map[k] = v - -if options.command == 'multiple' : - for n in range(1, int(options.count)+1) : - expand_multiple(options, n) - -elif options.command == 'single' : - expand_single(options) diff --git a/build/__tools__/verify-pre-conf.sh b/build/__tools__/verify-pre-conf.sh deleted file mode 100755 index c549dce3..00000000 --- a/build/__tools__/verify-pre-conf.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -# Copyright 2019 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# This script performs several tests on the environment to ensure -# that it is set up correctly. It should be run prior to building - -F_VERIFIED=0 - -# ----------------------------------------------------------------- -# ----------------------------------------------------------------- -SCRIPTDIR="$(dirname $(readlink --canonicalize ${BASH_SOURCE}))" -SRCDIR="$(realpath ${SCRIPTDIR}/../..)" - -source ${SRCDIR}/bin/lib/common.sh -check_pdo_build_env - -function warn () { - recho "WARNING: $*" - F_VERIFIED=-1 -} - -# ----------------------------------------------------------------- -# CHECK ENVIRONMENT -# ----------------------------------------------------------------- - -yell --------------- CONFIG AND ENVIRONMENT PRE-CONF CHECK --------------- - -# the SPID should be a 32 byte hex string -if [[ ! "${PDO_SPID}" =~ ^[A-Fa-f0-9]{32}$ ]]; then - warn "PDO_SPID is not defined correctly, should be a a 32-byte hex key" -fi - -if [ "${SGX_MODE}" = "HW" ]; then - # the SPID_API_KEY should be a 32 byte hex string - if [[ ! "${PDO_SPID_API_KEY}" =~ ^[A-Fa-f0-9]{32}$ ]]; then - warn "PDO_SPID_API_KEY is not defined correctly, should be a a 32-byte hex key" - fi -fi - -exit $F_VERIFIED diff --git a/build/cmake/Test.cmake b/build/cmake/Test.cmake index e5b6c332..531d96c1 100644 --- a/build/cmake/Test.cmake +++ b/build/cmake/Test.cmake @@ -34,8 +34,8 @@ SET(PDO_TEST_CONTRACT --logfile ${TEST_LOG_FILE}) # NOTE: we override the default configuration here because clients -# do not have the full configuration files (eservice1.toml and -# enclave.toml) and when running with services these are not required. +# do not have the full configuration file (eservice1.toml) and +# when running with services these are not required. SET(PDO_TEST_CONTRACT_WITH_SERVICES ${PDO_TEST_CONTRACT} --ledger ${TEST_LEDGER} diff --git a/build/common-config.sh b/build/common-config.sh index 44614e6a..eeddb520 100755 --- a/build/common-config.sh +++ b/build/common-config.sh @@ -113,37 +113,11 @@ var_set() { env_val[PDO_SGX_KEY_ROOT]="${PDO_SGX_KEY_ROOT:-${SCRIPTDIR}/keys/sgx_mode_${SGX_MODE,,}}" env_desc[PDO_SGX_KEY_ROOT]=" PDO_SGX_KEY_ROOT is the root directory where SGX & IAS related keys are stored. - The default points to a directory which contains values which are good - enough for SGX simulator mode. However, for SGX HW mode you - should provide your own version, at least for PDO_SPID and PDO_SPID_API_KEY + If SGX_MODE=SIM, the default folder contains mock files that are good for simulation mode. + If SGX_MODE=HW, the default (or custom) folder must be filled with legitimate SGX & IAS keys. " env_key_sort[$i]="PDO_SGX_KEY_ROOT"; i=$i+1; export PDO_SGX_KEY_ROOT=${env_val[PDO_SGX_KEY_ROOT]} - env_val[PDO_ENCLAVE_CODE_SIGN_PEM]="${PDO_ENCLAVE_CODE_SIGN_PEM:-${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem}" - env_desc[PDO_ENCLAVE_CODE_SIGN_PEM]=" - PDO_ENCLAVE_CODE_SIGN_PEM contains the name of the file containing the key - used to sign the enclave. This key must be white-listed with IAS to work for - production-mode/default launch-control. For non-production use, in simulator or HW mode, - the key can generated by the command: - openssl genrsa -3 -out ${PDO_ENCLAVE_CODE_SIGN_PEM} 3072. - The default path points to a key which is generated during built on-demand. - " - env_key_sort[$i]="PDO_ENCLAVE_CODE_SIGN_PEM"; i=$i+1; export PDO_ENCLAVE_CODE_SIGN_PEM=${env_val[PDO_ENCLAVE_CODE_SIGN_PEM]} - - env_val[PDO_SPID]="${PDO_SPID:-$(cat ${PDO_SGX_KEY_ROOT}/sgx_spid.txt)}" - env_desc[PDO_SPID]=" - PDO_SPID is the ID that accompanies the certificate registered - with the Intel Attestation Service. This should be a 32 character - hex string. - " - env_key_sort[$i]="PDO_SPID"; i=$i+1; export PDO_SPID=${env_val[PDO_SPID]} - - env_val[PDO_SPID_API_KEY]="${PDO_SPID_API_KEY:-$(cat ${PDO_SGX_KEY_ROOT}/sgx_spid_api_key.txt)}" - env_desc[PDO_SPID_API_KEY]=" - PDO_SPID_API_KEY is API-key associated with the SPID. - " - env_key_sort[$i]="PDO_SPID_API_KEY"; i=$i+1; export PDO_SPID_API_KEY=${env_val[PDO_SPID_API_KEY]} - env_val[PDO_LEDGER_KEY_ROOT]="${PDO_LEDGER_KEY_ROOT:-${PDO_INSTALL_ROOT}/opt/pdo/etc/keys/ledger}" env_desc[PDO_LEDGER_KEY_ROOT]=" PDO_LEDGER_KEY_ROOT is the root directory where the system keys are stored @@ -173,7 +147,7 @@ print_export() { } help() { - echo 'common-config.sh -[--reset-keys|-r] [--evalable-export|-e] [--help|-h|-?] + echo 'common-config.sh [--evalable-export|-e] [--help|-h|-?] This script can be used to set the environment variables that are used in the build, installation & execution process. While the build should @@ -200,9 +174,6 @@ and before buidling it you call script as If passed the parameter --evalable-export it will return a list of export commands of the variables instead of directly exporting them to the environment. -Passing parameter --reset-keys will unset keying variables -PDO_ENCLAVE_CODE_SIGN_PEM, -PDO_SPID and PDO_SPID_API_KEY before setting variables. The list of variables set (in order they are defined, their defaults and semantics is as follows: @@ -222,16 +193,6 @@ while [[ $# > 0 ]] do opt=$1 case $opt in - --reset-keys|-r) - # ----------------------------------------------------------------- - # if you change either PDO_SGX_KEY_ROOT or PDO_LEDGER_KEY_ROOT variable - # and re-source this file you should unset all of the variables that - # depend on those variables - # ----------------------------------------------------------------- - unset PDO_ENCLAVE_CODE_SIGN_PEM - unset PDO_SPID - unset PDO_SPID_API_KEY - ;; --evalable-export|-e) is_sourced=0 ;; diff --git a/build/template/enclave.toml b/build/template/enclave.toml deleted file mode 100644 index 11b7aaa7..00000000 --- a/build/template/enclave.toml +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2018 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -------------------------------------------------- -# EnclaveModule -- configuration of the SGX contract enclave -# -------------------------------------------------- -[EnclaveModule] - -# Number of available enclave workers to service requests -num_of_enclaves = '7' - -# spid is a 32-digit hex string tied to the enclave implementation -spid = '${spid}' - -# ias_url is the URL of the Intel Attestation Service (IAS) server. The -# example server is for debug enclaves only, -# the production url is without the trailing '/dev' -ias_url = 'https://api.trustedservices.intel.com/sgx/dev' - -# proxy configuration .. -https_proxy = '${proxy}' - -# spid_api_key is a 32-digit hex string tied to the SPID -spid_api_key = '${spid_api_key}' diff --git a/docs/environment.md b/docs/environment.md index 783c51fd..3e652f14 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -49,10 +49,6 @@ If passed the parameter `--evalable-export` the script will return a list of export commands of the variables instead of directly exporting them to the environment. -Passing parameter `--reset-keys` will unset key variables -`PDO_ENCLAVE_CODE_SIGN_PEM`, -`PDO_SPID` and `PDO_SPID_API_KEY` before setting variables. - ## Generic Environment Variables @@ -143,58 +139,12 @@ run in a real SGX enclave. (default: `${PDO_SOURCE_ROOT}/build/keys/sgx_mode_${SGX_MODE,,}/`): `PDO_SGX_KEY_ROOT` is the root directory where SGX and IAS related keys -are stored. The default points to a directory which contains values -which are good enough for SGX simulator mode. However, for SGX HW mode -you should provide your own version, at least for `PDO_SPID` and -`PDO_SPID_API_KEY`. See [SGX section](install.md#SGX) of the -[BUILD document](install.md) for more information. - - -### `PDO_ENCLAVE_CODE_SIGN_PEM` -(default: `${PDO_SGX_KEY_ROOT}/enclave_code_sign.pem`): +are stored. If SGX_MODE=SIM, the default folder contains mock files that +are good for simulation mode. If SGX_MODE=HW, the default (or custom) +folder must be filled with legitimate SGX & IAS keys. +See [SGX section](install.md#SGX) of the [BUILD document](install.md) +for more information. -`PDO_ENCLAVE_CODE_SIGN_PEM` contains the name of the file containing the -key used to sign the enclave. If you wish to use PDO for production, -this key must be white-listed with IAS. For development, testing, and -other non-production uses, whether in simulator or hardware mode, the -key can generated by the command: - -```bash - openssl genrsa -3 -out ${PDO_ENCLAVE_CODE_SIGN_PEM} 3072. -``` - -The default path points to a key which is automatically generated during -the build. - - -### `PDO_SPID` -(default: `DEADBEEF00000000DEADBEEF00000000`) - -`PDO_SPID` is the ID that accompanies the certificate registered with -the Intel Attestation Service. This should be a 32 character hex -string. If the variable is unset, the configuration script -`common-config.sh` will pull the value from the file -`${PDO_SGX_KEY_ROOT}/sgx_spid.txt`. - -The default value will work for SGX simulation mode. See -[SGX section](install.md#SGX) of the [BUILD document](install.md) for -instructions to create the SPID to support SGX hardware mode. - - -### `PDO_SPID_API_KEY` -(default `deadbeef00000000deadbeef00000000`) - -`PDO_SPID_API_KEY` is the key used to authenticate IAS client -requests. This should be a 32 character hex string. -If the variable is unset, the configuration script -`common-config.sh` will pull the value from the file -`${PDO_SGX_KEY_ROOT}/sgx_spid_api_key.txt`. - -The default value will work for SGX simulation mode. See -[SGX section](install.md#SGX) of the [BUILD document](install.md) for -instructions to create the API key to support SGX hardware mode. - - ## Ledger Environment Variables diff --git a/eservice/etc/sample_eservice.toml b/eservice/etc/sample_eservice.toml deleted file mode 100644 index 2b772af7..00000000 --- a/eservice/etc/sample_eservice.toml +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2018 Intel Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -------------------------------------------------- -# EnclaveService -- general information about the enclave service -# -------------------------------------------------- -[EnclaveService] - # Identity is a string used to identify the service in log files -Identity = "${identity}" -HttpPort = 7100 -Host = "localhost" - - # Max number of threads for processing WSGI requests -WorkerThreads = 8 - # Suggested number of threads for processing other requests -ReactorThreads = 8 - -# -------------------------------------------------- -# StorageService -- information about the associated storage service -# -------------------------------------------------- -[StorageService] -URL = "http://localhost:7200" -BlockStore = "${data}/${identity}.mdb" - -# -------------------------------------------------- -# Ledger -- ledger configuration -# -------------------------------------------------- -[Ledger] -# LedgerURL is used to submit the registration transaction should -# the enclave require registration -LedgerType = "${ledger_type}" -LedgerURL = "${ledger}" -Organization = "Widgets R Us" - -# -------------------------------------------------- -# Logging -- configuration of service logging -# -------------------------------------------------- -[Logging] -LogLevel = "INFO" -LogFile = "${logs}/${identity}.log" - -# -------------------------------------------------- -# Keys -- configuration for retrieving service keys -# -------------------------------------------------- -[Key] -# Keys are used to sign the registration transaction -# should it be required -SearchPath = [ ".", "./keys", "${keys}" ] -FileName = "${identity}_private.pem" - -# -------------------------------------------------- -# EnclaveData -- configuration of sealed storage for the enclave -# -------------------------------------------------- -[EnclaveData] -# DataPath is the directory where sealed storage is saved if -# it needs to be created for this enclave -DataPath = "${data}" - -# BaseName is the root of the name used to store data -# about the enclave. A 'enc' extension will be added -BaseName = "${identity}" - -# -------------------------------------------------- -# EnclaveModule -- configuration of the SGX contract enclave -# -------------------------------------------------- -[EnclaveModule] - -# Number of available enclave workers to service requests -num_of_enclaves = '7' - -# block_store_file_name is the path where persistent state data is stored -# This is safe to share between eservice's -block_store_file_name = "${data}/blockstore.mdb" - -# spid is a 32-digit hex string tied to the enclave implementation -spid = 'DEADBEEF00000000DEADBEEF00000000' - -# ias_url is the URL of the Intel Attestation Service (IAS) server. The -# example server is for debug enclaves only, -# the production url is without the trailing '/dev' -ias_url = 'https://api.trustedservices.intel.com/sgx/dev' -https_proxy = '' - -# spid_api_key is a 32-digit hex string tied to the SPID -spid_api_key = 'DEADBEEF00000000DEADBEEF00000000' diff --git a/eservice/setup.py b/eservice/setup.py index f9fe59da..9427bf07 100644 --- a/eservice/setup.py +++ b/eservice/setup.py @@ -46,9 +46,7 @@ 'bin/es-start.sh', 'bin/es-stop.sh', 'bin/es-status.sh', ]), (dat_dir, []), - (etc_dir, [ - 'etc/sample_eservice.toml', - ]), + (etc_dir, []), (log_dir, []), (key_dir, []), ('lib', [ os.path.join(script_dir, 'deps/bin/libpdo-enclave.signed.so')]) From 5749e445a4a08018aea7c6afd42b6a26db272ca7 Mon Sep 17 00:00:00 2001 From: Bruno Vavala Date: Tue, 9 Apr 2024 02:01:48 +0000 Subject: [PATCH 3/3] More robust SPID checking inside the enclave and cosmetic updates The enclave only performs length check on the SPID, but it does not check the hex format. Previously this was performed on shell variables. This makes the enclave check more robust. Finally, additional naming updates are pushed to align with current conventions. Signed-off-by: Bruno Vavala --- eservice/pdo/eservice/enclave/enclave/enclave.cpp | 7 +++++++ eservice/pdo/eservice/enclave/enclave_info.cpp | 4 ++-- eservice/pdo/eservice/enclave/enclave_info.h | 2 +- pservice/pdo/pservice/enclave/enclave/enclave.cpp | 7 +++++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/eservice/pdo/eservice/enclave/enclave/enclave.cpp b/eservice/pdo/eservice/enclave/enclave/enclave.cpp index 9e4616a8..a6b9c35b 100644 --- a/eservice/pdo/eservice/enclave/enclave/enclave.cpp +++ b/eservice/pdo/eservice/enclave/enclave/enclave.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "sgx_support.h" @@ -327,10 +328,16 @@ namespace pdo { const HexEncodedString& inSpid ) { + // check SPID length pdo::error::ThrowIf( inSpid.length() != 32, "Invalid SPID length"); + // check SPID format + pdo::error::ThrowIf( + ! std::all_of(inSpid.begin(), inSpid.end(), ::isxdigit), + "Invalid SPID format"); + HexStringToBinary(this->spid.id, sizeof(this->spid.id), inSpid); } // Enclave::SetSpid diff --git a/eservice/pdo/eservice/enclave/enclave_info.cpp b/eservice/pdo/eservice/enclave/enclave_info.cpp index dedccfb7..e3e25f9e 100644 --- a/eservice/pdo/eservice/enclave/enclave_info.cpp +++ b/eservice/pdo/eservice/enclave/enclave_info.cpp @@ -35,7 +35,7 @@ bool is_sgx_simulator() pdo_enclave_info::pdo_enclave_info( const std::string& enclaveModulePath, const std::string& spid, - const int num_of_enclaves + const int numberOfEnclaves ) { SAFE_LOG1(PDO_LOG_INFO, "Initializing SGX PDO enclave"); @@ -44,7 +44,7 @@ pdo_enclave_info::pdo_enclave_info( pdo_err_t ret = pdo::enclave_api::base::Initialize(enclaveModulePath, spid, - num_of_enclaves); + numberOfEnclaves); ThrowPDOError(ret); SAFE_LOG1(PDO_LOG_INFO, "SGX PDO enclave initialized."); diff --git a/eservice/pdo/eservice/enclave/enclave_info.h b/eservice/pdo/eservice/enclave/enclave_info.h index 1143b7d0..ed30e892 100644 --- a/eservice/pdo/eservice/enclave/enclave_info.h +++ b/eservice/pdo/eservice/enclave/enclave_info.h @@ -26,7 +26,7 @@ class pdo_enclave_info pdo_enclave_info( const std::string& enclaveModulePath, const std::string& spid, - const int num_of_enclaves + const int numberOfEnclaves ); virtual ~pdo_enclave_info(); std::string get_epid_group(); diff --git a/pservice/pdo/pservice/enclave/enclave/enclave.cpp b/pservice/pdo/pservice/enclave/enclave/enclave.cpp index 1b594938..ec316fcc 100644 --- a/pservice/pdo/pservice/enclave/enclave/enclave.cpp +++ b/pservice/pdo/pservice/enclave/enclave/enclave.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "sgx_support.h" @@ -250,10 +251,16 @@ namespace pdo { const HexEncodedString& inSpid ) { + // check SPID length pdo::error::ThrowIf( inSpid.length() != 32, "Invalid SPID length"); + // check SPID format + pdo::error::ThrowIf( + ! std::all_of(inSpid.begin(), inSpid.end(), ::isxdigit), + "Invalid SPID format"); + HexStringToBinary(this->spid.id, sizeof(this->spid.id), inSpid); } // Enclave::SetSpid