diff --git a/.ci/ubuntu18.04.dockerfile b/.ci/ubuntu18.04.dockerfile
index ec287b831b..4fc758d7f3 100644
--- a/.ci/ubuntu18.04.dockerfile
+++ b/.ci/ubuntu18.04.dockerfile
@@ -8,6 +8,7 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \
bison \
build-essential \
cargo \
+ cmake \
curl \
flex \
gawk \
diff --git a/.ci/ubuntu20.04.dockerfile b/.ci/ubuntu20.04.dockerfile
index fef644df87..2f772327df 100644
--- a/.ci/ubuntu20.04.dockerfile
+++ b/.ci/ubuntu20.04.dockerfile
@@ -8,6 +8,7 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \
build-essential \
cargo \
clang \
+ cmake \
curl \
flex \
gawk \
diff --git a/CI-Examples/ra-tls-mbedtls/src/server.c b/CI-Examples/ra-tls-mbedtls/src/server.c
index d5c63ae87c..c9e4a2facb 100644
--- a/CI-Examples/ra-tls-mbedtls/src/server.c
+++ b/CI-Examples/ra-tls-mbedtls/src/server.c
@@ -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 {
diff --git a/Documentation/attestation.rst b/Documentation/attestation.rst
index 8b5441bbf5..5d43a01e17 100644
--- a/Documentation/attestation.rst
+++ b/Documentation/attestation.rst
@@ -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``.
diff --git a/Documentation/devel/building.rst b/Documentation/devel/building.rst
index 74dc07a2af..149464846e 100644
--- a/Documentation/devel/building.rst
+++ b/Documentation/devel/building.rst
@@ -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
diff --git a/Documentation/img/ratls-interoperable.svg b/Documentation/img/ratls-interoperable.svg
new file mode 100644
index 0000000000..234746e54e
--- /dev/null
+++ b/Documentation/img/ratls-interoperable.svg
@@ -0,0 +1 @@
+
diff --git a/meson.build b/meson.build
index 7d6e93b75f..d17f8cf121 100644
--- a/meson.build
+++ b/meson.build
@@ -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
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index a2c9535aaa..c5385662dd 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -4,6 +4,7 @@
/curl-*/
/gcc-*/
/glibc-*/
+/libcbor-*/
/mbedtls-*/
/musl-*/
/tomlc99-*/
diff --git a/subprojects/libcbor-0.9.0.wrap b/subprojects/libcbor-0.9.0.wrap
new file mode 100644
index 0000000000..56a72cb502
--- /dev/null
+++ b/subprojects/libcbor-0.9.0.wrap
@@ -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
diff --git a/subprojects/packagefiles/libcbor/compile.sh b/subprojects/packagefiles/libcbor/compile.sh
new file mode 100644
index 0000000000..fc683c5e01
--- /dev/null
+++ b/subprojects/packagefiles/libcbor/compile.sh
@@ -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"
diff --git a/subprojects/packagefiles/libcbor/meson.build b/subprojects/packagefiles/libcbor/meson.build
new file mode 100644
index 0000000000..69804926d6
--- /dev/null
+++ b/subprojects/packagefiles/libcbor/meson.build
@@ -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',
+)
diff --git a/tools/sgx/ra-tls/meson.build b/tools/sgx/ra-tls/meson.build
index b57a459204..8b714b6ba9 100644
--- a/tools/sgx/ra-tls/meson.build
+++ b/tools/sgx/ra-tls/meson.build
@@ -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,
@@ -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')),
@@ -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,
],
@@ -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')),
@@ -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')),
@@ -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')),
@@ -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')),
diff --git a/tools/sgx/ra-tls/ra_tls.h b/tools/sgx/ra-tls/ra_tls.h
index 13ae00d3a3..f8af6930a4 100644
--- a/tools/sgx/ra-tls/ra_tls.h
+++ b/tools/sgx/ra-tls/ra_tls.h
@@ -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);
@@ -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")))
diff --git a/tools/sgx/ra-tls/ra_tls_attest.c b/tools/sgx/ra-tls/ra_tls_attest.c
index 0ce47b7738..a7c3abe989 100644
--- a/tools/sgx/ra-tls/ra_tls_attest.c
+++ b/tools/sgx/ra-tls/ra_tls_attest.c
@@ -22,6 +22,8 @@
#include
#include
+#include
+
#include
#include
#include
@@ -67,8 +69,10 @@ static ssize_t rw_file(const char* path, uint8_t* buf, size_t len, bool do_write
return ret < 0 ? ret : bytes;
}
-/*! given public key \p pk, generate an RA-TLS certificate \p writecrt with \p quote embedded */
+/*! given public key \p pk, generate an RA-TLS certificate \p writecrt with \p quote (legacy format)
+ * and \p evidence (new standard format) embedded */
static int generate_x509(mbedtls_pk_context* pk, const uint8_t* quote, size_t quote_size,
+ const uint8_t* evidence, size_t evidence_size,
mbedtls_x509write_cert* writecrt) {
int ret;
char* cert_timestamp_not_before = NULL;
@@ -133,12 +137,21 @@ static int generate_x509(mbedtls_pk_context* pk, const uint8_t* quote, size_t qu
if (ret < 0)
goto out;
- /* finally, embed the quote into the generated certificate (as X.509 extension) */
+ /* embed the SGX quote into the generated certificate (as X.509 extension) in two formats:
+ * - legacy non-standard "SGX quote" OID (used from Gramine v1.0)
+ * - new standard TCG DICE "tagged evidence" OID (2.23.133.5.4.9)
+ */
ret = mbedtls_x509write_crt_set_extension(writecrt, (const char*)g_quote_oid, g_quote_oid_size,
/*critical=*/0, quote, quote_size);
if (ret < 0)
goto out;
+ ret = mbedtls_x509write_crt_set_extension(writecrt, (const char*)g_evidence_oid,
+ g_evidence_oid_size, /*critical=*/0, evidence,
+ evidence_size);
+ if (ret < 0)
+ goto out;
+
ret = 0;
out:
free(cert_timestamp_not_before);
@@ -162,8 +175,9 @@ static int sha256_over_pk(mbedtls_pk_context* pk, uint8_t* sha) {
return mbedtls_sha256(pk_der, pk_der_size_byte, sha, /*is224=*/0);
}
-/*! given public key \p pk, generate an RA-TLS certificate \p writecrt */
-static int create_x509(mbedtls_pk_context* pk, mbedtls_x509write_cert* writecrt) {
+/*! generate SGX quote with user_report_data equal to SHA256 hash over \p pk (legacy format) */
+static int generate_quote_with_pk_hash(mbedtls_pk_context* pk, uint8_t** out_quote,
+ size_t* out_quote_size) {
sgx_report_data_t user_report_data = {0};
int ret = sha256_over_pk(pk, user_report_data.d);
if (ret < 0)
@@ -185,9 +199,310 @@ static int create_x509(mbedtls_pk_context* pk, mbedtls_x509write_cert* writecrt)
return MBEDTLS_ERR_X509_FILE_IO_ERROR;
}
- ret = generate_x509(pk, quote, quote_size, writecrt);
+ *out_quote = quote;
+ *out_quote_size = (size_t)quote_size;
+ return 0;
+}
+
+/*! create CBOR bstr from SHA256 hash of public key \p pk and copy it into \p out_cbor_bstr */
+static int cbor_bstr_from_pk_sha256(mbedtls_pk_context* pk, cbor_item_t** out_cbor_bstr) {
+ uint8_t sha256[SHA256_DIGEST_SIZE] = {0};
+ int ret = sha256_over_pk(pk, sha256);
+ if (ret < 0)
+ return ret;
+
+ cbor_item_t* cbor_bstr = cbor_build_bytestring(sha256, sizeof(sha256));
+ if (!cbor_bstr)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ *out_cbor_bstr = cbor_bstr;
+ return 0;
+}
+
+/*! generate hash-entry -- CBOR array with [ hash-alg-id, hash-value -- hash of pubkey ] */
+static int generate_serialized_hash_entry(mbedtls_pk_context* pk, uint8_t** out_hash_entry_buf,
+ size_t* out_hash_entry_buf_size) {
+ /* the hash-entry array as defined in Concise Software Identification Tags (CoSWID) */
+ cbor_item_t* cbor_hash_entry = cbor_new_definite_array(2);
+ if (!cbor_hash_entry)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ /* RA-TLS always generates SHA256 hash over pubkey */
+ cbor_item_t* cbor_hash_alg_id = cbor_build_uint8(IANA_NAMED_INFO_HASH_ALG_REGISTRY_SHA256);
+ if (!cbor_hash_alg_id) {
+ cbor_decref(&cbor_hash_entry);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ cbor_item_t* cbor_hash_value;
+ int ret = cbor_bstr_from_pk_sha256(pk, &cbor_hash_value);
+ if (ret < 0) {
+ cbor_decref(&cbor_hash_alg_id);
+ cbor_decref(&cbor_hash_entry);
+ return ret;
+ }
+
+ int bool_ret = cbor_array_push(cbor_hash_entry, cbor_hash_alg_id);
+ if (!bool_ret) {
+ cbor_decref(&cbor_hash_value);
+ cbor_decref(&cbor_hash_alg_id);
+ cbor_decref(&cbor_hash_entry);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ bool_ret = cbor_array_push(cbor_hash_entry, cbor_hash_value);
+ if (!bool_ret) {
+ cbor_decref(&cbor_hash_value);
+ cbor_decref(&cbor_hash_alg_id);
+ cbor_decref(&cbor_hash_entry);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ /* cbor_hash_entry took ownership of hash_alg_id and hash_value cbor items */
+ cbor_decref(&cbor_hash_alg_id);
+ cbor_decref(&cbor_hash_value);
+
+ uint8_t* hash_entry_buf;
+ size_t hash_entry_buf_size;
+ cbor_serialize_alloc(cbor_hash_entry, &hash_entry_buf, &hash_entry_buf_size);
+
+ cbor_decref(&cbor_hash_entry);
+
+ if (!hash_entry_buf)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ *out_hash_entry_buf = hash_entry_buf;
+ *out_hash_entry_buf_size = hash_entry_buf_size;
+ return 0;
+}
+
+/*! generate claims -- CBOR map with { "pubkey-hash" = } */
+static int generate_serialized_claims(mbedtls_pk_context* pk, uint8_t** out_claims_buf,
+ size_t* out_claims_buf_size) {
+ cbor_item_t* cbor_claims = cbor_new_definite_map(1);
+ if (!cbor_claims)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ cbor_item_t* cbor_pubkey_hash_key = cbor_build_string("pubkey-hash");
+ if (!cbor_pubkey_hash_key) {
+ cbor_decref(&cbor_claims);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ uint8_t* hash_entry_buf;
+ size_t hash_entry_buf_size;
+ int ret = generate_serialized_hash_entry(pk, &hash_entry_buf, &hash_entry_buf_size);
+ if (ret < 0) {
+ cbor_decref(&cbor_pubkey_hash_key);
+ cbor_decref(&cbor_claims);
+ return ret;
+ }
+
+ cbor_item_t* cbor_pubkey_hash_val = cbor_build_bytestring(hash_entry_buf, hash_entry_buf_size);
+
+ free(hash_entry_buf);
+
+ if (!cbor_pubkey_hash_val) {
+ cbor_decref(&cbor_pubkey_hash_key);
+ cbor_decref(&cbor_claims);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ struct cbor_pair cbor_pubkey_hash_pair = { .key = cbor_pubkey_hash_key,
+ .value = cbor_pubkey_hash_val };
+ bool bool_ret = cbor_map_add(cbor_claims, cbor_pubkey_hash_pair);
+ if (!bool_ret) {
+ cbor_decref(&cbor_pubkey_hash_val);
+ cbor_decref(&cbor_pubkey_hash_key);
+ cbor_decref(&cbor_claims);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ uint8_t* claims_buf;
+ size_t claims_buf_size;
+ cbor_serialize_alloc(cbor_claims, &claims_buf, &claims_buf_size);
+
+ cbor_decref(&cbor_pubkey_hash_val);
+ cbor_decref(&cbor_pubkey_hash_key);
+ cbor_decref(&cbor_claims);
+
+ if (!claims_buf)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ *out_claims_buf = claims_buf;
+ *out_claims_buf_size = claims_buf_size;
+ return 0;
+}
+
+/*! generate evidence -- CBOR tag with CBOR array of CBOR bstrs: [ quote, claims ] */
+static int generate_serialized_evidence(uint8_t* quote, size_t quote_size, uint8_t* claims,
+ size_t claims_size, uint8_t** out_evidence_buf,
+ size_t* out_evidence_buf_size) {
+ cbor_item_t* cbor_evidence = cbor_new_definite_array(2);
+ if (!cbor_evidence)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ cbor_item_t* cbor_quote = cbor_build_bytestring(quote, quote_size);
+ if (!cbor_quote) {
+ cbor_decref(&cbor_evidence);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ cbor_item_t* cbor_claims = cbor_build_bytestring(claims, claims_size);
+ if (!cbor_claims) {
+ cbor_decref(&cbor_quote);
+ cbor_decref(&cbor_evidence);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ int bool_ret = cbor_array_push(cbor_evidence, cbor_quote);
+ if (!bool_ret) {
+ cbor_decref(&cbor_claims);
+ cbor_decref(&cbor_quote);
+ cbor_decref(&cbor_evidence);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ bool_ret = cbor_array_push(cbor_evidence, cbor_claims);
+ if (!bool_ret) {
+ cbor_decref(&cbor_claims);
+ cbor_decref(&cbor_quote);
+ cbor_decref(&cbor_evidence);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ /* cbor_evidence took ownership of quote and claims cbor bstrs */
+ cbor_decref(&cbor_claims);
+ cbor_decref(&cbor_quote);
+
+ cbor_item_t* cbor_tagged_evidence = cbor_new_tag(TCG_DICE_TAGGED_EVIDENCE_CBOR_TAG);
+ if (!cbor_tagged_evidence) {
+ cbor_decref(&cbor_evidence);
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ }
+
+ cbor_tag_set_item(cbor_tagged_evidence, cbor_evidence);
+
+ uint8_t* evidence_buf;
+ size_t evidence_buf_size;
+ cbor_serialize_alloc(cbor_tagged_evidence, &evidence_buf, &evidence_buf_size);
+ cbor_decref(&cbor_evidence);
+ cbor_decref(&cbor_tagged_evidence);
+
+ if (!evidence_buf)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+
+ *out_evidence_buf = evidence_buf;
+ *out_evidence_buf_size = evidence_buf_size;
+ return 0;
+}
+
+/*! generate SGX-quote evidence with \p pk as one of the embedded claims (standard format) */
+static int generate_evidence_with_claims(mbedtls_pk_context* pk, uint8_t** out_evidence,
+ size_t* out_evidence_size) {
+ /*
+ * SGX-quote evidence has the following serialized-CBOR format:
+ *
+ * CBOR object (major type 6, new CBOR tag for "ECDSA SGX Quotes") ->
+ * CBOR array ->
+ * [
+ * 0: CBOR bstr (SGX quote with user_report_data = hash(serialized-cbor-map of claims)),
+ * 1: CBOR bstr (serialized-cbor-map of claims)
+ * ]
+ *
+ * where "serialized-cbor-map of claims" is as follows:
+ *
+ * CBOR map ->
+ * {
+ * "pubkey-hash" (req) : CBOR bstr (serialized-cbor-array hash-entry),
+ * "nonce" (opt) : CBOR bstr (arbitrary-sized nonce for per-session freshness)
+ * }
+ *
+ * where "serialized-cbor-array hash-entry" is as follows:
+ *
+ * CBOR array ->
+ * [
+ * 0: CBOR uint (hash-alg-id),
+ * 1: CBOR bstr (hash of DER-formatted "SubjectPublicKeyInfo" field as CBOR bstr)
+ * ]
+ *
+ * For hash-alg-id values, see
+ * https://www.iana.org/assignments/named-information/named-information.xhtml
+ */
+ uint8_t* claims = NULL;
+ uint8_t* quote = NULL;
+ uint8_t* evidence = NULL;
+
+ size_t claims_size;
+ int ret = generate_serialized_claims(pk, &claims, &claims_size);
+ if (ret < 0)
+ goto out;
+
+ sgx_report_data_t user_report_data = {0};
+ ret = mbedtls_sha256(claims, claims_size, user_report_data.d, /*is224=*/0);
+ if (ret < 0)
+ goto out;
+
+ ssize_t written = rw_file("/dev/attestation/user_report_data", user_report_data.d,
+ sizeof(user_report_data.d), /*do_write=*/true);
+ if (written != sizeof(user_report_data)) {
+ ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
+ goto out;
+ }
+
+ quote = malloc(SGX_QUOTE_MAX_SIZE);
+ if (!quote) {
+ ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+ goto out;
+ }
+
+ ssize_t quote_size = rw_file("/dev/attestation/quote", quote, SGX_QUOTE_MAX_SIZE,
+ /*do_write=*/false);
+ if (quote_size < 0) {
+ ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
+ goto out;
+ }
+
+ size_t evidence_size;
+ ret = generate_serialized_evidence(quote, quote_size, claims, claims_size, &evidence,
+ &evidence_size);
+ if (ret < 0)
+ goto out;
+
+ *out_evidence = evidence;
+ *out_evidence_size = (size_t)evidence_size;
+ ret = 0;
+out:
+ free(quote);
+ free(claims);
+ return ret;
+}
+
+/*! given public key \p pk, generate an RA-TLS certificate \p writecrt */
+static int create_x509(mbedtls_pk_context* pk, mbedtls_x509write_cert* writecrt) {
+ int ret;
+
+ /* put both "legacy Gramine" OID with plain SGX quote as well as standardized TCG DICE "tagged
+ * evidence" OID with CBOR-formatted SGX quote into RA-TLS X.509 cert */
+ uint8_t* quote = NULL;
+ uint8_t* evidence = NULL;
+
+ /* TODO: this legacy OID with plain SGX quote should be removed at some point */
+ size_t quote_size;
+ ret = generate_quote_with_pk_hash(pk, "e, "e_size);
+ if (ret < 0)
+ goto out;
+
+ size_t evidence_size;
+ ret = generate_evidence_with_claims(pk, &evidence, &evidence_size);
+ if (ret < 0)
+ goto out;
+
+ ret = generate_x509(pk, quote, quote_size, evidence, evidence_size, writecrt);
+out:
free(quote);
+ free(evidence);
return ret;
}
diff --git a/tools/sgx/ra-tls/ra_tls_verify_common.c b/tools/sgx/ra-tls/ra_tls_verify_common.c
index d8afd8bbd7..d999a1e036 100644
--- a/tools/sgx/ra-tls/ra_tls_verify_common.c
+++ b/tools/sgx/ra-tls/ra_tls_verify_common.c
@@ -13,6 +13,8 @@
#include
#include
+#include
+
#include
#include
#include
@@ -170,32 +172,34 @@ static int find_oid(const uint8_t* exts, size_t exts_size, const uint8_t* oid, s
return 0;
}
-/*! calculate sha256 over public key from \p crt and copy it into \p sha */
-static int sha256_over_crt_pk(mbedtls_x509_crt* crt, uint8_t* sha) {
+/*! fill buffer \p pk_der with DER-formatted public key from \p crt */
+static int fill_crt_pk_der(mbedtls_x509_crt* crt, uint8_t* pk_der, size_t* pk_der_size) {
mbedtls_ecp_keypair* key = mbedtls_pk_ec(crt->pk);
if (key == NULL || key->MBEDTLS_PRIVATE(grp).id != MBEDTLS_ECP_DP_SECP384R1) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
- uint8_t pk_der[PUB_KEY_SIZE_MAX] = {0};
-
/* below function writes data at the end of the buffer */
- int pk_der_size_byte = mbedtls_pk_write_pubkey_der(&crt->pk, pk_der, sizeof(pk_der));
- if (pk_der_size_byte < 0)
- return pk_der_size_byte;
+ int pk_der_size_int = mbedtls_pk_write_pubkey_der(&crt->pk, pk_der, *pk_der_size);
+ if (pk_der_size_int < 0)
+ return pk_der_size_int;
/* move the data to the beginning of the buffer, to avoid pointer arithmetic later */
- memmove(pk_der, pk_der + PUB_KEY_SIZE_MAX - pk_der_size_byte, pk_der_size_byte);
-
- return mbedtls_sha256(pk_der, pk_der_size_byte, sha, /*is224=*/0);
+ memmove(pk_der, pk_der + *pk_der_size - pk_der_size_int, pk_der_size_int);
+ *pk_der_size = (size_t)pk_der_size_int;
+ return 0;
}
-/*! compares if report_data from \quote corresponds to sha256 of public key in \p crt */
+/*! compares if report_data from \p quote corresponds to sha256 of public key in \p crt */
int cmp_crt_pk_against_quote_report_data(mbedtls_x509_crt* crt, sgx_quote_t* quote) {
- int ret;
+ uint8_t pk_der[PUB_KEY_SIZE_MAX] = {0};
+ size_t pk_der_size = sizeof(pk_der);
+ int ret = fill_crt_pk_der(crt, pk_der, &pk_der_size);
+ if (ret < 0)
+ return ret;
uint8_t sha[SHA256_DIGEST_SIZE];
- ret = sha256_over_crt_pk(crt, sha);
+ ret = mbedtls_sha256(pk_der, pk_der_size, sha, /*is224=*/0);
if (ret < 0)
return ret;
@@ -206,10 +210,249 @@ int cmp_crt_pk_against_quote_report_data(mbedtls_x509_crt* crt, sgx_quote_t* quo
return 0;
}
-int extract_quote_and_verify_pubkey(mbedtls_x509_crt* crt, sgx_quote_t** out_quote,
- size_t* out_quote_size) {
+/*! compares if CBOR array \p cbor_hash_entry from claims corresponds to public key in \p crt */
+static int cmp_crt_pk_against_cbor_claim_hash_entry(mbedtls_x509_crt* crt,
+ cbor_item_t* cbor_hash_entry) {
+ uint8_t pk_der[PUB_KEY_SIZE_MAX] = {0};
+ size_t pk_der_size = sizeof(pk_der);
+ int ret = fill_crt_pk_der(crt, pk_der, &pk_der_size);
+ if (ret < 0)
+ return ret;
+
+ if (!cbor_isa_array(cbor_hash_entry) || !cbor_array_is_definite(cbor_hash_entry)
+ || cbor_array_size(cbor_hash_entry) != 2) {
+ return MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ }
+
+ cbor_item_t* cbor_hash_alg_id = NULL;
+ cbor_item_t* cbor_hash_value = NULL;
+
+ cbor_hash_alg_id = cbor_array_get(cbor_hash_entry, /*index=*/0);
+ if (!cbor_hash_alg_id || !cbor_isa_uint(cbor_hash_alg_id)) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ cbor_hash_value = cbor_array_get(cbor_hash_entry, /*index=*/1);
+ if (!cbor_hash_value || !cbor_isa_bytestring(cbor_hash_value)
+ || !cbor_bytestring_is_definite(cbor_hash_value)) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ uint8_t hash_alg_id = cbor_get_uint8(cbor_hash_alg_id);
+ switch (hash_alg_id) {
+ /* assume that RESERVED (ID = 0) means SHA256 */
+ case IANA_NAMED_INFO_HASH_ALG_REGISTRY_RESERVED:
+ case IANA_NAMED_INFO_HASH_ALG_REGISTRY_SHA256: {
+ if (cbor_bytestring_length(cbor_hash_value) != SHA256_DIGEST_SIZE) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ uint8_t sha[SHA256_DIGEST_SIZE];
+ ret = mbedtls_sha256(pk_der, pk_der_size, sha, /*is224=*/0);
+ if (ret < 0)
+ goto out;
+
+ ret = memcmp(cbor_bytestring_handle(cbor_hash_value), sha, sizeof(sha));
+ if (ret) {
+ ret = MBEDTLS_ERR_X509_SIG_MISMATCH;
+ goto out;
+ }
+
+ break;
+ }
+
+ /* TODO: add other recognized hash functions on a need basis */
+
+ default:
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (cbor_hash_alg_id)
+ cbor_decref(&cbor_hash_alg_id);
+ if (cbor_hash_value)
+ cbor_decref(&cbor_hash_value);
+ return ret;
+}
+
+static int extract_standard_quote_and_verify_claims(mbedtls_x509_crt* crt, sgx_quote_t** out_quote,
+ size_t* out_quote_size) {
+ /* for description of evidence format, see ra_tls_attest.c:generate_evidence_with_claims() */
+ cbor_item_t* cbor_tagged_evidence = NULL;
+ cbor_item_t* cbor_evidence = NULL;
+ cbor_item_t* cbor_quote = NULL;
+ cbor_item_t* cbor_claims = NULL; /* serialized CBOR map of claims (as bytestring) */
+ cbor_item_t* cbor_claims_map = NULL;
+ cbor_item_t* cbor_hash_entry = NULL;
+ sgx_quote_t* quote = NULL;
+
+ uint8_t* evidence_buf;
+ size_t evidence_buf_size;
+ int ret = find_oid(crt->v3_ext.p, crt->v3_ext.len, g_evidence_oid_raw, g_evidence_oid_raw_size,
+ &evidence_buf, &evidence_buf_size);
+ if (ret < 0)
+ return ret;
+
+ struct cbor_load_result cbor_result;
+ cbor_tagged_evidence = cbor_load(evidence_buf, evidence_buf_size, &cbor_result);
+ if (cbor_result.error.code != CBOR_ERR_NONE) {
+ ERROR("Certificate: cannot parse 'tagged evidence' OID in CBOR format (error %d)\n",
+ cbor_result.error.code);
+ ret = (cbor_result.error.code == CBOR_ERR_MEMERROR) ? MBEDTLS_ERR_X509_ALLOC_FAILED
+ : MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ if (!cbor_isa_tag(cbor_tagged_evidence)
+ || cbor_tag_value(cbor_tagged_evidence) != TCG_DICE_TAGGED_EVIDENCE_CBOR_TAG) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ cbor_evidence = cbor_tag_item(cbor_tagged_evidence);
+ if (!cbor_evidence || !cbor_isa_array(cbor_evidence)
+ || !cbor_array_is_definite(cbor_evidence)) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ if (cbor_array_size(cbor_evidence) != 2) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ cbor_quote = cbor_array_get(cbor_evidence, /*index=*/0);
+ if (!cbor_quote || !cbor_isa_bytestring(cbor_quote) || !cbor_bytestring_is_definite(cbor_quote)
+ || cbor_bytestring_length(cbor_quote) == 0) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ size_t quote_size = cbor_bytestring_length(cbor_quote);
+ if (quote_size < sizeof(*quote)) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+ quote = malloc(quote_size);
+ if (!quote) {
+ ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
+ goto out;
+ }
+ memcpy(quote, cbor_bytestring_handle(cbor_quote), quote_size);
+
+ cbor_claims = cbor_array_get(cbor_evidence, /*index=*/1);
+ if (!cbor_claims || !cbor_isa_bytestring(cbor_claims)
+ || !cbor_bytestring_is_definite(cbor_claims)
+ || cbor_bytestring_length(cbor_claims) == 0) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ /* claims object is borrowed, no need to free separately */
+ uint8_t* claims_buf = cbor_bytestring_handle(cbor_claims);
+ size_t claims_buf_size = cbor_bytestring_length(cbor_claims);
+ assert(claims_buf && claims_buf_size);
+
+ /* verify that SGX quote corresponds to the attached serialized claims */
+ uint8_t sha[SHA256_DIGEST_SIZE];
+ ret = mbedtls_sha256(claims_buf, claims_buf_size, sha, /*is224=*/0);
+ if (ret < 0) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ ret = memcmp(quote->body.report_body.report_data.d, sha, SHA256_DIGEST_SIZE);
+ if (ret) {
+ ret = MBEDTLS_ERR_X509_SIG_MISMATCH;
+ goto out;
+ }
+
+ /* parse and verify CBOR claims */
+ cbor_claims_map = cbor_load(claims_buf, claims_buf_size, &cbor_result);
+ if (cbor_result.error.code != CBOR_ERR_NONE) {
+ ERROR("Certificate: cannot parse serialized CBOR map of claims (error %d)\n",
+ cbor_result.error.code);
+ ret = (cbor_result.error.code == CBOR_ERR_MEMERROR) ? MBEDTLS_ERR_X509_ALLOC_FAILED
+ : MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ if (!cbor_isa_map(cbor_claims_map) || !cbor_map_is_definite(cbor_claims_map)
+ || cbor_map_size(cbor_claims_map) < 1) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ struct cbor_pair* claims_pairs = cbor_map_handle(cbor_claims_map);
+ for (size_t i = 0; i < cbor_map_size(cbor_claims_map); i++) {
+ if (!claims_pairs[i].key || !cbor_isa_string(claims_pairs[i].key)
+ || !cbor_string_is_definite(claims_pairs[i].key)
+ || cbor_string_length(claims_pairs[i].key) == 0) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ if (strncmp((char*)cbor_string_handle(claims_pairs[i].key), "pubkey-hash",
+ cbor_string_length(claims_pairs[i].key)) == 0) {
+ /* claim { "pubkey-hash" : serialized CBOR array hash-entry (as CBOR bstr) } */
+ if (!claims_pairs[i].value || !cbor_isa_bytestring(claims_pairs[i].value)
+ || !cbor_bytestring_is_definite(claims_pairs[i].value)
+ || cbor_bytestring_length(claims_pairs[i].value) == 0) {
+ ret = MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ uint8_t* hash_entry_buf = cbor_bytestring_handle(claims_pairs[i].value);
+ size_t hash_entry_buf_size = cbor_bytestring_length(claims_pairs[i].value);
+
+ cbor_hash_entry = cbor_load(hash_entry_buf, hash_entry_buf_size, &cbor_result);
+ if (cbor_result.error.code != CBOR_ERR_NONE) {
+ ERROR("Certificate: cannot parse 'pubkey-hash' array in CBOR format (error %d)\n",
+ cbor_result.error.code);
+ ret = (cbor_result.error.code == CBOR_ERR_MEMERROR) ? MBEDTLS_ERR_X509_ALLOC_FAILED
+ : MBEDTLS_ERR_X509_INVALID_EXTENSIONS;
+ goto out;
+ }
+
+ ret = cmp_crt_pk_against_cbor_claim_hash_entry(crt, cbor_hash_entry);
+ if (ret < 0)
+ goto out;
+ } else {
+ INFO("WARNING: Unrecognized claim in TCG DICE 'tagged evidence' OID, ignoring.\n");
+ }
+ }
+
+ *out_quote = quote;
+ *out_quote_size = quote_size;
+ ret = 0;
+out:
+ if (ret < 0)
+ free(quote);
+ if (cbor_hash_entry)
+ cbor_decref(&cbor_hash_entry);
+ if (cbor_claims_map)
+ cbor_decref(&cbor_claims_map);
+ if (cbor_claims)
+ cbor_decref(&cbor_claims);
+ if (cbor_quote)
+ cbor_decref(&cbor_quote);
+ if (cbor_evidence)
+ cbor_decref(&cbor_evidence);
+ if (cbor_tagged_evidence)
+ cbor_decref(&cbor_tagged_evidence);
+ return ret;
+}
+
+static int extract_legacy_quote_and_verify_pubkey(mbedtls_x509_crt* crt, sgx_quote_t** out_quote,
+ size_t* out_quote_size) {
sgx_quote_t* quote;
size_t quote_size;
+
int ret = find_oid(crt->v3_ext.p, crt->v3_ext.len, g_quote_oid, g_quote_oid_size,
(uint8_t**)"e, "e_size);
if (ret < 0)
@@ -223,11 +466,29 @@ int extract_quote_and_verify_pubkey(mbedtls_x509_crt* crt, sgx_quote_t** out_quo
if (ret < 0)
return ret;
- *out_quote = quote;
+ /* quote returned by find_oid() is a pointer somewhere inside of the X.509 cert object; let's
+ * copy it into a newly allocated object to correctly track ownership */
+ sgx_quote_t* allocated_quote = malloc(quote_size);
+ if (!allocated_quote)
+ return MBEDTLS_ERR_X509_ALLOC_FAILED;
+ memcpy(allocated_quote, quote, quote_size);
+
+ *out_quote = allocated_quote;
*out_quote_size = quote_size;
return 0;
}
+int extract_quote_and_verify_claims(mbedtls_x509_crt* crt, sgx_quote_t** out_quote,
+ size_t* out_quote_size) {
+ int ret = extract_standard_quote_and_verify_claims(crt, out_quote, out_quote_size);
+ if (!ret)
+ return 0;
+
+ INFO("WARNING: TCG DICE 'tagged evidence' OID was not found. Checking non-standard legacy "
+ "Gramine OID. This will be deprecated in the future.\n");
+ return extract_legacy_quote_and_verify_pubkey(crt, out_quote, out_quote_size);
+}
+
void ra_tls_set_measurement_callback(int (*f_cb)(const char* mrenclave, const char* mrsigner,
const char* isv_prod_id, const char* isv_svn)) {
g_verify_measurements_cb = f_cb;
diff --git a/tools/sgx/ra-tls/ra_tls_verify_dcap.c b/tools/sgx/ra-tls/ra_tls_verify_dcap.c
index 572b47c9de..85fd6e883e 100644
--- a/tools/sgx/ra-tls/ra_tls_verify_dcap.c
+++ b/tools/sgx/ra-tls/ra_tls_verify_dcap.c
@@ -99,6 +99,7 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
(void)data;
int ret;
+ sgx_quote_t* quote = NULL;
uint8_t* supplemental_data = NULL;
uint32_t supplemental_data_size = 0;
@@ -116,9 +117,8 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
}
/* extract SGX quote from "quote" OID extension from crt */
- sgx_quote_t* quote;
size_t quote_size;
- ret = extract_quote_and_verify_pubkey(crt, "e, "e_size);
+ ret = extract_quote_and_verify_claims(crt, "e, "e_size);
if (ret < 0)
goto out;
@@ -212,6 +212,7 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
ret = 0;
out:
+ free(quote);
free(supplemental_data);
return ret;
}
diff --git a/tools/sgx/ra-tls/ra_tls_verify_epid.c b/tools/sgx/ra-tls/ra_tls_verify_epid.c
index e3491b28c0..2f30fc8386 100644
--- a/tools/sgx/ra-tls/ra_tls_verify_epid.c
+++ b/tools/sgx/ra-tls/ra_tls_verify_epid.c
@@ -121,6 +121,8 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
(void)data;
int ret;
+ sgx_quote_t* quote = NULL;
+
struct ias_context_t* ias = NULL;
char* ias_pub_key_pem = NULL;
@@ -160,9 +162,8 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
goto out;
/* extract SGX quote from "quote" OID extension from crt */
- sgx_quote_t* quote;
size_t quote_size;
- ret = extract_quote_and_verify_pubkey(crt, "e, "e_size);
+ ret = extract_quote_and_verify_claims(crt, "e, "e_size);
if (ret < 0)
goto out;
@@ -256,6 +257,7 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
if (ias)
ias_cleanup(ias);
+ free(quote);
free(ias_pub_key_pem);
free(quote_from_ias);
free(report_data);