Skip to content
This repository was archived by the owner on Jan 27, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion common/cpp/verify_ias_report/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,22 @@ 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need SGX SDK dependency for untrusted part.? SGX SDK dependency previously was based on the condition if(NOT UNTRUSTED_ONLY).

SET(UNTRUSTED_LIB_NAME uavalon-verify-ias-report)
PROJECT(${UNTRUSTED_LIB_NAME} CXX)

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
################################################################################
Expand Down
45 changes: 41 additions & 4 deletions common/cpp/verify_ias_report/ias_attestation_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,30 @@
* limitations under the License.
*/

#include <string>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <string>

#include <sgx_utils.h>
#include <sgx_quote.h>

#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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change Return to @return

* otherwise false
*/

// Parse JSON serialized IAS report
JsonValue report_parsed(json_parse_string(ias_report.c_str()));
Expand Down Expand Up @@ -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,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add function comments

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change Return to @return

**/
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<sgx_quote_t*>(
quote_bytes.data());
sgx_report_body_t* report_body = &quote_body->report_body;
sgx_measurement_t mr_enclave_from_report = *(&report_body->mr_enclave);
Copy link
Contributor

@manojgop manojgop Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue with above approach is it brings SGX SDK dependency on common/cpp module. So we need to install SGX SDK in client Dockerfile ? All this is done just to extract the mrencalve value from quote.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are using python client for doing to MR enclave check and we are depend on C++ sgx sdk. Is there problem if we bring SGX sdk dependency in common/cpp? Anyway we are using sgx sdk for verifying signature and quote verification. Porting C++ structure to python is not right thing to do. It may lead to inconsistencies. I am not clear on option 2.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of design goals of Avalon is to hide SGX complexities from Avalon clients. If we make Avalon clients install SGX SDK we are moving away from that goal. Sawtooth PoET for example solves this by doing AVR verification at Python layer and it uses the python struct. Another option is used a fixed offset in AVR quote (based on IAS attestation API spec)
Also bringing in SGX SDK dependency on Avalon client just to do MREnclave verification is not necessary.

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;
}
}
}
7 changes: 5 additions & 2 deletions common/cpp/verify_ias_report/ias_attestation_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Original file line number Diff line number Diff line change
Expand Up @@ -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 = \
Expand All @@ -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
23 changes: 23 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We dont need protobuf. please remove

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is required otherwise below dpkg complain while installing packages.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok

make


Expand All @@ -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/

Expand Down
6 changes: 2 additions & 4 deletions examples/apps/generic_client/base_generic_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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")
Expand All @@ -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
Expand Down
18 changes: 17 additions & 1 deletion examples/apps/generic_client/generic_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down