diff --git a/common/cpp/verify_ias_report/CMakeLists.txt b/common/cpp/verify_ias_report/CMakeLists.txt index 189856d1f..a00cb6c32 100644 --- a/common/cpp/verify_ias_report/CMakeLists.txt +++ b/common/cpp/verify_ias_report/CMakeLists.txt @@ -42,6 +42,8 @@ add_custom_command(OUTPUT ${PROJECT_GENERATED_IAS_SOURCES} # Untrusted Verify-Ias-Report Library ################################################################################ +SET(SGX_SDK "$ENV{SGX_SDK}") +SET(SGX_SDK_INCLUDE ${SGX_SDK}/include) SET(UNTRUSTED_LIB_NAME uavalon-verify-ias-report) PROJECT(${UNTRUSTED_LIB_NAME} CXX) @@ -49,12 +51,13 @@ pkg_check_modules (OPENSSL REQUIRED openssl>=1.1.1d) ADD_LIBRARY(${UNTRUSTED_LIB_NAME} STATIC ${PROJECT_HEADERS} ${PROJECT_GENERATED_IAS_SOURCES} ${PROJECT_SOURCES}) -TARGET_INCLUDE_DIRECTORIES(${UNTRUSTED_LIB_NAME} PRIVATE ${COMMON_PRIVATE_INCLUDE_DIRS}) +TARGET_INCLUDE_DIRECTORIES(${UNTRUSTED_LIB_NAME} PRIVATE ${COMMON_PRIVATE_INCLUDE_DIRS} ${SGX_SDK_INCLUDE}) TARGET_COMPILE_OPTIONS(${UNTRUSTED_LIB_NAME} PRIVATE ${COMMON_CXX_FLAGS} ${OPENSSL_CFLAGS}) TARGET_COMPILE_DEFINITIONS(${UNTRUSTED_LIB_NAME} PRIVATE "-D_UNTRUSTED_=1") + ################################################################################ # Trusted Verify-Ias-Report Library ################################################################################ diff --git a/common/cpp/verify_ias_report/ias_attestation_util.cpp b/common/cpp/verify_ias_report/ias_attestation_util.cpp index 61e95183e..bddfa9010 100644 --- a/common/cpp/verify_ias_report/ias_attestation_util.cpp +++ b/common/cpp/verify_ias_report/ias_attestation_util.cpp @@ -13,20 +13,30 @@ * limitations under the License. */ -#include #include -#include #include +#include + +#include +#include #include "ias_attestation_util.h" #include "verify-report.h" #include "tcf_error.h" #include "parson.h" #include "jsonvalue.h" +#include "types.h" bool verify_ias_report_signature(const std::string& signing_cert_pem, - const std::string& ias_report, - const std::string& ias_signature) { + const std::string& ias_report, + const std::string& ias_signature) { + /* Verify IAS report signature + * @param signing_cert_pem signing certificate + * @param ias_report attestion report + * @param ias_signature attestation report signature + * Returns true if signature verification success + * otherwise false + */ // Parse JSON serialized IAS report JsonValue report_parsed(json_parse_string(ias_report.c_str())); @@ -54,3 +64,30 @@ bool verify_quote(const std::string& ias_report, int group_out_of_date_is_ok) { return quote_status; } +bool verify_mr_enclave_value(const std::string& enclave_quote_body, + const std::string& mr_enclave) { + /* Verify MR enclave in the attestation + * report and compare with the value passed + * @param enclave_quote_body Enclave quote body + * @param mr_enclave MR enclave value in hex format + * Return true if comparision matches otherwise false + **/ + if (mr_enclave.size() != 0) { + /* Extract ReportData and MR_ENCLAVE from isvEnclaveQuoteBody + present in Verification Report */ + ByteArray quote_bytes = Base64EncodedStringToByteArray( + enclave_quote_body.c_str()); + sgx_quote_t* quote_body = reinterpret_cast( + quote_bytes.data()); + sgx_report_body_t* report_body = "e_body->report_body; + sgx_measurement_t mr_enclave_from_report = *(&report_body->mr_enclave); + ByteArray mr_enclave_bytes = HexEncodedStringToByteArray(mr_enclave); + if (memcmp(mr_enclave_from_report.m, mr_enclave_bytes.data(), + SGX_HASH_SIZE) == 0) { + return true; + } + else { + return false; + } + } +} diff --git a/common/cpp/verify_ias_report/ias_attestation_util.h b/common/cpp/verify_ias_report/ias_attestation_util.h index 8fc203fde..4cf873307 100644 --- a/common/cpp/verify_ias_report/ias_attestation_util.h +++ b/common/cpp/verify_ias_report/ias_attestation_util.h @@ -17,9 +17,12 @@ // Verifies signature of the message by extracting public key from certificate bool verify_ias_report_signature(const std::string& ias_attestation_signing_cert_pem, - const std::string& ias_report, - const std::string& ias_signature); + const std::string& ias_report, + const std::string& ias_signature); // Verifies certificate against IAS CA certificate bool verify_quote(const std::string& ias_report, int group_out_of_date_is_ok); +// Verify MR enclave value +bool verify_mr_enclave_value(const std::string& ias_report, + const std::string& mr_enclave); diff --git a/common/verify_report_utils/verify_report/verify_attestation_report.py b/common/verify_report_utils/verify_report/verify_attestation_report.py index dd3776b57..6f7c6a0ca 100644 --- a/common/verify_report_utils/verify_report/verify_attestation_report.py +++ b/common/verify_report_utils/verify_report/verify_attestation_report.py @@ -20,9 +20,10 @@ logger = logging.getLogger(__name__) -def verify_attestation_report(enclave_info): +def verify_attestation_report(enclave_info, mr_enclave=""): ''' Function to verify quote status, signature of IAS attestation report + and verify MR enclave value ''' verification_report = \ @@ -47,4 +48,17 @@ def verify_attestation_report(enclave_info): logger.error("Enclave IAS report signature verification failed") return report_sig_status logger.info("Enclave IAS report signature verification passed") + + if mr_enclave != "": + v_report = json.loads( + enclave_info["proof_data"]["verification_report"]) + mr_check = verify_report_util.verify_mr_enclave_value( + v_report["isvEnclaveQuoteBody"], + mr_enclave) + if mr_check is False: + logger.error("MR enclave value check failed") + return mr_check + else: + logger.info("MR enclave value check passed") + return True diff --git a/docker/Dockerfile b/docker/Dockerfile index 88773f0b3..346af6f1a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -102,7 +102,9 @@ FROM ubuntu:bionic as common_cpp_image RUN apt-get update \ && apt-get install -y -q \ pkg-config \ + wget \ cmake \ + libprotobuf-dev \ make @@ -112,6 +114,27 @@ COPY --from=openssl_image /usr/local/bin /usr/local/bin COPY --from=openssl_image /usr/local/include /usr/local/include COPY --from=openssl_image /usr/local/lib /usr/local/lib +# Intel SGX common library and SDK are installed in /opt/intel directory. +# Installation of Intel SGX libsgx-common packages requires +# /etc/init directory. In the Docker image this directory doesn't exist. +# Hence creating /etc/init directory. +RUN mkdir -p /opt/intel \ + && mkdir -p /etc/init +WORKDIR /opt/intel + +# Install Intel SGX common library +RUN wget https://download.01.org/intel-sgx/sgx-linux/2.7.1/distro/ubuntu18.04-server/libsgx-enclave-common_2.7.101.3-bionic1_amd64.deb \ + && dpkg -i libsgx-enclave-common_2.7.101.3-bionic1_amd64.deb + +# Install Intel SGX SDK +RUN SGX_SDK_FILE=sgx_linux_x64_sdk_2.7.101.3.bin \ + && wget --no-check-certificate https://download.01.org/intel-sgx/sgx-linux/2.7.1/distro/ubuntu18.04-server/$SGX_SDK_FILE \ + && echo "yes" | bash ./$SGX_SDK_FILE \ + && rm $SGX_SDK_FILE \ + && echo ". /opt/intel/sgxsdk/environment" >> /etc/environment + +ENV SGX_SDK=/opt/intel/sgxsdk + RUN ldconfig \ && ln -s /etc/ssl/certs/* /usr/local/ssl/certs/ diff --git a/examples/apps/generic_client/base_generic_client.py b/examples/apps/generic_client/base_generic_client.py index 2d07a091a..94ff44bb9 100644 --- a/examples/apps/generic_client/base_generic_client.py +++ b/examples/apps/generic_client/base_generic_client.py @@ -40,7 +40,7 @@ def __init__(self): self._work_order_instance = None self._work_order_receipt_instance = None - def do_worker_verification(self, worker_obj): + def do_worker_verification(self, worker_obj, mr_enclave): """ Do worker verification on proof data if it exists Proof data exists in SGX hardware mode. @@ -60,8 +60,6 @@ def do_worker_verification(self, worker_obj): "Failed to verify worker encryption key signature") return False - # TODO Need to do verify MRENCLAVE value - # in the attestation report if not worker_obj.proof_data: logging.info("Proof data is empty. " + "Skipping verification of attestation report") @@ -76,7 +74,7 @@ def do_worker_verification(self, worker_obj): logging.info("Perform verification of attestation report") verify_report_status = attestation_util.verify_attestation_report( - enclave_info) + enclave_info, mr_enclave) if verify_report_status is False: logging.error("Verification of enclave sign-up info failed") return False diff --git a/examples/apps/generic_client/generic_client.py b/examples/apps/generic_client/generic_client.py index 264a6991a..b03a65a94 100755 --- a/examples/apps/generic_client/generic_client.py +++ b/examples/apps/generic_client/generic_client.py @@ -110,6 +110,12 @@ def __init__(self, args): # requester signature for work order requests self._requester_signature = options.requester_signature + # MR enclave value + if options.mr_enclave is None: + self._mr_enclave = "" + else: + self._mr_enclave = options.mr_enclave + logging.info("******* Hyperledger Avalon Generic client *******") # mode should be one of listing or registry (default) @@ -182,6 +188,10 @@ def _parse_command_line(self, args): "-rs", "--requester_signature", help="Enable requester signature for work order requests", action="store_true") + parser.add_argument( + "-mr", "--mr_enclave", + help='mr enclave value', + type=str) options = parser.parse_args(args) return options @@ -238,6 +248,9 @@ def uri(self): def mode(self): return self._mode + def mr_enclave(self): + return self._mr_enclave + def Main(args=None): parser = GenericClient(args) @@ -279,7 +292,10 @@ def Main(args=None): session_iv = crypto_utility.generate_iv() # Do worker verification - generic_client_obj.do_worker_verification(worker_obj) + status = generic_client_obj.do_worker_verification(worker_obj, + parser.mr_enclave()) + if status is False: + sys.exit(-1) logging.info("**********Worker details Updated with Worker ID" + "*********\n%s\n", worker_id)