In a typical Open Enclave application, it's common to see multiple enclaves working together to achieve common goals. They would need to attest each other before a trust could be established. Once an enclave verifies the counterpart is trustworthy, they can exchange information on a protected channel, which typically provides confidentiality, integrity and replay protection. This sample demonstrates how to conduct local attestation between two enclaves on the same system and establish a secure communication channel for exchanging messages between them.
It has the following properties:
- Written in C++
- Demonstrates an implementation of local attestation
- Use of mbedTLS within the enclave
- Use Asymmetric / Public-Key Encryption to establish secure communications between two attesting enclaves
- Enclave APIs used:
- oe_get_report
- oe_verify_report,
- oe_get_target_info
See Remote Attestation's README for information
This sample demonstrates how to attest two enclaves to each other locally by using Open Enclave APIs: oe_get_report
, oe_get_target_info
, and oe_verify_report
. They work together to complete a local attestation process.
To simplify this sample without losing the focus in explaining how the local attestation works, host1 and host2 are combined into one single host to eliminate the need for additional code for inter-process communication between two hosts. Diagram 2 is the configuration used in this sample.
For two enclaves on the same system to locally attest each other, the enclaves need to know each other’s identities. OE SDK provides oe_get_report
, oe_get_target_info
, and oe_verify_report
APIs to help broker the identity retrieval, exchange and validation between two enclaves.
Here are the basic steps of a typical local attestation between two enclaves.
Let's say two enclaves involved are enclave_a and enclave_b.
-
Inside enclave_a, call
oe_get_report
to get enclave_a's report, then calloe_get_target_info
on enclave_a's report to get enclave_a's target info, enclave_a's identity. -
Send enclave_a's identity to enclave_b.
-
Inside enclave_b, create an enclave_b report targeted at enclave_a, that is, a report with enclave_b's identity signed so that enclave_a can verify it.
-
Send the enclave_b report above to enclave_a.
-
Inside enclave_a, call
oe_verify_report
to verify enclave_b report, on success, it means enclave_b was successfully attested to enclave_a.
Step 1-5 completes the process of local attesting enclave_b to enclave_a
Repeating step 1-4 with reverse roles of enclave_a and enclave_b can achieve attesting enclave_a to enclave_b.
The host application coordinates the local attestation steps described above for helping local attestation process.
The host does the following in this sample:
-
Create two enclaves for attesting each other, let's say they are enclave_a and enclave_b
oe_create_localattestation_enclave( enclaveImagePath, OE_ENCLAVE_TYPE_SGX, OE_ENCLAVE_FLAG_DEBUG, NULL, 0, &enclave);
-
Attest enclave 1 to enclave 2
attest_one_enclave_to_the_other("enclave_a", enclave_a, "enclave_b", enclave_b);
-
Attest enclave 2 to enclave 1
attest_one_enclave_to_the_other("enclave_b", enclave_b, "enclave_a", enclave_a);
With successfully attestation on each other, we are ready to securely exchange data between enclaves via asymmetric encryption.
-
Get encrypted message from 1st enclave
generate_encrypted_message(enclave_a, &ret, &encrypted_msg, &encrypted_msg_size);
-
Sending the encrypted message to 2nd enclave to decrypt and validate if the decrypted message is correct.
Note: both enclaves hardcode their sample messages for this validation.
process_encrypted_msg(enclave_b, &ret, encrypted_msg, encrypted_msg_size);
This routine handles the process of attesting enclave_b to enclave_a with the following three steps.
get_target_info(enclave_a, &ret, &target_info_buf, &target_info_size);
get_targeted_report_with_pubkey(enclave_b, &ret,
target_info_buf, target_info_size,
&pem_key, &pem_key_size,
&report, &report_size);
verify_report_and_set_pubkey(enclave_a, &ret,
pem_key,pem_key_size,
report, report_size);
Let's say, we want to attest enclave 2 to enclave 1.
Attesting an enclave consists of three steps:
To conduct a local attestation, both enclaves need to know each other’s identities. This is done by calling oe_get_target_info on the enclave 1's own report.
oe_result_t oe_get_target_info(
const uint8_t* report,
size_t report_size,
void* target_info_buffer,
size_t* target_info_size);
On a successful return, target_info_buffer will be deposited with platform specific identity information needed for local attestation.
Inside enclave 2, call oe_get_report with the target info as opt_params. This creates a enclave_b report that' targeted at enclave 1, that is, for enclave 1 to validate.
oe_result_t oe_get_report(
uint32_t flags,
const uint8_t* report_data,
size_t report_data_size,
const void* opt_params,
size_t opt_params_size,
uint8_t* report_buffer,
size_t* report_buffer_size);
This validation consists two parts:
-
Integrity of the Enclave Report
Enclave 1 can call
oe_verify_report
to validate the report originated from an Trust Execution Environment (TEE), which in this case would be a valid SGX platform.oe_result_t oe_verify_report(const uint8_t* report, size_t report_size, oe_report_t* parsed_report);
At this point, Enclave 1 knows that the report originated from an enclave running in a TEE, and that the information in the report can be trusted.
-
Validation of an enclave identity
Finally, it is up to the enclave app to check that identity and properties of the enclave reflected in the report matches its expectation. Open Enclave exposes a generalized identity model to support this process across TEE types.
oe_identity_t
is the data structure that defined for this identity model.typedef struct _oe_identity { /** Version of the oe_identity_t structure */ uint32_t idVersion; /** Security version of the enclave. For SGX enclaves, this is the * ISVN value */ uint32_t securityVersion; /** Values of the attributes flags for the enclave - * OE_REPORT_ATTRIBUTES_DEBUG: The report is for a debug enclave. * OE_REPORT_ATTRIBUTES_REMOTE: The report can be used for remote * attestation */ uint64_t attributes; /** The unique ID for the enclave. * For SGX enclaves, this is the MRENCLAVE value */ uint8_t uniqueID[OE_UNIQUE_ID_SIZE]; /** The author ID for the enclave. * For SGX enclaves, this is the MRSIGNER value */ uint8_t authorID[OE_AUTHOR_ID_SIZE]; /** The Product ID for the enclave. * For SGX enclaves, this is the ISVPRODID value. */ uint8_t productID[OE_PRODUCT_ID_SIZE]; } oe_identity_t;
As shown in the sample, the set of validations performed on these properties is up to the app.
In general, we would strongly recommend:
- Ensure that the identity of the enclave matches the expected value:
- Verify the
uniqueID
value if you want to match the exact bitwise identity of the enclave. Bear in mind that any patches to the enclave will change the uniqueID in the future. - Verify the
authorID
andproductID
values if you want to match the identity of an enclave that might span multiple binary versions. This is what the attestation sample does. - Ensure that the
securityVersion
of the enclave matches your minimum required security version. - Ensure that the
reportData
matches the hash of the data provided with the report, as illustrated by the sample.
In the sample, the app-specific
Attestation::attest_local_report
method callsoe_parse_report
to obtain anoe_report_t
for report integrity checking before conducting enclave identity validation based on the information insideparsed_report
.
The attestation local_attestation/common/crypto.cpp
file from the sample illustrates how to use mbedTLS inside the enclave for cryptographic operations such as:
- RSA key generation, encryption and decryption
- SHA256 hashing
In general, the Open Enclave SDK provides default support for mbedTLS layered on top of the Open Enclave core runtime with a small integration surface so that it can be switched out by open source developers in the future for your choice of crypto libraries.
See here for supported mbedTLS functions
Note that there are two different build systems supported, one using GNU Make and
pkg-config
, the other using CMake.
This uses the CMake package provided by the Open Enclave SDK.
cd local_attestation
mkdir build && cd build
cmake ..
make run
cd local_attestation
make build
make run