Experimental nix derivation for Intel's SGX SDK.
This a work-in-progress.
Build the image:
$ docker-compose build
Note that this will take some time as this will build the SGX SDK installer
and install it under /usr/src/result
.
You should see something similar to at the end of the build:
$ docker-compose build
...
Installation is successful! The SDK package can be found in /nix/store/rfh0lambk582hmxc9kb9wks7bw1jd4nz-sgx/sgxsdk
Please set the environment variables with below command:
source /nix/store/rfh0lambk582hmxc9kb9wks7bw1jd4nz-sgx/sgxsdk/environment
/nix/store/rfh0lambk582hmxc9kb9wks7bw1jd4nz-sgx
NOTE that The SDK is also under the more convenient path /usr/src/result
.
See this for yourself:
$ docker-compose run --rm nix-sgx-sdk
bash-4.4# ls result/sgxsdk/
SampleCode bin buildenv.mk environment include lib64 licenses pkgconfig sdk_libs uninstall.sh
Source the SGX SDK environment:
bash-4.4# source result/sgxsdk/environment
Let's build and a sign an enclave, for the SampleEnclave
example:
bash-4.4# cd result/sgxsdk/SampleCode/SampleEnclave
In order to use make
we need to go into a nix-shell
session because make
is not installed on the system.
bash-4.4# nix-shell /usr/src/shell.nix
SGX SDK enviroment
Build the signed enclave:
[nix-shell:/usr/src/result/sgxsdk/SampleCode/SampleEnclave]# make enclave.signed.so
GEN => Enclave/Enclave_t.h
CC <= Enclave/Enclave_t.c
CXX <= Enclave/Edger8rSyntax/Arrays.cpp
CXX <= Enclave/Edger8rSyntax/Functions.cpp
CXX <= Enclave/Edger8rSyntax/Pointers.cpp
CXX <= Enclave/Edger8rSyntax/Types.cpp
CXX <= Enclave/Enclave.cpp
CXX <= Enclave/TrustedLibrary/Libc.cpp
CXX <= Enclave/TrustedLibrary/Libcxx.cpp
CXX <= Enclave/TrustedLibrary/Thread.cpp
LINK => enclave.so
<EnclaveConfiguration>
<ProdID>0</ProdID>
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>10</TCSNum>
<TCSPolicy>1</TCSPolicy>
<!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release -->
<DisableDebug>0</DisableDebug>
<MiscSelect>0</MiscSelect>
<MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>
tcs_num 10, tcs_max_num 10, tcs_min_pool 1
The required memory is 4059136B.
The required memory is 0x3df000, 3964 KB.
Succeed.
SIGN => enclave.signed.so
Check the hash of the enclave.so
file:
[nix-shell:/usr/src/result/sgxsdk/SampleCode/SampleEnclave]# sha256sum enclave.so
00c8533ff8e0be9c03fa58b69deac89b8c54af2e48782957562fd2d866112b86 enclave.so
For the signed enclave, one has to follow steps based on Verify Intel(R) Prebuilt AE Reproducibility. A brief example, which checks the "private-key-independent" and "time-independent" metadata is shown below. For a more detailed example see the audit case example.
# check the "private-key-independent" and "time-independent" metadata aka
# "partial metadata"
[nix-shell:/usr/src/result/sgxsdk/SampleCode/SampleEnclave]# $SGX_SDK/bin/x64/sgx_sign dump -enclave enclave.signed.so -dumpfile metadata.txt
Succeed.
[nix-shell:/usr/src/result/sgxsdk/SampleCode/SampleEnclave]# sed -n '/metadata->magic_num/,/metadata->enclave_css.header.module_vendor/p;/metadata->enclave_css.header.header2/,/metadata->enclave_css.header.hw_version/p;/metadata->enclave_css.body.misc_select/,/metadata->enclave_css.body.isv_svn/p;' metadata.txt > partial_metadata.txt
[nix-shell:/usr/src/result/sgxsdk/SampleCode/SampleEnclave]# sha256sum partial_metadata.txt
8f349074773701017b3eeb2e1603df88aff02c31fb3ad51b06a7367ab414f310 partial_metadata.txt
# NOTE that this is not reproducible as the message signed depends on the date. But
# if you try it on the same day (UTC) it should be reproducible. Below it's just an
# an example (2020.12.07).
[nix-shell:/usr/src/result/sgxsdk/SampleCode/SampleEnclave]# sha256sum enclave.signed.so
de2a88e478da28267f077d0631e7f247e08af7966d4c5603e90128ed6915231c enclave.signed.so
Compile and run the local attestation sample in simulation mode:
[nix-shell:/usr/src/result/sgxsdk/SampleCode]# cd LocalAttestation/
[nix-shell:/usr/src/result/sgxsdk/SampleCode/LocalAttestation]# make SGX_MODE=SIM
...
LINK => libenclave_responder.so
<EnclaveConfiguration>
<ProdID>1</ProdID>
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>1</TCSNum>
<TCSPolicy>1</TCSPolicy>
<!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release -->
<DisableDebug>0</DisableDebug>
<MiscSelect>0</MiscSelect>
<MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>
tcs_num 1, tcs_max_num 1, tcs_min_pool 1
The required memory is 1994752B.
The required memory is 0x1e7000, 1948 KB.
Succeed.
SIGN => libenclave_responder.signed.so
make[1]: Leaving directory '/nix/store/rfh0lambk582hmxc9kb9wks7bw1jd4nz-sgx/sgxsdk/SampleCode/LocalAttestation/EnclaveResponder'
make[1]: Entering directory '/nix/store/rfh0lambk582hmxc9kb9wks7bw1jd4nz-sgx/sgxsdk/SampleCode/LocalAttestation/App'
CC <= EnclaveInitiator_u.c
CC <= EnclaveResponder_u.c
CC <= UntrustedEnclaveMessageExchange.cpp
CXX <= App.cpp
GEN => app
make[1]: Leaving directory '/nix/store/rfh0lambk582hmxc9kb9wks7bw1jd4nz-sgx/sgxsdk/SampleCode/LocalAttestation/App'
The project has been built in simulation debug mode.
Run the app:
[nix-shell:/usr/src/result/sgxsdk/SampleCode/LocalAttestation]# cd bin/
[nix-shell:/usr/src/result/sgxsdk/SampleCode/LocalAttestation/bin]# ./app
succeed to load enclaves.
succeed to establish secure channel.
Succeed to exchange secure message...
Succeed to close Session...
[nix-shell:/usr/src/result/sgxsdk/SampleCode/LocalAttestation/bin]# sha256sum app
03325cae23ecb64672ad63b17d406ae0039c8d87e26573ed37b8183ba7991a8d app
The same commands can be used with the other samples.
As an example of reproducing an enclave build, for an application based on
the Rust SGX SDK,
let's build the enclave of the
helloworld
sample.
NOTE: The steps that follow could be simplified and further automated, thus reducing the number of manual steps currently required. Future improvements should make it simpler.
First build the image:
docker-compose build nix-rust-sgx-sdk
Launch a container:
docker-compose run --rm nix-rust-sgx-sdk
Once in the container, start a nix-shell
session:
bash-4.4# nix-shell rust-sgx-sdk.nix
Unpack the Rust SGX SDK source code:
[nix-shell:/usr/src]# unpackPhase
This should output something similar to:
unpacking source archive /nix/store/msvp3cfv2d8h0r9dhb2mqypkhil0nzra-source
source root is source
Go into the directory where the Rust SGX SDK source code has been unpacked:
[nix-shell:/usr/src]# cd source/
Build the enclave:
[nix-shell:/usr/src/source]# buildPhase
The end of the output should be similar to:
...
GEN => enclave/Enclave_t.c enclave/Enclave_t.h app/Enclave_u.c app/Enclave_u.h
CC <= enclave/Enclave_t.c
LINK => enclave/enclave.so
mkdir -p bin
<!-- Please refer to User's Guide for the explanation of each field -->
<EnclaveConfiguration>
<ProdID>0</ProdID>
<ISVSVN>0</ISVSVN>
<StackMaxSize>0x40000</StackMaxSize>
<HeapMaxSize>0x100000</HeapMaxSize>
<TCSNum>1</TCSNum>
<TCSPolicy>1</TCSPolicy>
<DisableDebug>0</DisableDebug>
<MiscSelect>0</MiscSelect>
<MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>
tcs_num 1, tcs_max_num 1, tcs_min_pool 1
The required memory is 1601536B.
The required memory is 0x187000, 1564 KB.
Succeed.
SIGN => bin/enclave.signed.so
This will result in an enclave build under enclave/enclave.so
and a signed
enclave under bin/enclave.signed.so
.
If the "reproducibility" works as it should, then one should obtain the
following sha256 hash for the enclave.so
:
[nix-shell:/usr/src/source/samplecode/helloworld]# sha256sum enclave/enclave.so
1a3290cfff5d805f6963972bd4901990383a9c056149ccd05337d8f131117a88 enclave/enclave.so
For verifying the reproducibility of the signed enclave, we cannot just check
the hash of the enclave.signed.so
as it may have been signed by a private
key that we do not have access to. Moreover, even if we have access to the
private key, the signed message depends on the current date, which makes the
signed build non-reproducible unless one signs it again on the same (UTC) day.
Here's a brief example. See Audit Case: Comparing two signed enclaves for a more complete example, and more explanations.
[nix-shell:/usr/src/source/samplecode/helloworld]# ${SGX_SDK}/bin/x64/sgx_sign dump -enclave bin/enclave.signed.so -dumpfile metadata.txt
Succeed.
[nix-shell:/usr/src/source/samplecode/helloworld]# sed -n '/metadata->magic_num/,/metadata->enclave_css.header.module_vendor/p;/metadata->enclave_css.header.header2/,/metadata->enclave_css.header.hw_version/p;/metadata->enclave_css.body.misc_select/,/metadata->enclave_css.body.isv_svn/p;' metadata.txt > partial_metadata.txt
[nix-shell:/usr/src/source/samplecode/helloworld]# sha256sum partial_metadata.txt
75ed5e722ffeb059f58a6814c14bb88707b7ea103d3bac5704ee3668e284e245 partial_metadata.txt
The above build phase used the private key provided by the sample code to sign
the enclave. This private key is under enclave/Enclave_private.pem
.
To use a different key, one can copy the preferred key to replace
enclave/Enclave_private.pem
, and run buildPhase
, as shown above.
For instance:
cp /usr/src/keys/Developer_private.pem \
/usr/src/source/samplecode/helloworld/enclave/Enclave_private.pem
and proceed with the buildPhase
:
[nix-shell:/usr/src/source]# buildPhase
This section presents a simple approach that may be used for auditing purposes. Given a signed enclave, an auditor wishes to reproduce the enclave build, and verify its integrity. The approach is based on Intel's AE Reproducibility Verification.
After having built and signed the enclave as shown above, one can use
Intel's script reproducibility_verifier.sh
to verify the reproducibility
of a signed enclave, using a different private key to sign the "reproducible"
enclave build.
Make sure you are in helloworld
directory:
cd /usr/src/source/samplecode/helloworld
Run Intel's script, passing the auditor's private key:
/usr/src/reproducibility_verifier.sh \
bin/enclave.signed.so enclave/enclave.so \
/usr/src/keys/Auditor_private.pem \
enclave/Enclave.config.xml
* developer signed AE is: bin/enclave.signed.so
* auditor unsigned AE is: enclave/enclave.so
* auditor private key is: /usr/src/keys/Auditor_private.pem
* developer config.xml is: enclave/Enclave.config.xml
Reproducibility Verification PASSED!
See the section below for more details, on how the check works.
This section is self-contained, and therefore repeats some of the above material.
First build the image:
docker-compose build nix-rust-sgx-sdk
Launch a container:
docker-compose run --rm nix-rust-sgx-sdk
Once in the container, start a nix-shell
session:
bash-4.4# nix-shell rust-sgx-sdk.nix
Unpack the Rust SGX SDK source code:
[nix-shell:/usr/src]# unpackPhase
unpacking source archive /nix/store/msvp3cfv2d8h0r9dhb2mqypkhil0nzra-source
source root is source
Go into the directory where the application sample application is, and build the enclave:
[nix-shell:/usr/src]# cd source/samplecode/helloworld/
[nix-shell:/usr/src/source]# make enclave/enclave.so
Sign the enclave with the "developer" key:
$sgxsdk/sgxsdk/bin/x64/sgx_sign sign \
-key /usr/src/keys/Developer_private.pem \
-enclave enclave/enclave.so \
-out bin/dev.enclave.signed.so \
-config enclave/Enclave.config.xml
Sign the enclave with the auditor key:
$sgxsdk/sgxsdk/bin/x64/sgx_sign sign \
-key /usr/src/keys/Auditor_private.pem \
-enclave enclave/enclave.so \
-out bin/audit.enclave.signed.so \
-config enclave/Enclave.config.xml
Compare the metadata of the signed enclaves, using Intel's suggested approach, in https://github.com/intel/linux-sgx/tree/master/linux/reproducibility/ae_reproducibility_verifier#2-verify-by-manual.
Dump and extract the metadata of each enclave, and compare the extracted metadata.
Extract the metadata of the developer's signed enclave:
# dump metadata
${SGX_SDK}/bin/x64/sgx_sign dump -enclave bin/dev.enclave.signed.so -dumpfile dev_metadata_orig.txt
# extract metadata
sed -n '/metadata->magic_num/,/metadata->enclave_css.header.module_vendor/p;/metadata->enclave_css.header.header2/,/metadata->enclave_css.header.hw_version/p;/metadata->enclave_css.body.misc_select/,/metadata->enclave_css.body.isv_svn/p;' dev_metadata_orig.txt > dev_metadata.txt
Extract the metadata of the enclave signed by the auditor:
# dump metadata
${SGX_SDK}/bin/x64/sgx_sign dump -enclave bin/audit.enclave.signed.so -dumpfile audit_metadata_orig.txt
# extract metadata
sed -n '/metadata->magic_num/,/metadata->enclave_css.header.module_vendor/p;/metadata->enclave_css.header.header2/,/metadata->enclave_css.header.hw_version/p;/metadata->enclave_css.body.misc_select/,/metadata->enclave_css.body.isv_svn/p;' audit_metadata_orig.txt > audit_metadata.txt
Compare the two metadata files:
diff dev_metadata.txt audit_metadata.txt