Skip to content

Commit

Permalink
DONTMERGE [tools/sgx] Interoperable RA-TLS
Browse files Browse the repository at this point in the history
Interoperable RA-TLS is a spec that allows different RA-TLS
implementations (from different SGX frameworks, e.g. Gramine and Occlum)
to interoperate and recognize each others' SGX evidence (SGX quotes and
attached SGX claims). For example, Gramine app enclave can establish a
TLS connection with an Occlum app enclave and verify its SGX evidence.

The spec standardizes the OID extension for X.509 certs that is used for
the SGX evidence. It also standardizes the format of the OID contents: a
CBOR-formatted tag with an array that contains the SGX quote and a dict
of related claims (with the most important dict item being the public
key hash encoded as a CBOR array `hash-entry`).

Current RA-TLS implementation creates X.509 certs that have both the old
(legacy) OID with plain SGX quote as well as the new (standardized) OID
with the CBOR-formatted SGX evidence. Thus, backward compatibility is
preserved at a small cost of larger-sized certs.

Signed-off-by: Dmitrii Kuvaiskii <[email protected]>
  • Loading branch information
Dmitrii Kuvaiskii committed Jan 13, 2023
1 parent 67b1b9f commit af400b3
Show file tree
Hide file tree
Showing 17 changed files with 801 additions and 61 deletions.
1 change: 1 addition & 0 deletions .ci/ubuntu18.04.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \
bison \
build-essential \
cargo \
cmake \
curl \
flex \
gawk \
Expand Down
1 change: 1 addition & 0 deletions .ci/ubuntu20.04.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential \
cargo \
clang \
cmake \
curl \
flex \
gawk \
Expand Down
45 changes: 31 additions & 14 deletions CI-Examples/ra-tls-mbedtls/src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,25 +184,42 @@ int main(int argc, char** argv) {
return 1;
}

/* user asks to maliciously modify the embedded SGX quote (for testing purposes) */
/* user asks to maliciously modify the embedded SGX quote (for testing purposes); we
* have two quotes currently (with legacy OID and with standard TCG DICE OID), so we
* modify them both */
mbedtls_printf(" . Maliciously modifying SGX quote embedded in RA-TLS cert...");
fflush(stdout);

