Skip to content
This repository has been archived by the owner on Jan 20, 2022. It is now read-only.

[Pal/Linux-SGX] Add support for Microsoft Azure Attestation to RA-TLS #1793

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Examples/ra-tls-mbedtls/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/*.tar.gz
/*.json
/OUTPUT
/client
/mbedtls
Expand Down
2 changes: 1 addition & 1 deletion Examples/ra-tls-mbedtls/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ check_dcap_fail: app dcap

.PHONY: clean
clean:
$(RM) *.token *.sig *.manifest.sgx *.manifest pal_loader server client *.so *.so.* OUTPUT
$(RM) *.token *.sig *.manifest.sgx *.manifest pal_loader server client *.so *.so.* OUTPUT *.json

.PHONY: distclean
distclean: clean
Expand Down
8 changes: 8 additions & 0 deletions Examples/ra-tls-mbedtls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ RA_CLIENT_SPID=12345678901234567890123456789012 RA_CLIENT_LINKABLE=0 make app ep

SGX=1 ./pal_loader ./server epid &

RA_TLS_MAA_JSON_FILE="maa.json" \
RA_TLS_EPID_API_KEY=12345678901234567890123456789012 \
RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \
RA_TLS_MRENCLAVE=1234567890123456789012345678901234567890123456789012345678901234 \
Expand All @@ -77,6 +78,9 @@ RA_TLS_ISV_PROD_ID=0 RA_TLS_ISV_SVN=0 \

# client will successfully connect to the server via RA-TLS/EPID flows
kill %%

# you can open the generated file maa.json for Microsoft Azure Attestation (MAA)
# in your favorite text editor
```

- RA-TLS flows with SGX and with Graphene, ECDSA-based (DCAP) attestation:
Expand All @@ -88,6 +92,7 @@ make app dcap

SGX=1 ./pal_loader ./server dcap &

RA_TLS_MAA_JSON_FILE="maa.json" \
RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1 \
RA_TLS_MRENCLAVE=1234567890123456789012345678901234567890123456789012345678901234 \
RA_TLS_MRSIGNER=1234567890123456789012345678901234567890123456789012345678901234 \
Expand All @@ -96,6 +101,9 @@ RA_TLS_ISV_PROD_ID=0 RA_TLS_ISV_SVN=0 \

# client will successfully connect to the server via RA-TLS/DCAP flows
kill %%

# you can open the generated file maa.json for Microsoft Azure Attestation (MAA)
# in your favorite text editor
```

- RA-TLS flows with SGX and with Graphene, client with its own verification callback:
Expand Down
1 change: 1 addition & 0 deletions Jenkinsfiles/Linux-SGX-18.04-apps
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ pipeline {
make SGX=1 check_epid RA_CLIENT_SPID=${ra_client_spid} \
RA_TLS_EPID_API_KEY=${ra_client_key} \
RA_CLIENT_LINKABLE=0 \
RA_TLS_MAA_JSON_FILE="maa.json" \
RA_TLS_ALLOW_OUTDATED_TCB_INSECURE=1; \
make SGX=1 check_epid_fail RA_CLIENT_SPID=${ra_client_spid} \
RA_TLS_EPID_API_KEY=${ra_client_key} \
Expand Down
8 changes: 8 additions & 0 deletions Pal/src/host/Linux-SGX/tools/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ The library uses the following EPID-specific environment variables if available:
- ``RA_TLS_IAS_PUB_KEY_PEM`` (optional) -- public key of IAS. If not specified, the default
hard-coded public key is used.

The library uses the following Microsoft Azure Attestation (MAA) specific environment variables if
available:

- ``RA_TLS_MAA_JSON_FILE`` (optional) -- filename where the MAA-specific JSON content is generated.
The generated file contains "Type = 2", "EnclaveHeldDataHex" that contains the base64Url-encoded
public key of the RA-TLS certificate, and "QuoteHex" that contains the base64Url-encoded SGX
quote.

``ra_tls_verify_dcap.so``
^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
6 changes: 6 additions & 0 deletions Pal/src/host/Linux-SGX/tools/ra-tls/ra_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#define RA_TLS_EPID_API_KEY "RA_TLS_EPID_API_KEY"

#define RA_TLS_MAA_JSON_FILE "RA_TLS_MAA_JSON_FILE"

#define RA_TLS_ALLOW_OUTDATED_TCB_INSECURE "RA_TLS_ALLOW_OUTDATED_TCB_INSECURE"

#define RA_TLS_MRSIGNER "RA_TLS_MRSIGNER"
Expand All @@ -34,6 +36,7 @@
static const uint8_t quote_oid[] = OID(0x06);
static const size_t quote_oid_len = sizeof(quote_oid);
#define QUOTE_MAX_SIZE 8192
#define MAA_JSON_FILE_MAX_SIZE (QUOTE_MAX_SIZE * 3)

typedef int (*verify_measurements_cb_t)(const char* mrenclave, const char* mrsigner,
const char* isv_prod_id, const char* isv_svn);
Expand All @@ -52,6 +55,9 @@ int cmp_crt_pk_against_quote_report_data(mbedtls_x509_crt* crt, sgx_quote_t* quo
__attribute__ ((visibility("hidden")))
int verify_quote_against_envvar_measurements(const void* quote, size_t quote_size);

__attribute__ ((visibility("hidden")))
int generate_maa_json_file(const void* quote, size_t quote_size, mbedtls_x509_crt* crt);

/*!
* \brief Callback for user-specific verification of measurements in SGX quote.
*
Expand Down
193 changes: 193 additions & 0 deletions Pal/src/host/Linux-SGX/tools/ra-tls/ra_tls_verify_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
*/

