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__/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-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/__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/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/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/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/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/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/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/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/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/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/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')]) 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/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 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()