Skip to content

Commit

Permalink
[tools/sgx] Modify RA-TLS to adhere to Interoperable RA-TLS standard
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 `pubkey-hash`).

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 Aug 6, 2024
1 parent 67a00de commit 7d589f8
Show file tree
Hide file tree
Showing 22 changed files with 885 additions and 60 deletions.
1 change: 1 addition & 0 deletions .ci/ubuntu20.04.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential \
cargo \
clang \
cmake \
curl \
flex \
gawk \
Expand Down
1 change: 1 addition & 0 deletions .ci/ubuntu22.04.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ RUN apt-get update && apt-get satisfy -y \
RUN apt-get update && apt-get install -y \
cargo \
clang \
cmake \
cpio \
dwarves \
g++-12 \
Expand Down
1 change: 1 addition & 0 deletions .ci/ubuntu24.04.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ RUN apt-get update && apt-get satisfy -y \
# nginx: CI-Examples/ra-tls-nginx
# shellcheck: .ci/run-shellcheck
RUN apt-get update && apt-get install -y \
cmake \
git \
libunwind8 \
nginx \
Expand Down
44 changes: 30 additions & 14 deletions CI-Examples/ra-tls-mbedtls/src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,25 +193,41 @@ 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 both of them */
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[] = NON_STANDARD_INTEL_SGX_QUOTE_OID;
uint8_t standard_oid[] = TCG_DICE_TAGGED_EVIDENCE_OID_RAW;
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
45 changes: 35 additions & 10 deletions Documentation/attestation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -242,21 +242,46 @@ 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 evidence claims, with the most important one being the "pubkey-hash" claim
that contains the hash of 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 hash of 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 legacy
non-standard OID), was developed prior to the "Interoperable RA-TLS"
specification, and is deprecated. One can see that this old X.509 certificate
format 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 available 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 @@ -87,7 +87,7 @@ If your current kernel version is lower than 5.11, then you have two options:
""""""""""""""""""""
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 Intel SGX SDK/PSW
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.
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Maintainer: Wojtek Porczyk <[email protected]>
Build-Depends: debhelper-compat (= 13),
autoconf,
bison,
cmake,
jq,
gawk,
libcurl4-openssl-dev (>= 7.58),
Expand Down
1 change: 1 addition & 0 deletions gramine.spec
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ BuildArch: x86_64
Source0: %{name}-%{version}.tar.gz

BuildRequires: bison
BuildRequires: cmake
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: jq
Expand Down
6 changes: 6 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ mbedtls_pal_dep = mbedtls_proj.get_variable('mbedtls_pal_dep')

curl_proj = subproject('curl-8.8.0')
cjson_proj = subproject('cJSON-1.7.12')
libcbor_proj = subproject('libcbor-0.11.0')

if sgx
# XXX: do not call subproject() from under "if sgx" conditional, because it
Expand All @@ -265,6 +266,11 @@ if sgx

protobuf_dep = dependency('libprotobuf-c')

# NOTE: For libcbor build we use a custom_target (see subprojects/packagefiles/libcbor), because
# CMake integration in Meson doesn't work correctly with PIC static libraries, see
# https://github.com/mesonbuild/meson/issues/10764.
libcbor_dep = libcbor_proj.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 packaging/alpine/APKBUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ makedepends="
autoconf
binutils-dev
bison
cmake
coreutils
findutils
gawk
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.11.0.wrap
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[wrap-file]
directory = libcbor-0.11.0
source_url = https://github.com/PJK/libcbor/archive/refs/tags/v0.11.0.tar.gz
source_fallback_url = https://packages.gramineproject.io/distfiles/libcbor-v0.11.0.tar.gz
source_filename = libcbor-0.11.0.tar.gz
source_hash = 89e0a83d16993ce50651a7501355453f5250e8729dfc8d4a251a78ea23bb26d7
patch_directory = libcbor-0.11.0
47 changes: 47 additions & 0 deletions subprojects/packagefiles/libcbor-0.11.0/compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/sh

set -e

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

if [ "$#" -ne 3 ]; then
echo "Usage: $0 <source dir> <build dir> <private dir>" >&2
exit 2
fi

SOURCE_DIR="$1"
BUILD_DIR="$2"
PRIVATE_DIR="$3"

BUILD_LOG=$(realpath "$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 "$SOURCE_DIR" "$PRIVATE_DIR"

(
cd "$PRIVATE_DIR"

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

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

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

log "done"
38 changes: 38 additions & 0 deletions subprojects/packagefiles/libcbor-0.11.0/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
project('libcbor', 'c', version: '0.11.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,
# see https://github.com/mesonbuild/meson/issues/1855
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',
)
9 changes: 8 additions & 1 deletion tools/sgx/ra-tls/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ libra_tls_attest = shared_library('ra_tls_attest',
link_args: ra_tls_link_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 @@ -40,8 +41,9 @@ libra_tls_verify = static_library('ra_tls_verify',

include_directories: pal_sgx_inc,
dependencies: [
sgx_util_dep,
libcbor_dep,
mbedtls_static_dep,
sgx_util_dep,
],
install: true,
install_rpath: get_option('prefix') / get_option('libdir'),
Expand Down Expand Up @@ -86,6 +88,7 @@ libsecret_prov_attest = shared_library('secret_prov_attest',
link_args: secret_prov_link_args,
include_directories: pal_sgx_inc,
dependencies: [
libcbor_dep,
mbedtls_static_dep,
sgx_util_dep,
],
Expand All @@ -104,6 +107,7 @@ libsecret_prov_verify = static_library('secret_prov_verify',
'secret_prov_common.c',

dependencies: [
libcbor_dep,
libra_tls_verify_dep,
mbedtls_static_dep,
sgx_util_dep,
Expand Down Expand Up @@ -150,6 +154,7 @@ if dcap

link_args: ra_tls_link_args,
dependencies: [
libcbor_dep,
libra_tls_verify_dep.as_link_whole(),
mbedtls_static_dep,
sgx_dcap_quoteverify_dep,
Expand All @@ -171,6 +176,7 @@ if dcap

link_args: ra_tls_link_args,
dependencies: [
libcbor_dep,
libra_tls_verify_dep.as_link_whole(),
mbedtls_static_dep,
sgx_dcap_quoteverify_dep,
Expand All @@ -192,6 +198,7 @@ if dcap
link_args: secret_prov_link_args,
include_directories: pal_sgx_inc,
dependencies: [
libcbor_dep,
libsecret_prov_verify_dep.as_link_whole(),
mbedtls_static_dep,
sgx_dcap_quoteverify_dep,
Expand Down
10 changes: 10 additions & 0 deletions tools/sgx/ra-tls/ra_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@

#include <stdint.h>

/* 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 }

/* 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 }

#define RA_TLS_EPID_API_KEY "RA_TLS_EPID_API_KEY"

#define RA_TLS_ALLOW_OUTDATED_TCB_INSECURE "RA_TLS_ALLOW_OUTDATED_TCB_INSECURE"
Expand Down
Loading

0 comments on commit 7d589f8

Please sign in to comment.