#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <mbedtls/base64.h>
#include <mbedtls/pk.h>
#include <mbedtls/sha256.h>
#include <mbedtls/x509_crt.h>
Expand All @@ -24,6 +29,65 @@

verify_measurements_cb_t g_verify_measurements_cb = NULL;

/* annoyingly, mbedTLS doesn't provide Base64URL encoding, so need to add this helper; see
* https://github.com/ARMmbed/mbedtls/issues/1285; the below code is adapted from there */
static const uint8_t base64url_enc_map[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
'5', '6', '7', '8', '9', '-', '_' };

static int base64url_encode(uint8_t* dst, size_t dst_size, size_t* actual_size, const uint8_t* src,
size_t src_size) {
if (!src_size) {
*actual_size = 0;
return 0;
}

size_t n = src_size / 3;
if (src_size % 3)
n += 1;

n *= 4;

if (!dst || dst_size < n + 1) {
*actual_size = n + 1;
return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
}

n = (src_size / 3) * 3;

size_t i;
int C1, C2, C3;
uint8_t* p = dst;

for (i = 0; i < n; i += 3) {
C1 = *src++;
C2 = *src++;
C3 = *src++;

*p++ = base64url_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64url_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64url_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64url_enc_map[C3 & 0x3F];
}

if (i < src_size) {
C1 = *src++;
C2 = (i + 1 < src_size) ? *src++ : 0;

*p++ = base64url_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64url_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];

if (i + 1 < src_size)
*p++ = base64url_enc_map[((C2 & 15) << 2) & 0x3F];
}

*actual_size = p - dst;
*p = 0;
return 0;
}