uint8_t oid[] = {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF8, 0x4D, 0x8A, 0x39, 0x06};
uint8_t* p = memmem(srvcert.v3_ext.p, srvcert.v3_ext.len, oid, sizeof(oid));
if (!p) {
mbedtls_printf(" failed\n ! No embedded SGX quote found\n\n");
goto exit;
uint8_t legacy_oid[] = {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF8, 0x4D, 0x8A, 0x39,
0x06};
uint8_t standard_oid[] = { 0x06, 0x06, 0x67, 0x81, 0x05, 0x05, 0x04, 0x09 };
struct {
uint8_t* oid;
size_t size;
size_t offset;
} oids[2] = {
{ .oid = legacy_oid, .size = sizeof(legacy_oid), .offset = 5},
{ .oid = standard_oid, .size = sizeof(standard_oid), .offset = 10},
};

for (size_t i = 0; i < 2; i++) {
uint8_t* p = memmem(srvcert.v3_ext.p, srvcert.v3_ext.len, oids[i].oid,
oids[i].size);
if (!p) {
mbedtls_printf(" failed\n ! No embedded SGX quote found\n\n");
goto exit;
}

p += oids[i].size;
p += oids[i].offset; /* jump somewhere in the middle of the SGX quote */
if (p + sizeof(MALICIOUS_STR) > srvcert.v3_ext.p + srvcert.v3_ext.len) {
mbedtls_printf(" failed\n ! Size of embedded SGX quote is too small\n\n");
goto exit;
}

memcpy(p, MALICIOUS_STR, sizeof(MALICIOUS_STR));
}

p += sizeof(oid);
p += 5; /* jump somewhere in the middle of the SGX quote */
if (p + sizeof(MALICIOUS_STR) > srvcert.v3_ext.p + srvcert.v3_ext.len) {
mbedtls_printf(" failed\n ! Size of embedded SGX quote is too small\n\n");
goto exit;
}

memcpy(p, MALICIOUS_STR, sizeof(MALICIOUS_STR));
mbedtls_printf(" ok\n");
}
} else {
Expand Down
44 changes: 34 additions & 10 deletions Documentation/attestation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -248,21 +248,45 @@ information (SGX quote). The additional information allows the remote user
(verifier) of the certificate to verify that it is indeed communicating with an
SGX enclave (attester).

.. image:: ./img/ratls.svg
:target: ./img/ratls.svg
:alt: Figure: The X.509 certificate generated by RA-TLS
.. image:: ./img/ratls-interoperable.svg
:target: ./img/ratls-interoperable.svg
:alt: Figure: The X.509 certificate generated by RA-TLS (standardized)

The diagram above shows the standard X.509 certificate generated by RA-TLS (the
diagram shows the DCAP based RA-TLS certificate, but the EPID based RA-TLS
certificate is conceptually similar). This certificate is self-signed because
the actual chain of trust is stored in the Intel SGX certificates embedded in
the SGX quote. The most important concept behind the RA-TLS certificate is that
it embeds the SGX quote (in one of the unused X.509 extension fields), which in
turn embeds the SGX report and the complete Intel SGX certificate chain.
Therefore, the RA-TLS certificate contains all the SGX-relevant information.
Also, notice how the SGX report's REPORTDATA field contains the secure hash of
the ephemeral public key generated by the enclavized application -- this is how
this RA-TLS certificate is tied to the enclavized application that generated it.
the SGX quote.

The most important concept behind the RA-TLS certificate is that it embeds the
SGX quote (in the standardized X.509 extension field with the TCG DICE "tagged
evidence" OID), which in turn embeds the SGX report and the complete Intel SGX
certificate chain. In addition to the SGX quote, the certificate also contains
the so-called evidence claims, with the most important one being the "pubkey"
claim that contains the ephemeral public key (in DER format) generated by the
enclavized application. For reasons of standardization, the OID object and all
its sub-objects are encoded in the CBOR data format.

Notice how the SGX report's REPORTDATA field contains the secure hash of the
complete claims buffer. This is how the RA-TLS certificate is tied to the
enclavized application that generated it (through the claims buffer that
contains the enclave-generated public key). In the end, the RA-TLS certificate
contains all the SGX-relevant information.

.. image:: ./img/ratls.svg
:target: ./img/ratls.svg
:alt: Figure: The X.509 certificate generated by RA-TLS (legacy)

The diagram above shows the non-standard X.509 certificate generated by RA-TLS.
This format, with a non-standard X.509 extension field (and a dummy OID), was
developed prior to the "Interoperable RA-TLS" specification, and is deprecated.
One can see that the non-standard OID directly embeds the SGX quote, doesn't
have the concept of claims and doesn't use the CBOR data format.

Gramine generates RA-TLS certificates that contain both the new standard OID and
the legacy non-standard OID, for backward compatibility. In the future, legacy
OID will be dropped, and only the new standard OID will be put in the X.509
certificates generated by Gramine.

RA-TLS is shipped as three libraries: ``ra_tls_attest.so``, EPID based
``ra_tls_verify_epid.so`` and DCAP/ECDSA based ``ra_tls_verify_dcap.so``.
Expand Down
2 changes: 1 addition & 1 deletion Documentation/devel/building.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ running, and Intel SGX SDK/PSW/DCAP must be installed.
""""""""""""""""""""
Run the following commands on Ubuntu to install SGX-related dependencies::

sudo apt-get install -y libprotobuf-c-dev protobuf-c-compiler \
sudo apt-get install -y cmake libprotobuf-c-dev protobuf-c-compiler \
protobuf-compiler python3-cryptography python3-pip python3-protobuf

2. Install Linux kernel with patched FSGSBASE
Expand Down
1 change: 1 addition & 0 deletions Documentation/img/ratls-interoperable.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ if sgx

protobuf_dep = dependency('libprotobuf-c')

libcbor_dep = subproject('libcbor-0.9.0').get_variable('libcbor_dep')

if dcap
sgx_dcap_quoteverify_dep = cc.find_library('sgx_dcap_quoteverify')
endif
Expand Down
1 change: 1 addition & 0 deletions subprojects/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/curl-*/
/gcc-*/
/glibc-*/
/libcbor-*/
/mbedtls-*/
/musl-*/
/tomlc99-*/
Expand Down
7 changes: 7 additions & 0 deletions subprojects/libcbor-0.9.0.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[wrap-file]
directory = libcbor-0.9.0
source_url = https://github.com/PJK/libcbor/archive/refs/tags/v0.9.0.tar.gz
source_fallback_url = https://packages.gramineproject.io/distfiles/libcbor-v0.9.0.tar.gz
source_filename = libcbor-0.9.0.tar.gz
source_hash = da81e4f9333e0086d4e2745183c7052f04ecc4dbcffcf910029df24f103c15d1
patch_directory = libcbor
44 changes: 44 additions & 0 deletions subprojects/packagefiles/libcbor/compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/sh

set -e

log() {
echo "libcbor (static): $*"
}

CURRENT_SOURCE_DIR="$1"
CURRENT_BUILD_DIR="$2"
PRIVATE_DIR="$3"

BUILD_LOG=$(realpath "$CURRENT_BUILD_DIR/libcbor-build.log")
rm -f "$BUILD_LOG"

log "see $BUILD_LOG for full build log"

log "preparing sources..."

rm -rf "$PRIVATE_DIR"
cp -ar "$CURRENT_SOURCE_DIR" "$PRIVATE_DIR"

(
cd "$PRIVATE_DIR"

log "running cmake..."
cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_INSTALL_PREFIX="$CURRENT_BUILD_DIR" \
. >>"$BUILD_LOG" 2>&1

log "running make..."
make -j"$(nproc)" >>"$BUILD_LOG" 2>&1
make install >>"$BUILD_LOG" 2>&1
)

cp -ar "$CURRENT_BUILD_DIR"/include/. "$CURRENT_BUILD_DIR"
cp -ar "$CURRENT_BUILD_DIR"/lib/. "$CURRENT_BUILD_DIR"

log "ls -la $CURRENT_BUILD_DIR"
ls -la $CURRENT_BUILD_DIR

log "done"
37 changes: 37 additions & 0 deletions subprojects/packagefiles/libcbor/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
project('libcbor', 'c', version: '0.9.0')

fs = import('fs')

# NOTE: This is custom_target, because CMake integration in Meson doesn't work correctly with PIC
# static libraries, see https://github.com/mesonbuild/meson/issues/10764.
libcbor_lib = custom_target('libcbor',
command: [
find_program('compile.sh'),
'@CURRENT_SOURCE_DIR@',
meson.current_build_dir(),
'@PRIVATE_DIR@',
],

input: 'CMakeLists.txt',
output: [
'libcbor.a',
'cbor.h',
],

console: true,
install: false,
)

# We can't use `include_directories('include')` because the `include/` dir is generated in the
# custom target above, but Meson checks for existence of the dir *before* running the target
libcbor_inc = include_directories('.')

libcbor_dep = declare_dependency(
link_with: libcbor_lib[0],
# HACK: Use the generated "cbor.h" file and propagate it as part of the RA-TLS build dependency
# to enforce compile order, i.e., to make sure libcbor headers are ready before RA-TLS sources
# start compiling.
sources: libcbor_lib[1],
include_directories: libcbor_inc,
compile_args: '-Wno-strict-prototypes',
)
21 changes: 14 additions & 7 deletions tools/sgx/ra-tls/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ libra_tls_attest = shared_library('ra_tls_attest',
c_args: ra_tls_args,
include_directories: pal_sgx_inc, # this is only for `sgx_arch.h` and `sgx_attest.h`
dependencies: [
libcbor_dep,
mbedtls_static_dep,
],
install: true,
Expand All @@ -31,8 +32,9 @@ libra_tls_verify_epid = shared_library('ra_tls_verify_epid',
c_args: ra_tls_args,
include_directories: pal_sgx_inc,
dependencies: [
sgx_util_dep,
libcbor_dep,
mbedtls_static_dep,
sgx_util_dep,
],
install: true,
install_rpath: join_paths(get_option('prefix'), get_option('libdir')),
Expand All @@ -52,6 +54,7 @@ libsecret_prov_attest = shared_library('secret_prov_attest',
c_args: ra_tls_args,
include_directories: pal_sgx_inc,
dependencies: [
libcbor_dep,
mbedtls_static_dep,
sgx_util_dep,
],
Expand All @@ -74,9 +77,10 @@ libsecret_prov_verify_epid = shared_library('secret_prov_verify_epid',
c_args: ra_tls_args,
include_directories: pal_sgx_inc,
dependencies: [
threads_dep,
sgx_util_dep,
libcbor_dep,
mbedtls_static_dep,
sgx_util_dep,
threads_dep,
],
install: true,
install_rpath: join_paths(get_option('prefix'), get_option('libdir')),
Expand All @@ -95,9 +99,10 @@ if dcap
c_args: ra_tls_args,
include_directories: pal_sgx_inc,
dependencies: [
libcbor_dep,
mbedtls_static_dep,
sgx_dcap_quoteverify_dep,
sgx_util_dep,
mbedtls_static_dep,
],
install: true,
install_rpath: join_paths(get_option('prefix'), get_option('libdir')),
Expand All @@ -116,9 +121,10 @@ if dcap
c_args: ra_tls_args,
include_directories: pal_sgx_inc,
dependencies: [
libcbor_dep,
mbedtls_static_dep,
sgx_dcap_quoteverify_dep,
sgx_util_dep,
mbedtls_static_dep,
],
install: true,
install_rpath: join_paths(get_option('prefix'), get_option('libdir')),
Expand All @@ -139,10 +145,11 @@ if dcap
c_args: ra_tls_args,
include_directories: pal_sgx_inc,
dependencies: [
threads_dep,
libcbor_dep,
mbedtls_static_dep,
sgx_dcap_quoteverify_dep,
sgx_util_dep,
mbedtls_static_dep,
threads_dep,
],
install: true,
install_rpath: join_paths(get_option('prefix'), get_option('libdir')),
Expand Down
27 changes: 23 additions & 4 deletions tools/sgx/ra-tls/ra_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,30 @@
#define PUB_KEY_SIZE_MAX 128 /* enough for the only currently supported algo (ECDSA-384) */
#define IAS_REQUEST_NONCE_LEN 32

#define OID(N) \
{ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF8, 0x4D, 0x8A, 0x39, (N) }
static const uint8_t g_quote_oid[] = OID(0x06);
/* below OID is actually wrong: it shouldn't have the first two bytes (0x06 0x09) because they
* represent the ASN.1 Type (6 = OBJECT IDENTIFIER) and ASN.1 Length (9 bytes); we don't modify it
* because it is non-standard anyway and we don't want to break backwards-compatibility */
#define NON_STANDARD_INTEL_SGX_QUOTE_OID \
{ 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF8, 0x4D, 0x8A, 0x39, 0x06 }
static const uint8_t g_quote_oid[] = NON_STANDARD_INTEL_SGX_QUOTE_OID;
static const size_t g_quote_oid_size = sizeof(g_quote_oid);

/* standard TCG DICE "tagged evidence" OID (2.23.133.5.4.9) */
#define TCG_DICE_TAGGED_EVIDENCE_OID { 0x67, 0x81, 0x05, 0x05, 0x04, 0x09 }
#define TCG_DICE_TAGGED_EVIDENCE_OID_RAW { 0x06, 0x06, 0x67, 0x81, 0x05, 0x05, 0x04, 0x09 }
static const uint8_t g_evidence_oid[] = TCG_DICE_TAGGED_EVIDENCE_OID;
static const size_t g_evidence_oid_size = sizeof(g_evidence_oid);
static const uint8_t g_evidence_oid_raw[] = TCG_DICE_TAGGED_EVIDENCE_OID_RAW;
static const size_t g_evidence_oid_raw_size = sizeof(g_evidence_oid_raw);

#define TCG_DICE_TAGGED_EVIDENCE_CBOR_TAG 0x1A75 /* FIXME: proper IANA tag once registered */

/* hash IDs per IANA: https://www.iana.org/assignments/named-information/named-information.xhtml */
#define IANA_NAMED_INFO_HASH_ALG_REGISTRY_RESERVED 0
#define IANA_NAMED_INFO_HASH_ALG_REGISTRY_SHA256 1
#define IANA_NAMED_INFO_HASH_ALG_REGISTRY_SHA384 7
#define IANA_NAMED_INFO_HASH_ALG_REGISTRY_SHA512 8

typedef int (*verify_measurements_cb_t)(const char* mrenclave, const char* mrsigner,
const char* isv_prod_id, const char* isv_svn);

Expand All @@ -49,7 +68,7 @@ __attribute__ ((visibility("hidden")))
int cmp_crt_pk_against_quote_report_data(mbedtls_x509_crt* crt, sgx_quote_t* quote);

__attribute__ ((visibility("hidden")))
int extract_quote_and_verify_pubkey(mbedtls_x509_crt* crt, sgx_quote_t** out_quote,
int extract_quote_and_verify_claims(mbedtls_x509_crt* crt, sgx_quote_t** out_quote,
size_t* out_quote_size);

__attribute__ ((visibility("hidden")))
Expand Down
Loading

0 comments on commit af400b3

Please sign in to comment.