static int getenv_enclave_measurements(sgx_measurement_t* mrsigner, bool* validate_mrsigner,
sgx_measurement_t* mrenclave, bool* validate_mrenclave,
sgx_prod_id_t* isv_prod_id, bool* validate_isv_prod_id,
Expand Down Expand Up @@ -231,3 +295,132 @@ int verify_quote_against_envvar_measurements(const void* quote, size_t quote_siz

return 0;
}

/* generate Microsoft Azure Attestation (MAA) compatible JSON file with fields like "QuoteHex",
* "EnclaveHeldDataHex", etc. to be sent MAA to for SGX remote attestation */
int generate_maa_json_file(const void* quote, size_t quote_size, mbedtls_x509_crt* crt) {
int ret;

char* json_file = getenv(RA_TLS_MAA_JSON_FILE);
if (!json_file) {
/* no filename provided, user doesn't want to create the MAA JSON file */
return 0;
}

/* make a copy of filename string immediately since getenv is not reentrant */
json_file = strdup(json_file);
if (!json_file)
return MBEDTLS_ERR_X509_ALLOC_FAILED;

/* allocate enough memory for SGX quote in base64Url format */
char* quote_base64url = calloc(1, QUOTE_MAX_SIZE * 2);
if (!quote_base64url) {
free(json_file);
return MBEDTLS_ERR_X509_ALLOC_FAILED;
}

/* allocate enough memory for JSON content (mostly SGX quote in Base64URL format) */
char* json_content = calloc(1, MAA_JSON_FILE_MAX_SIZE);
if (!json_content) {
free(json_file);
free(quote_base64url);
return MBEDTLS_ERR_X509_ALLOC_FAILED;
}

int bytes_printed;
char* json_content_ptr = json_content;

/* "Type" is always 2 for Intel SGX quotes */
bytes_printed = sprintf(json_content_ptr, "{ \"Type\": 2,\n");
if (bytes_printed < 0) {
ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
goto out;
}
json_content_ptr += bytes_printed;
assert(json_content_ptr - json_content < MAA_JSON_FILE_MAX_SIZE);

/* "EnclaveHeldDataHex" is a Base64URL-encoded public key in DER format of the RA-TLS cert */
uint8_t pk_der[PUB_KEY_SIZE_MAX] = {0};
int pk_der_size = mbedtls_pk_write_pubkey_der(&crt->pk, pk_der, PUB_KEY_SIZE_MAX);
if (pk_der_size != RSA_PUB_3072_KEY_DER_LEN) {
ret = MBEDTLS_ERR_PK_INVALID_PUBKEY;
goto out;
}

memmove(pk_der, pk_der + PUB_KEY_SIZE_MAX - pk_der_size, pk_der_size);

uint8_t pk_der_base64url[PUB_KEY_SIZE_MAX * 2] = {0};
size_t pk_der_base64url_size = 0;
ret = base64url_encode(pk_der_base64url, sizeof(pk_der_base64url), &pk_der_base64url_size,
pk_der, pk_der_size);
if (ret < 0)
goto out;

assert(pk_der_base64url_size);
bytes_printed = sprintf(json_content_ptr, "\"EnclaveHeldDataHex\": \"%s\",\n",
pk_der_base64url);
if (bytes_printed < 0) {
ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
goto out;
}
json_content_ptr += bytes_printed;
assert(json_content_ptr - json_content < MAA_JSON_FILE_MAX_SIZE);

/* "QuoteHex" is a Base64URL-encoded SGX quote */
size_t quote_base64url_size = 0;
ret = base64url_encode((uint8_t*)quote_base64url, QUOTE_MAX_SIZE * 2, &quote_base64url_size,
quote, quote_size);
if (ret < 0)
goto out;

assert(quote_base64url_size);
bytes_printed = sprintf(json_content_ptr, "\"QuoteHex\": \"%s\"\n", quote_base64url);
if (bytes_printed < 0) {
ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
goto out;
}
json_content_ptr += bytes_printed;
assert(json_content_ptr - json_content < MAA_JSON_FILE_MAX_SIZE);

/* finalize JSON file content and write into a file */
bytes_printed = sprintf(json_content_ptr, "}");
if (bytes_printed < 0) {
ret = MBEDTLS_ERR_X509_ALLOC_FAILED;
goto out;
}
json_content_ptr += bytes_printed;
assert(json_content_ptr - json_content < MAA_JSON_FILE_MAX_SIZE);

int fd = open(json_file, O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (fd < 0) {
ret = -errno;
goto out;
}

ssize_t len = json_content_ptr - json_content;
ssize_t bytes = 0;
while ((ssize_t)len > bytes) {
ssize_t x = write(fd, json_content + bytes, len - bytes);
if (x < 0 && (errno == EAGAIN || errno == EINTR))
continue;
if (x < 0) {
ret = -errno;
goto out;
}
bytes += x;
}

ret = close(fd);
if (ret < 0) {
ret = -errno;
goto out;
}

ret = 0;
out:
free(json_file);
free(json_content);
free(quote_base64url);
return ret;
}
5 changes: 5 additions & 0 deletions Pal/src/host/Linux-SGX/tools/ra-tls/ra_tls_verify_dcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
if (ret < 0)
goto out;

/* generate Microsoft Azure Attestation (MAA) JSON file if specified in envvars */
ret = generate_maa_json_file(quote, quote_size, crt);
if (ret < 0)
goto out;

/* prepare user-supplied verification parameter "allow outdated TCB" */
bool allow_outdated_tcb;
ret = getenv_allow_outdated_tcb(&allow_outdated_tcb);
Expand Down
5 changes: 5 additions & 0 deletions Pal/src/host/Linux-SGX/tools/ra-tls/ra_tls_verify_epid.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ int ra_tls_verify_callback(void* data, mbedtls_x509_crt* crt, int depth, uint32_
if (ret < 0)
goto out;

/* generate Microsoft Azure Attestation (MAA) JSON file if specified in envvars */
ret = generate_maa_json_file(quote, quote_size, crt);
if (ret < 0)
goto out;

/* initialize the IAS context, send the quote to the IAS and receive IAS attestation report */
ias = ias_init(g_api_key, g_report_url, g_sigrl_url);
if (!ias) {
Expand Down