From 5473b8554849f095d010dd646c1468426311e2ff Mon Sep 17 00:00:00 2001 From: "YiLin.Li" Date: Mon, 27 Jul 2020 23:47:27 +0000 Subject: [PATCH] stub_enclave: Add ra and tls librarys from sgx-ra-tls. Choose wolfSSL as sgx-ra-tls librarys. Signed-off-by: Yilin Li Signed-off-by: Jia Zhang --- stub_enclave/ra-attester.h | 43 ++ stub_enclave/ra-attester_private.h | 11 + stub_enclave/ra-challenger.c | 286 ++++++++++ stub_enclave/ra-challenger.h | 46 ++ stub_enclave/ra-challenger_private.h | 66 +++ stub_enclave/ra.c | 22 + stub_enclave/ra.h | 51 ++ stub_enclave/ra_private.h | 31 ++ stub_enclave/ra_tls.edl | 19 + stub_enclave/ra_tls_options.c.sh | 37 ++ stub_enclave/ratls-wolfssl.mk | 82 +++ stub_enclave/sgxsdk-ra-attester_t.c | 39 ++ stub_enclave/wolfssl-ra-attester.c | 752 +++++++++++++++++++++++++++ stub_enclave/wolfssl-ra-challenger.c | 391 ++++++++++++++ stub_enclave/wolfssl-ra.c | 34 ++ stub_enclave/wolfssl-ra.h | 7 + stub_enclave/wolfssl.patch | 519 ++++++++++++++++++ 17 files changed, 2436 insertions(+) create mode 100644 stub_enclave/ra-attester.h create mode 100644 stub_enclave/ra-attester_private.h create mode 100644 stub_enclave/ra-challenger.c create mode 100644 stub_enclave/ra-challenger.h create mode 100644 stub_enclave/ra-challenger_private.h create mode 100644 stub_enclave/ra.c create mode 100644 stub_enclave/ra.h create mode 100644 stub_enclave/ra_private.h create mode 100644 stub_enclave/ra_tls.edl create mode 100755 stub_enclave/ra_tls_options.c.sh create mode 100644 stub_enclave/ratls-wolfssl.mk create mode 100644 stub_enclave/sgxsdk-ra-attester_t.c create mode 100644 stub_enclave/wolfssl-ra-attester.c create mode 100644 stub_enclave/wolfssl-ra-challenger.c create mode 100644 stub_enclave/wolfssl-ra.c create mode 100644 stub_enclave/wolfssl-ra.h create mode 100644 stub_enclave/wolfssl.patch diff --git a/stub_enclave/ra-attester.h b/stub_enclave/ra-attester.h new file mode 100644 index 0000000..cb2b511 --- /dev/null +++ b/stub_enclave/ra-attester.h @@ -0,0 +1,43 @@ +#ifndef _RA_ATTESTER_H_ +#define _RA_ATTESTER_H_ + +#include + +struct ra_tls_options { + sgx_spid_t spid; + sgx_quote_sign_type_t quote_type; + /* NULL-terminated string of domain name/IP, port and path prefix, + e.g., api.trustedservices.intel.com/sgx/dev for development and + api.trustedservices.intel.com/sgx for production. */ + const char ias_server[512]; + const char subscription_key[32]; +}; + +struct ecdsa_ra_tls_options { + char subscription_key[32]; +}; + +void create_key_and_x509_pem +( + uint8_t* pem_key, + int* pem_key_len, + uint8_t* pem_cert, + int* pem_cert_len, + const struct ra_tls_options* opts +); + +#ifdef RATLS_ECDSA +void ecdsa_create_key_and_x509 +( + uint8_t* der_key, + int* der_key_len, + uint8_t* der_cert, + int* der_cert_len, + const struct ecdsa_ra_tls_options* opts +); +#endif + +void ra_tls_create_report( + sgx_report_t* report +); +#endif diff --git a/stub_enclave/ra-attester_private.h b/stub_enclave/ra-attester_private.h new file mode 100644 index 0000000..5f001e8 --- /dev/null +++ b/stub_enclave/ra-attester_private.h @@ -0,0 +1,11 @@ +#ifndef __RA_ATTESTER_PRIVATE_H__ +#define __RA_ATTESTER_PRIVATE_H__ + +void create_report +( + sgx_target_info_t* target_info, + const sgx_report_data_t* report_data, + sgx_report_t* report +); + +#endif diff --git a/stub_enclave/ra-challenger.c b/stub_enclave/ra-challenger.c new file mode 100644 index 0000000..e894bf0 --- /dev/null +++ b/stub_enclave/ra-challenger.c @@ -0,0 +1,286 @@ +/** + * Code common to all challenger implementations (i.e., independent of + * the TLS library). + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include + +#include "ra.h" +#include "ra_private.h" + +#if SGX_SDK +/* SGX SDK does not have this. */ +void *memmem(const void *h0, size_t k, const void *n0, size_t l); +#endif + +#include "ra-challenger_private.h" +#include "ra-challenger.h" + +void get_quote_from_extension +( + uint8_t* exts, + size_t exts_len, + sgx_quote_t* q +) +{ + uint8_t report[2048]; + uint32_t report_len; + + int rc = extract_x509_extension(exts, exts_len, + ias_response_body_oid, ias_oid_len, + report, &report_len, sizeof(report)); + + if (rc == 1) { + get_quote_from_report(report, report_len, q); + return; + } + + rc = extract_x509_extension(exts, exts_len, + quote_oid, ias_oid_len, + report, &report_len, sizeof(report)); + assert(rc == 1); + memcpy(q, report, sizeof(*q)); +} + +/** + * @return Returns -1 if OID not found. Otherwise, returns 1; + */ +int find_oid +( + const unsigned char* ext, size_t ext_len, + const unsigned char* oid, size_t oid_len, + unsigned char** val, size_t* len +) +{ + uint8_t* p = memmem(ext, ext_len, oid, oid_len); + if (p == NULL) { + return -1; + } + + p += oid_len; + + int i = 0; + + // Some TLS libraries generate a BOOLEAN for the criticality of the extension. + if (p[i] == 0x01) { + assert(p[i++] == 0x01); // tag, 0x01 is ASN1 Boolean + assert(p[i++] == 0x01); // length + assert(p[i++] == 0x00); // value (0 is non-critical, non-zero is critical) + } + + // Now comes the octet string + assert(p[i++] == 0x04); // tag for octet string + assert(p[i++] == 0x82); // length encoded in two bytes + *len = p[i++] << 8; + *len += p[i++]; + *val = &p[i++]; + + return 1; +} + +/** + * @return Returns -1 if OID was not found. Otherwise, returns 1; + */ +int extract_x509_extension +( + uint8_t* ext, + int ext_len, + const uint8_t* oid, + size_t oid_len, + uint8_t* data, + uint32_t* data_len, + uint32_t data_max_len +) +{ + uint8_t* ext_data; + size_t ext_data_len; + + int rc = find_oid(ext, ext_len, oid, oid_len, &ext_data, &ext_data_len); + if (rc == -1) return -1; + + assert(ext_data != NULL); + assert(ext_data_len <= data_max_len); + memcpy(data, ext_data, ext_data_len); + *data_len = ext_data_len; + + return 1; +} + +/** + * Extract all extensions. + */ +void extract_x509_extensions +( + uint8_t* ext, + int ext_len, + attestation_verification_report_t* attn_report +) +{ + extract_x509_extension(ext, ext_len, + ias_response_body_oid, ias_oid_len, + attn_report->ias_report, + &attn_report->ias_report_len, + sizeof(attn_report->ias_report)); + + extract_x509_extension(ext, ext_len, + ias_root_cert_oid, ias_oid_len, + attn_report->ias_sign_ca_cert, + &attn_report->ias_sign_ca_cert_len, + sizeof(attn_report->ias_sign_ca_cert)); + + extract_x509_extension(ext, ext_len, + ias_leaf_cert_oid, ias_oid_len, + attn_report->ias_sign_cert, + &attn_report->ias_sign_cert_len, + sizeof(attn_report->ias_sign_cert)); + + extract_x509_extension(ext, ext_len, + ias_report_signature_oid, ias_oid_len, + attn_report->ias_report_signature, + &attn_report->ias_report_signature_len, + sizeof(attn_report->ias_report_signature)); +} + +/** + * Extract ECDSA related extensions from X509. + */ +void ecdsa_extract_x509_extensions +( + uint8_t* ext, + int ext_len, + ecdsa_attestation_evidence_t* evidence +) +{ + extract_x509_extension(ext, ext_len, quote_oid, ias_oid_len, + evidence->quote, &evidence->quote_len, + sizeof(evidence->quote)); + + extract_x509_extension(ext, ext_len, pck_crt_oid, ias_oid_len, + evidence->pck_crt, &evidence->pck_crt_len, + sizeof(evidence->pck_crt)); + + extract_x509_extension(ext, ext_len, pck_sign_chain_oid, ias_oid_len, + evidence->pck_sign_chain, &evidence->pck_sign_chain_len, + sizeof(evidence->pck_sign_chain)); + + extract_x509_extension(ext, ext_len, tcb_info_oid, ias_oid_len, + evidence->tcb_info, &evidence->tcb_info_len, + sizeof(evidence->tcb_info)); + + extract_x509_extension(ext, ext_len, tcb_sign_chain_oid, ias_oid_len, + evidence->tcb_sign_chain, &evidence->tcb_sign_chain_len, + sizeof(evidence->tcb_sign_chain)); + + extract_x509_extension(ext, ext_len, qe_identity_oid, ias_oid_len, + evidence->qe_identity, &evidence->qe_identity_len, + sizeof(evidence->qe_identity)); + + extract_x509_extension(ext, ext_len, root_ca_crl_oid, ias_oid_len, + evidence->root_ca_crl, &evidence->root_ca_crl_len, + sizeof(evidence->root_ca_crl)); + + extract_x509_extension(ext, ext_len, pck_crl_oid, ias_oid_len, + evidence->pck_crl, &evidence->pck_crl_len, + sizeof(evidence->pck_crl)); +} + +/** + * @return 1 if it is an EPID-based attestation RA-TLS + * certificate. Otherwise, 0. + */ +int is_epid_ratls_cert +( + const uint8_t* der_crt, + uint32_t der_crt_len +) +{ + uint8_t* ext_data; + size_t ext_data_len; + int rc; + + rc = find_oid(der_crt, der_crt_len, + ias_response_body_oid, ias_oid_len, + &ext_data, &ext_data_len); + if (1 == rc) return 1; + + rc = find_oid(der_crt, der_crt_len, + quote_oid, ias_oid_len, + &ext_data, &ext_data_len); + if (1 == rc) return 0; + + /* Something is fishy. Neither EPID nor ECDSA RA-TLC cert?! */ + assert(0); + // Avoid compiler error: control reaches end of non-void function + // [-Werror=return-type] + return -1; +} + +/** + * Pretty-print information of EPID-based RA-TLS certificate to file descriptor. + */ +static +void dprintf_epid_ratls_cert +( + int fd, + uint8_t* der_crt, + uint32_t der_crt_len +) +{ + attestation_verification_report_t report; + extract_x509_extensions(der_crt, der_crt_len, &report); + dprintf(fd, "\nIntel Attestation Service Report\n"); + dprintf(fd, "%.*s\n", report.ias_report_len, report.ias_report); +} + +/** + * Pretty-print information of ECDSA-based RA-TLS certificate to file descriptor. + */ +static +void dprintf_ecdsa_ratls_cert +( + int fd, + uint8_t* der_crt, + uint32_t der_crt_len +) +{ + ecdsa_attestation_evidence_t evidence; + ecdsa_extract_x509_extensions(der_crt, der_crt_len, &evidence); + + dprintf(fd, "\nTCB info: "); + dprintf(fd, "%.*s\n", evidence.tcb_info_len, evidence.tcb_info); + dprintf(fd, "\nPCK Certificate:\n"); + dprintf(fd, "%.*s\n", evidence.pck_crt_len, evidence.pck_crt); +} + +void dprintf_ratls_cert +( + int fd, + uint8_t* der_crt, + uint32_t der_crt_len +) +{ + if (is_epid_ratls_cert(der_crt, der_crt_len)) { + dprintf_epid_ratls_cert(fd, der_crt, der_crt_len); + } else { + dprintf_ecdsa_ratls_cert(fd, der_crt, der_crt_len); + } + + sgx_quote_t quote; + get_quote_from_cert(der_crt, der_crt_len, "e); + sgx_report_body_t* body = "e.report_body; + + dprintf(fd, "MRENCLAVE = "); + for (int i=0; i < SGX_HASH_SIZE; ++i) dprintf(fd, "%02x", body->mr_enclave.m[i]); + dprintf(fd, "\n"); + + dprintf(fd, "MRSIGNER = "); + for (int i=0; i < SGX_HASH_SIZE; ++i) dprintf(fd, "%02x", body->mr_signer.m[i]); + dprintf(fd, "\n"); +} diff --git a/stub_enclave/ra-challenger.h b/stub_enclave/ra-challenger.h new file mode 100644 index 0000000..dedb64f --- /dev/null +++ b/stub_enclave/ra-challenger.h @@ -0,0 +1,46 @@ +#ifndef _RA_CHALLENGER_H_ +#define _RA_CHALLENGER_H_ + +#include + +/** + * Extract an Intel SGX quote from an Intel Attestation Service (IAS) report. + */ +void get_quote_from_report +( + const uint8_t* report /* in */, + const int report_len /* in */, + sgx_quote_t* quote +); + +/** + * Extract an Intel SGX quote from a DER-encoded X.509 certificate. + */ +void get_quote_from_cert +( + const uint8_t* der_crt, + uint32_t der_crt_len, + sgx_quote_t* q +); + +/** + * Verify SGX-related X.509 extensions. + * @return 0 if verification succeeds, 1 otherwise. + */ +int verify_sgx_cert_extensions +( + uint8_t* der_crt, + uint32_t der_crt_len +); + +/** + * Pretty-print information of RA-TLS certificate to file descriptor. + */ +void dprintf_ratls_cert +( + int fd, + uint8_t* der_crt, + uint32_t der_crt_len +); + +#endif diff --git a/stub_enclave/ra-challenger_private.h b/stub_enclave/ra-challenger_private.h new file mode 100644 index 0000000..c08dbb7 --- /dev/null +++ b/stub_enclave/ra-challenger_private.h @@ -0,0 +1,66 @@ +#include +#include + +#include + +extern const uint8_t ias_response_body_oid[]; +extern const uint8_t ias_root_cert_oid[]; +extern const uint8_t ias_leaf_cert_oid[]; +extern const uint8_t ias_report_signature_oid[]; + +extern const uint8_t quote_oid[]; +extern const uint8_t pck_crt_oid[]; +extern const uint8_t pck_sign_chain_oid[]; +extern const uint8_t tcb_info_oid[]; +extern const uint8_t tcb_sign_chain_oid[]; + +extern const size_t ias_oid_len; + +void get_quote_from_extension +( + uint8_t* ext, + size_t ext_len, + sgx_quote_t* q +); + +int find_oid +( + const unsigned char* ext, size_t ext_len, + const unsigned char* oid, size_t oid_len, + unsigned char** val, size_t* len +); + +void extract_x509_extensions +( + uint8_t* ext, + int ext_len, + attestation_verification_report_t* attn_report +); + +int extract_x509_extension +( + uint8_t* ext, + int ext_len, + const uint8_t* oid, + size_t oid_len, + uint8_t* data, + uint32_t* data_len, + uint32_t data_max_len +); + +void ecdsa_extract_x509_extensions +( + uint8_t* ext, + int ext_len, + ecdsa_attestation_evidence_t* evidence +); + +/** + * @return 1 if it is an EPID-based attestation RA-TLS + * certificate. Otherwise, 0. + */ +int is_epid_ratls_cert +( + const uint8_t* der_crt, + uint32_t der_crt_len +); diff --git a/stub_enclave/ra.c b/stub_enclave/ra.c new file mode 100644 index 0000000..bf30a4a --- /dev/null +++ b/stub_enclave/ra.c @@ -0,0 +1,22 @@ +/* Definitions common to attester and verifier. */ + +#include +#include + +#define OID(N) {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF8, 0x4D, 0x8A, 0x39, (N)} + +const uint8_t ias_response_body_oid[] = OID(0x02); +const uint8_t ias_root_cert_oid[] = OID(0x03); +const uint8_t ias_leaf_cert_oid[] = OID(0x04); +const uint8_t ias_report_signature_oid[] = OID(0x05); + +const uint8_t quote_oid[] = OID(0x06); +const uint8_t pck_crt_oid[] = OID(0x07); +const uint8_t pck_sign_chain_oid[] = OID(0x08); +const uint8_t tcb_info_oid[] = OID(0x09); +const uint8_t tcb_sign_chain_oid[] = OID(0x0a); +const uint8_t qe_identity_oid[] = OID(0x0b); +const uint8_t root_ca_crl_oid[] = OID(0x0c); +const uint8_t pck_crl_oid[] = OID(0x0d); + +const size_t ias_oid_len = sizeof(ias_response_body_oid); diff --git a/stub_enclave/ra.h b/stub_enclave/ra.h new file mode 100644 index 0000000..5d1c815 --- /dev/null +++ b/stub_enclave/ra.h @@ -0,0 +1,51 @@ +#ifndef _RA_H_ +#define _RA_H_ + +typedef struct { + uint8_t ias_report[2*1024]; + uint32_t ias_report_len; + uint8_t ias_sign_ca_cert[2*1024]; + uint32_t ias_sign_ca_cert_len; + uint8_t ias_sign_cert[2*1024]; + uint32_t ias_sign_cert_len; + uint8_t ias_report_signature[2*1024]; + uint32_t ias_report_signature_len; +} attestation_verification_report_t; + +static const int rsa_3072_der_len = 1766; +static const int rsa_pub_3072_pcks_der_len = 422; +static const int rsa_pub_3072_pcks_header_len = 24; +static const int rsa_pub_3072_raw_der_len = 398; /* rsa_pub_3072_pcks_der_len - pcks_nr_1_header_len */ + +typedef struct { + uint8_t quote[2048]; + uint32_t quote_len; + /* Certificiate in PEM format. */ + uint8_t pck_crt[2048]; + uint32_t pck_crt_len; + /* Certificate chain in PEM format. */ + uint8_t pck_sign_chain[4096]; + uint32_t pck_sign_chain_len; + /* JSON data as published by + https://api.portal.trustedservices.intel.com/documentation#pcs-tcb-info */ + uint8_t tcb_info[4096]; + uint32_t tcb_info_len; + /* Certificate chain in PEM format. */ + uint8_t tcb_sign_chain[4096]; + uint32_t tcb_sign_chain_len; + /* JSON data, e.g., as obtained from + https://api.portal.trustedservices.intel.com/documentation#pcs-qe-identity */ + uint8_t qe_identity[1024]; + uint32_t qe_identity_len; + /* PEM-encoded CRL as published by + https://certificates.trustedservices.intel.com/IntelSGXRootCA.crl */ + uint8_t root_ca_crl[1024]; + uint32_t root_ca_crl_len; + /* PEM-encoded certificate revocation list as published by + https://api.portal.trustedservices.intel.com/documentation#pcs-revocation */ + uint8_t pck_crl[1024]; + uint32_t pck_crl_len; + +} ecdsa_attestation_evidence_t; + +#endif diff --git a/stub_enclave/ra_private.h b/stub_enclave/ra_private.h new file mode 100644 index 0000000..7caf91d --- /dev/null +++ b/stub_enclave/ra_private.h @@ -0,0 +1,31 @@ +/* Interface to do remote attestation against Intel Attestation + Service. Two implementations exist: (1) sgxsdk-ra-attester_* to be + used with the SGX SDK. (2) nonsdk-ra-attester.c to be used with + Graphene-SGX. */ + +#ifndef _RA_PRIVATE_H +#define _RA_PRIVATE_H + +struct ra_tls_options; + +void do_remote_attestation(sgx_report_data_t* report_data, + const struct ra_tls_options* opts, + attestation_verification_report_t* r); + +extern const uint8_t ias_response_body_oid[]; +extern const uint8_t ias_root_cert_oid[]; +extern const uint8_t ias_leaf_cert_oid[]; +extern const uint8_t ias_report_signature_oid[]; + +extern const uint8_t quote_oid[]; +extern const uint8_t pck_crt_oid[]; +extern const uint8_t pck_sign_chain_oid[]; +extern const uint8_t tcb_info_oid[]; +extern const uint8_t tcb_sign_chain_oid[]; +extern const uint8_t qe_identity_oid[]; +extern const uint8_t root_ca_crl_oid[]; +extern const uint8_t pck_crl_oid[]; + +extern const size_t ias_oid_len; + +#endif diff --git a/stub_enclave/ra_tls.edl b/stub_enclave/ra_tls.edl new file mode 100644 index 0000000..f69da0b --- /dev/null +++ b/stub_enclave/ra_tls.edl @@ -0,0 +1,19 @@ +enclave { + + include "ra.h" + include "ra-attester.h" + include "sgx_report.h" + + trusted { + public void dummy(void); + }; + + untrusted { + /* define OCALLs here. */ + void ocall_sgx_init_quote([out] sgx_target_info_t* target_info); + void ocall_remote_attestation([in] sgx_report_t* report, + [in] const struct ra_tls_options* opts, + [out] attestation_verification_report_t* attn_report + ); + }; +}; diff --git a/stub_enclave/ra_tls_options.c.sh b/stub_enclave/ra_tls_options.c.sh new file mode 100755 index 0000000..1000571 --- /dev/null +++ b/stub_enclave/ra_tls_options.c.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# set -x + +if [[ -z "$ECDSA_SUBSCRIPTION_KEY" ]] && ( [[ -z "$SPID" ]] || [[ -z "$EPID_SUBSCRIPTION_KEY" ]] ); then + echo "//Either SPID and EPID_SUBSCRIPTION_KEY or ECDSA_SUBSCRIPTION_KEY is required!" +fi + +if ( [[ ! -z "$SPID" ]] && [[ -z "$EPID_SUBSCRIPTION_KEY" ]] ) || \ + ( [[ -z "$SPID" ]] && [[ ! -z "$EPID_SUBSCRIPTION_KEY" ]] ); then + echo "//For EPID, Both SPID and EPID_SUBSCRIPTION_KEY must be set!" +fi + +if ( [[ "$QUOTE_TYPE" != "SGX_LINKABLE_SIGNATURE" ]] ) && \ + ( [[ "$QUOTE_TYPE" != "SGX_UNLINKABLE_SIGNATURE" ]] ); then + echo "//QUOTE_TYPE must be one of SGX_UNLINKABLE_SIGNATURE or SGX_LINKABLE_SIGNATURE" +fi + +SPID_BYTE_ARRAY=$(echo $SPID | python -c 'import sys ; s = sys.stdin.readline().strip(); print("".join(["0x"+s[2*i:2*i+2]+"," for i in range(len(s)/2)]))') + +cat < 2048 bits to work +Wolfssl_C_Extra_Flags := -DSGX_SDK -DWOLFSSL_SGX -DWOLFSSL_SGX_ATTESTATION -DUSER_TIME -DWOLFSSL_CERT_EXT -DFP_MAX_BITS=8192 + +Wolfssl_C_Files := $(PROJECT_ROOT)/wolfssl-ra-attester.c \ + $(PROJECT_ROOT)/wolfssl-ra-challenger.c \ + $(PROJECT_ROOT)/sgxsdk-ra-attester_t.c \ + $(PROJECT_ROOT)/ra-challenger.c \ + $(PROJECT_ROOT)/wolfssl-ra.c \ + $(PROJECT_ROOT)/ra_tls_t.c \ + $(PROJECT_ROOT)/ra_tls_options.c + +Wolfssl_Include_Paths := -I$(WOLFSSL_ROOT)/ \ + -I$(WOLFSSL_ROOT)/wolfcrypt/ \ + -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc \ + -I$(SGX_SDK)/include/stlport \ + -I/usr/include/linux + +Compiler_Warnings := -Wall -Wextra -Wwrite-strings -Wlogical-op -Wshadow +Flags_Just_For_C := -Wno-implicit-function-declaration -std=c11 +Common_C_Cpp_Flags := $(SGX_COMMON_CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector $(Wolfssl_Include_Paths) -fno-builtin-printf -I. +Wolfssl_C_Flags := $(Compiler_Warnings) $(Flags_Just_For_C) $(Common_C_Cpp_Flags) $(Wolfssl_C_Extra_Flags) + +Wolfssl_C_Objects := $(Wolfssl_C_Files:.c=.o) + +override CFLAGS += $(Wolfssl_C_Flags) + +.PHONY: all run clean mrproper + +all: libsgx_ra_tls_wolfssl.a + +######## Library Objects ######## + +ra_tls_t.c ra_tls_u.c ra_tls_t.h ra_tls_u.h : ra_tls.edl + $(SGX_EDGER8R) $^ --search-path $(SGX_SDK)/include + +libsgx_ra_tls_wolfssl.a: ra_tls_t.o ra_tls_u.o $(Wolfssl_C_Objects) + ar rcs $@ $(Wolfssl_C_Objects) + @echo "LINK => $@" + +clean: + @rm -f $(Wolfssl_C_Objects) + @rm -f ra_tls_t.c ra_tls_t.h ra_tls_u.h ra_tls_u.c libsgx_ra_tls_wolfssl.a + +mrproper: clean + @rm -f ra_tls_t.c ra_tls_t.h ra_tls_u.h ra_tls_u.c libsgx_ra_tls_wolfssl.a diff --git a/stub_enclave/sgxsdk-ra-attester_t.c b/stub_enclave/sgxsdk-ra-attester_t.c new file mode 100644 index 0000000..8a76c11 --- /dev/null +++ b/stub_enclave/sgxsdk-ra-attester_t.c @@ -0,0 +1,39 @@ +#include +#include + +#include + +#include "ra.h" +#include "ra-attester.h" +#include "ra_private.h" +#include "ra_tls_t.h" // OCALLs + +/* Trusted portion (called from within the enclave) to do remote + attestation with the SGX SDK. */ +void do_remote_attestation +( + sgx_report_data_t* report_data, + const struct ra_tls_options* opts, + attestation_verification_report_t* attn_report +) +{ + sgx_target_info_t target_info = {0, }; + ocall_sgx_init_quote(&target_info); + + sgx_report_t report = {0, }; + sgx_status_t status = sgx_create_report(&target_info, report_data, &report); + assert(status == SGX_SUCCESS); + + ocall_remote_attestation(&report, opts, attn_report); +} + +void ra_tls_create_report( + sgx_report_t* report +) +{ + sgx_target_info_t target_info = {0, }; + sgx_report_data_t report_data = {0, }; + memset(report, 0, sizeof(*report)); + + sgx_create_report(&target_info, &report_data, report); +} diff --git a/stub_enclave/wolfssl-ra-attester.c b/stub_enclave/wolfssl-ra-attester.c new file mode 100644 index 0000000..4207eae --- /dev/null +++ b/stub_enclave/wolfssl-ra-attester.c @@ -0,0 +1,752 @@ +/* Code to create an RA-TLS certificate with wolfSSL. */ + +#define _GNU_SOURCE // for memmem() + +#include +#include +#include +#include + +#include + +#ifdef RATLS_ECDSA +#include + +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "ra.h" +#include "wolfssl-ra.h" +#include "ra-attester.h" +#include "ra-attester_private.h" +#ifdef RATLS_ECDSA +#include "ecdsa-ra-attester.h" +#include "ecdsa-sample-data/real/sample_data.h" +#include "ecdsa-attestation-collateral.h" +#include "curl_helper.h" + +static const int FMSPC_SIZE_BYTES = 6; + +#endif +#include "ra_private.h" + +/** + * Caller must allocate memory for certificate. + * + * @param der_crt_len On entry contains the size of der_crt buffer. On return holds actual size of certificate in bytes. + */ +static +void generate_x509 +( + RsaKey* key, + uint8_t* der_crt, /* out */ + int* der_crt_len, /* in/out */ + const attestation_verification_report_t* attn_report +) +{ + Cert crt; + wc_InitCert(&crt); + + strncpy(crt.subject.country, "US", CTC_NAME_SIZE); + strncpy(crt.subject.state, "OR", CTC_NAME_SIZE); + strncpy(crt.subject.locality, "Hillsboro", CTC_NAME_SIZE); + strncpy(crt.subject.org, "Intel Inc.", CTC_NAME_SIZE); + strncpy(crt.subject.unit, "Intel Labs", CTC_NAME_SIZE); + strncpy(crt.subject.commonName, "SGX rocks!", CTC_NAME_SIZE); + strncpy(crt.subject.email, "webmaster@intel.com", CTC_NAME_SIZE); + + memcpy(crt.iasAttestationReport, attn_report->ias_report, + attn_report->ias_report_len); + crt.iasAttestationReportSz = attn_report->ias_report_len; + + memcpy(crt.iasSigCACert, attn_report->ias_sign_ca_cert, + attn_report->ias_sign_ca_cert_len); + crt.iasSigCACertSz = attn_report->ias_sign_ca_cert_len; + + memcpy(crt.iasSigCert, attn_report->ias_sign_cert, + attn_report->ias_sign_cert_len); + crt.iasSigCertSz = attn_report->ias_sign_cert_len; + + memcpy(crt.iasSig, attn_report->ias_report_signature, + attn_report->ias_report_signature_len); + crt.iasSigSz = attn_report->ias_report_signature_len; + + RNG rng; + wc_InitRng(&rng); + + int certSz = wc_MakeSelfCert(&crt, der_crt, *der_crt_len, key, &rng); + assert(certSz > 0); + *der_crt_len = certSz; +} + +#ifdef RATLS_ECDSA +/** + * Generate RA-TLS certificate containing ECDSA-based attestation evidence. + * + * @param der_crt Caller must allocate memory for certificate. + * @param der_crt_len On entry contains the size of der_crt buffer. On return holds actual size of certificate in bytes. + */ +static +void ecdsa_generate_x509 +( + RsaKey* key, + uint8_t* der_crt, /* out */ + int* der_crt_len, /* in/out */ + const ecdsa_attestation_evidence_t* evidence +) +{ + Cert crt; + wc_InitCert(&crt); + + strncpy(crt.subject.country, "US", CTC_NAME_SIZE); + strncpy(crt.subject.state, "OR", CTC_NAME_SIZE); + strncpy(crt.subject.locality, "Hillsboro", CTC_NAME_SIZE); + strncpy(crt.subject.org, "Intel Inc.", CTC_NAME_SIZE); + strncpy(crt.subject.unit, "Intel Labs", CTC_NAME_SIZE); + strncpy(crt.subject.commonName, "SGX rocks!", CTC_NAME_SIZE); + strncpy(crt.subject.email, "webmaster@intel.com", CTC_NAME_SIZE); + + memcpy(crt.quote, evidence->quote, evidence->quote_len); + crt.quoteSz = evidence->quote_len; + + memcpy(crt.pckCrt, evidence->pck_crt, evidence->pck_crt_len); + crt.pckCrtSz = evidence->pck_crt_len; + + memcpy(crt.pckSignChain, evidence->pck_sign_chain, + evidence->pck_sign_chain_len); + crt.pckSignChainSz = evidence->pck_sign_chain_len; + + memcpy(crt.tcbInfo, evidence->tcb_info, + evidence->tcb_info_len); + crt.tcbInfoSz = evidence->tcb_info_len; + + memcpy(crt.tcbSignChain, evidence->tcb_sign_chain, + evidence->tcb_sign_chain_len); + crt.tcbSignChainSz = evidence->tcb_sign_chain_len; + + memcpy(crt.qeIdentity, evidence->qe_identity, + evidence->qe_identity_len); + crt.qeIdentitySz = evidence->qe_identity_len; + + memcpy(crt.rootCaCrl, evidence->root_ca_crl, + evidence->root_ca_crl_len); + crt.rootCaCrlSz = evidence->root_ca_crl_len; + + memcpy(crt.pckCrl, evidence->pck_crl, + evidence->pck_crl_len); + crt.pckCrlSz = evidence->pck_crl_len; + + RNG rng; + wc_InitRng(&rng); + + int certSz = wc_MakeSelfCert(&crt, der_crt, *der_crt_len, key, &rng); + assert(certSz > 0); + *der_crt_len = certSz; +} +#endif + +static void +wolfssl_create_key_and_x509 +( + uint8_t* der_key, + int* der_key_len, + uint8_t* der_cert, + int* der_cert_len, + const struct ra_tls_options* opts +) +{ + /* Generate key. */ + RsaKey genKey; + RNG rng; + int ret; + + wc_InitRng(&rng); + wc_InitRsaKey(&genKey, 0); + ret = wc_MakeRsaKey(&genKey, 3072, 65537, &rng); + assert(ret == 0); + + uint8_t der[4096]; + int derSz = wc_RsaKeyToDer(&genKey, der, sizeof(der)); + assert(derSz >= 0); + assert(derSz <= (int) *der_key_len); + + *der_key_len = derSz; + memcpy(der_key, der, derSz); + + /* Generate certificate */ + sgx_report_data_t report_data = {0, }; + sha256_rsa_pubkey(report_data.d, &genKey); + attestation_verification_report_t attestation_report; + + do_remote_attestation(&report_data, opts, &attestation_report); + + // generate_x509(&genKey, der_cert, der_cert_len, + // &attestation_report); +} + +#ifdef RATLS_ECDSA +static void binary_to_base16 +( + const uint8_t* binary, + uint32_t binary_len, + char* base16, + uint32_t base16_len +) +{ + /* + 1 for terminating null byte. */ + assert(base16_len >= binary_len * 2 + 1); + + for (uint32_t i = 0; i < binary_len; ++i) { + sprintf(&base16[i * 2], "%02X", binary[i]); + } +} + +static +void ecdsa_get_quote_from_quote_service +( + const sgx_report_data_t* report_data, + uint8_t* quote, + uint32_t* quote_len +) +{ +#ifndef SGX_SIMULATION + uint32_t quote_size = 0; + sgx_target_info_t qe_target_info = {0, }; + int sockfd = connect_to_quote_service(); + get_target_info_from_quote_service(sockfd, &qe_target_info, "e_size); + assert(quote_size <= *quote_len); + + sgx_report_t report; + create_report(&qe_target_info, report_data, &report); + get_quote_from_quote_service(sockfd, &report, quote, quote_size); + *quote_len = quote_size; + + close(sockfd); +#else + (void) report_data; + + assert(ecdsa_sample_data_quote_ppid_rsa3072_dat_len <= *quote_len); + memcpy(quote, ecdsa_sample_data_quote_ppid_rsa3072_dat, ecdsa_sample_data_quote_ppid_rsa3072_dat_len); + *quote_len = ecdsa_sample_data_quote_ppid_rsa3072_dat_len; +#endif +} + +/* static void print_byte_array(FILE* f, uint8_t* data, int size) { */ +/* for (int i = 0; i < size; ++i) { */ +/* fprintf(f, "%02X", data[i]); */ +/* } */ +/* } */ + +/** + * Pulls PCK certificate's signing chain information out of HTTP + * response header. Also url-decodes it. + */ +static +void parse_response_header_get_pck_cert +( + CURL* curl, + const char* headers, + size_t headers_len, + char* pck_cert_chain, + uint32_t* pck_cert_chain_len +) +{ + const char header_tag[] = "SGX-PCK-Certificate-Issuer-Chain: "; + char* header_begin = memmem((const char*) headers, + headers_len, + header_tag, + strlen(header_tag)); + if (header_begin == NULL) { + fprintf(stderr, "HTTP headers: %.*s\n", (int) headers_len, headers); + } + assert(header_begin != NULL); + header_begin += strlen(header_tag); + char* header_end = memmem(header_begin, + headers_len - (header_begin - headers), + "\r\n", + strlen("\r\n")); + assert(header_end); + + int unescaped_len; + char* unescaped = curl_easy_unescape(curl, header_begin, header_end - header_begin, &unescaped_len); + assert(unescaped); + assert(unescaped_len <= (int) *pck_cert_chain_len); + memcpy(pck_cert_chain, unescaped, unescaped_len); + *pck_cert_chain_len = unescaped_len; + curl_free(unescaped); +} + +/** + * Today, this grabs the PCK certificate from Intel's backend service + * and stores it in evidence.pck_crt. + * + * Tomorrow, this may grab the PCK certificate from somewhere else, + * e.g., some local PCK certificate caching service. + */ +static +void obtain_pck_cert +( + ecdsa_attestation_evidence_t* evidence, + const struct ecdsa_ra_tls_options* opts, + sgx_ql_ppid_rsa3072_encrypted_cert_info_t* cert_data +) +{ + char encrypted_ppid[786 + 1]; + binary_to_base16(cert_data->enc_ppid, sizeof(cert_data->enc_ppid), + encrypted_ppid, sizeof(encrypted_ppid)); + + char pceid[4 + 1]; + binary_to_base16((uint8_t*)&cert_data->pce_info.pce_id, + sizeof(cert_data->pce_info.pce_id), + pceid, sizeof(pceid)); + + char pcesvn[4 + 1]; + binary_to_base16((uint8_t*)&cert_data->pce_info.pce_isv_svn, + sizeof(cert_data->pce_info.pce_isv_svn), + pcesvn, sizeof(pcesvn)); + + char cpusvn[32 + 1]; + binary_to_base16((uint8_t*)&cert_data->cpu_svn, + sizeof(cert_data->cpu_svn), + cpusvn, sizeof(cpusvn)); + +#ifdef DEBUG + printf("%s:%s: PPID=%s\nPCE ID= %s\nPCE SVN= %s\nCPU SVN= %s\n", + __FILE__, __FUNCTION__, encrypted_ppid, pceid, pcesvn, cpusvn); +#endif + + char url[2048]; + const char base_url[] = "https://api.trustedservices.intel.com/sgx/certification/v1/pckcert"; + snprintf(url, sizeof(url), "%s?encrypted_ppid=%s&cpusvn=%s&pcesvn=%s&pceid=%s", + base_url, encrypted_ppid, cpusvn, pcesvn, pceid); + /* printf("URL= %s\n", url); */ + /* printf("subscription_key= %.32s\n", opts->subscription_key); */ + + CURL* curl = curl_easy_init(); + assert(curl != NULL); + struct buffer_and_size header = {(char*) malloc(1), 0}; + struct buffer_and_size body = {(char*) malloc(1), 0}; + + char buf[128]; + int rc = snprintf(buf, sizeof(buf), "Ocp-Apim-Subscription-Key: %.32s", + opts->subscription_key); + assert(rc < (int) sizeof(buf)); + + struct curl_slist* request_headers = NULL; + request_headers = curl_slist_append(request_headers, buf); + + http_get(curl, url, &header, &body, request_headers, NULL); + + evidence->pck_sign_chain_len = sizeof(evidence->pck_sign_chain); + parse_response_header_get_pck_cert(curl, header.data, header.len, + (char*) evidence->pck_sign_chain, + &evidence->pck_sign_chain_len); + + assert(sizeof(evidence->pck_crt) >= body.len); + memcpy(evidence->pck_crt, body.data, body.len); + evidence->pck_crt_len = body.len; + + curl_easy_cleanup(curl); + free(header.data); + free(body.data); + curl_slist_free_all(request_headers); +} + +/** + * Pulls TCB info's signing chain from HTTP response header. Also url-decodes it. + */ +static +void parse_response_header_tcb_info_cert_chain +( + CURL* curl, + const char* headers, + size_t headers_len, + char* cert_chain, + uint32_t* cert_chain_len +) +{ + const char header_tag[] = "SGX-TCB-Info-Issuer-Chain: "; + char* header_begin = memmem((const char*) headers, + headers_len, + header_tag, + strlen(header_tag)); + assert(header_begin != NULL); + header_begin += strlen(header_tag); + char* header_end = memmem(header_begin, + headers_len - (header_begin - headers), + "\r\n", + strlen("\r\n")); + assert(header_end); + + int unescaped_len; + char* unescaped = curl_easy_unescape(curl, header_begin, header_end - header_begin, &unescaped_len); + assert(unescaped); + assert((int) *cert_chain_len >= unescaped_len); + memcpy(cert_chain, unescaped, unescaped_len); + *cert_chain_len = unescaped_len; +} + +static void init(void) __attribute__((constructor)); +static void init(void) { + /* Apparently this function is not thread-safe + (cf. https://curl.haxx.se/libcurl/c/curl_global_init.html + ). Calling it from within the library initializer hopefully + solves this. */ + curl_global_init(CURL_GLOBAL_DEFAULT); +} + +static void deinit(void) __attribute__((destructor)); +static void deinit(void) { + curl_global_cleanup(); +} + +/** + * Today, obtains the TCB information from Intel's backend service and + * stores it in evidence.tcb_info along with the signing chain in + * evidence.tcb_sign_chain. + * + * Tomorrow, this may obtain the TCB info from some local caching + * service, from an on-disk file, etc. + */ +static +void obtain_tcb_info +( + char fmspc[6], + ecdsa_attestation_evidence_t* evidence +) +{ + /* Need 2 * 6 bytes when encoded into + hexadecimal. +1 byte for terminating NUL. */ + char fmspc_base16[FMSPC_SIZE_BYTES * 2 + 1]; + binary_to_base16((unsigned char*) fmspc, FMSPC_SIZE_BYTES, fmspc_base16, + sizeof(fmspc_base16)); + + char url[256]; + int rc = snprintf(url, sizeof(url), + "https://api.trustedservices.intel.com/sgx/certification/v1/tcb?fmspc=%s", + fmspc_base16); + assert(rc < (int) sizeof(url)); + + CURL *curl = curl_easy_init(); + struct buffer_and_size header = {(char*) malloc(1), 0}; + struct buffer_and_size body = {(char*) malloc(1), 0}; + http_get(curl, url, &header, &body, NULL, NULL); + + evidence->tcb_sign_chain_len = sizeof(evidence->tcb_sign_chain); + parse_response_header_tcb_info_cert_chain(curl, header.data, header.len, + (char*) evidence->tcb_sign_chain, + &evidence->tcb_sign_chain_len); + + assert(sizeof(evidence->tcb_info) >= body.len); + evidence->tcb_info_len = sizeof(evidence->tcb_info); + memcpy(evidence->tcb_info, body.data, body.len); + evidence->tcb_info_len = body.len; + + curl_easy_cleanup(curl); + free(header.data); + free(body.data); +} + +/** + * The FMSPC field is contained in the PCK certificate. Find the FMSPC + * OID and extract it. + */ +static +void extract_fmspc_from_pck_cert +( + char fmspc[6], + ecdsa_attestation_evidence_t* evidence +) +{ + assert(NULL != evidence->pck_crt); + assert(evidence->pck_crt_len > 0); + + uint8_t pck_crt_der[2048]; + uint32_t pck_crt_der_len = sizeof(pck_crt_der); + int bytes = wolfSSL_CertPemToDer(evidence->pck_crt, evidence->pck_crt_len, + pck_crt_der, pck_crt_der_len, CERT_TYPE); + assert(bytes > 0); + pck_crt_der_len = (uint32_t) bytes; + + DecodedCert crt; + + InitDecodedCert(&crt, (byte*) pck_crt_der, pck_crt_der_len, NULL); + InitSignatureCtx(&crt.sigCtx, NULL, INVALID_DEVID); + int ret = ParseCertRelative(&crt, CERT_TYPE, NO_VERIFY, 0); + assert(ret == 0); + + /* fmspc_oid[0] = 0x06 ... ASN.1 type (0x06 is OID) + fmspc_oid[1] = 0x0a ... length of OID in bytes, i.e., 10 bytes. + fmspc_oid[2 .. ] ... the OID 1.2.840.113741.1.13.1.4 */ + const uint8_t fmspc_oid[] = { 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, + 0xf8, 0x4d, 0x01, 0x0d, 0x01, 0x04 }; + uint8_t* p = memmem(crt.extensions, crt.extensionsSz, + fmspc_oid, sizeof(fmspc_oid)); + assert(NULL != p); + p += sizeof(fmspc_oid); + /* p[0] ... ASN.1 type, i.e., octet string (0x04) */ + assert(p[0] == 0x04); + /* p[1] ... length in bytes, i.e., 6 bytes (0x06) */ + assert(p[1] == FMSPC_SIZE_BYTES); + p += 2; + FreeDecodedCert(&crt); + + memcpy(fmspc, p, FMSPC_SIZE_BYTES); +} + +/** + * Given a quote, gets corresponding PCK certificate. + * + * First, inspects the quote for all the values required to obtain the + * PCK certificate. Second, request PCK certificate from backend + * service. + */ +static +void ecdsa_get_pck_cert +( + ecdsa_attestation_evidence_t* evidence, + const struct ecdsa_ra_tls_options* opts +) +{ + sgx_quote3_t* q = (sgx_quote3_t*) evidence->quote; + assert(evidence->quote_len == sizeof(sgx_quote3_t) + q->signature_data_len); + sgx_quote_header_t quote_header = q->header; + assert(quote_header.version == 3); + assert(quote_header.att_key_type == 2); + + sgx_ql_ecdsa_sig_data_t* sig_data = + (sgx_ql_ecdsa_sig_data_t*) (q->signature_data); + sgx_ql_auth_data_t* auth_data = + (sgx_ql_auth_data_t*) (sig_data->auth_certification_data); + sgx_ql_certification_data_t* cert_data_generic = + (sgx_ql_certification_data_t*) (sig_data->auth_certification_data + + sizeof(*auth_data) + auth_data->size); + + assert(cert_data_generic->cert_key_type == PPID_RSA3072_ENCRYPTED); + + /* printf("ppid enc type= %d\n", cert_data_generic->cert_key_type); */ + + /* if (cert_data_generic->cert_key_type == PPID_CLEARTEXT) { */ + /* sgx_ql_ppid_cleartext_cert_info_t* cert_info = */ + /* (sgx_ql_ppid_cleartext_cert_info_t*) (cert_data_generic->certification_data); */ + /* char ppid_base16[16*2]; */ + /* binary_to_base16(cert_info->ppid, sizeof(cert_info->ppid), */ + /* ppid_base16, sizeof(ppid_base16)); */ + /* printf("PPID= %.32s\n", ppid_base16); */ + /* assert(0); */ + /* } */ + + assert(cert_data_generic->size == sizeof(sgx_ql_ppid_rsa3072_encrypted_cert_info_t)); + sgx_ql_ppid_rsa3072_encrypted_cert_info_t* cert_data = + (sgx_ql_ppid_rsa3072_encrypted_cert_info_t*) (cert_data_generic->certification_data); + + obtain_pck_cert(evidence, opts, cert_data); +} + +/** + * Obtains quote, PCK certificate, TCB information, Quoting Enclave + * identity and certificate revocation lists. + */ +static +void collect_attestation_evidence +( + const sgx_report_data_t* report_data, + const struct ecdsa_ra_tls_options* opts, + ecdsa_attestation_evidence_t* evidence +) +{ + evidence->quote_len = sizeof(evidence->quote); + ecdsa_get_quote_from_quote_service(report_data, evidence->quote, &evidence->quote_len); + + ecdsa_get_pck_cert(evidence, opts); + + char fmspc[6]; + extract_fmspc_from_pck_cert(fmspc, evidence); + obtain_tcb_info(fmspc, evidence); + + /* For now, these values are hard-coded in the executable. In the + future, they may be fetched dynamically. */ + memcpy(evidence->qe_identity, qe_identity_json, qe_identity_json_len); + evidence->qe_identity_len = qe_identity_json_len; + memcpy(evidence->root_ca_crl, root_ca_crl_pem, root_ca_crl_pem_len); + evidence->root_ca_crl_len = root_ca_crl_pem_len; + memcpy(evidence->pck_crl, pck_crl_pem, pck_crl_pem_len); + evidence->pck_crl_len = pck_crl_pem_len; +} + +static void +ecdsa_wolfssl_create_key_and_x509 +( + uint8_t* der_key, + int* der_key_len, + uint8_t* der_cert, + int* der_cert_len, + const struct ecdsa_ra_tls_options* opts +) +{ + /* Generate key. */ + RsaKey genKey; + RNG rng; + int ret; + + wc_InitRng(&rng); + wc_InitRsaKey(&genKey, 0); + ret = wc_MakeRsaKey(&genKey, 3072, 65537, &rng); + assert(ret == 0); + + uint8_t der[4096]; + int derSz = wc_RsaKeyToDer(&genKey, der, sizeof(der)); + assert(derSz >= 0); + assert(derSz <= (int) *der_key_len); + + *der_key_len = derSz; + memcpy(der_key, der, derSz); + + /* Generate certificate */ + sgx_report_data_t report_data = {0, }; + sha256_rsa_pubkey(report_data.d, &genKey); + ecdsa_attestation_evidence_t evidence; + + collect_attestation_evidence(&report_data, opts, &evidence); + + ecdsa_generate_x509(&genKey, der_cert, der_cert_len, &evidence); +} + +/** + * @param der_key_len On the way in, this is the max size for the der_key parameter. On the way out, this is the actual size for der_key. + * @param der_cert_len On the way in, this is the max size for the der_cert parameter. On the way out, this is the actual size for der_cert. + */ +void ecdsa_create_key_and_x509 +( + uint8_t* der_key, /* out */ + int* der_key_len, /* in/out */ + uint8_t* der_cert, /* out */ + int* der_cert_len, /* in/out */ + const struct ecdsa_ra_tls_options* opts /* in */ +) +{ + ecdsa_wolfssl_create_key_and_x509(der_key, der_key_len, + der_cert, der_cert_len, + opts); +} +#endif + +#ifdef WOLFSSL_SGX +time_t XTIME(time_t* tloc) { + time_t x = 1512498557; /* Dec 5, 2017, 10:29 PDT */ + if (tloc) *tloc = x; + return x; +} + +time_t mktime(struct tm* tm) { + (void) tm; + assert(0); + return (time_t) 0; +} +#endif + +/** + * @param der_key_len On the way in, this is the max size for the der_key parameter. On the way out, this is the actual size for der_key. + * @param der_cert_len On the way in, this is the max size for the der_cert parameter. On the way out, this is the actual size for der_cert. + */ +void create_key_and_x509 +( + uint8_t* der_key, /* out */ + int* der_key_len, /* in/out */ + uint8_t* der_cert, /* out */ + int* der_cert_len, /* in/out */ + const struct ra_tls_options* opts, /* in */ + void* targetinfo, void* data, void* report +) +{ + wolfssl_create_key_and_x509(der_key, der_key_len, + der_cert, der_cert_len, + opts); +} + +static void create_key_111 +( + uint8_t* der_key, /* out */ + int* der_key_len, /* in/out */ + uint8_t* der_cert, /* out */ + int* der_cert_len, /* in/out */ + const struct ra_tls_options* opts, /* in */ + void* targetinfo, void* data, void* report +) +{ + wolfssl_create_key_and_x509(der_key, der_key_len, + der_cert, der_cert_len, + opts); +} + +static void +wolfssl_create_key +( + uint8_t* der_key, + int* der_key_len, + uint8_t* der_cert, + int* der_cert_len, + const struct ra_tls_options* opts, + void* targetinfo, void* data, void* report +) +{ + /* Generate key. */ + RsaKey genKey; + RNG rng; + int ret; + + wc_InitRng(&rng); + wc_InitRsaKey(&genKey, 0); + ret = wc_MakeRsaKey(&genKey, 3072, 65537, &rng); + assert(ret == 0); + + uint8_t der[4096]; + int derSz = wc_RsaKeyToDer(&genKey, der, sizeof(der)); + assert(derSz >= 0); + assert(derSz <= (int) *der_key_len); + + *der_key_len = derSz; + memcpy(der_key, der, derSz); + /* Generate certificate */ + sgx_report_data_t report_data = {0, }; + sha256_rsa_pubkey(report_data.d, &genKey); + attestation_verification_report_t attestation_report; + do_remote_attestation(&report_data, opts, &attestation_report); +} + + +void create_key_and_x509_pem +( + uint8_t* pem_key, /* out */ + int* pem_key_len, /* in/out */ + uint8_t* pem_cert, /* out */ + int* pem_cert_len, /* in/out */ + const struct ra_tls_options* opts +) +{ + unsigned char der_key[16 * 1024] = {0, }; + int der_key_len = sizeof(der_key); + unsigned char der_cert[16 * 1024] = {0, }; + int der_cert_len = sizeof(der_cert_len); + int len; + + wolfssl_create_key_and_x509(der_key, &der_key_len, + der_cert, &der_cert_len, + opts); + + len = wc_DerToPem(der_key, der_key_len, pem_key, *pem_key_len, PRIVATEKEY_TYPE); + assert(len > 0); + *pem_key_len = len; + + len = wc_DerToPem(der_cert, der_cert_len, pem_cert, *pem_cert_len, CERT_TYPE); + assert(len > 0); + *pem_cert_len = len; +} diff --git a/stub_enclave/wolfssl-ra-challenger.c b/stub_enclave/wolfssl-ra-challenger.c new file mode 100644 index 0000000..ff54fb4 --- /dev/null +++ b/stub_enclave/wolfssl-ra-challenger.c @@ -0,0 +1,391 @@ +/** + * wolfSSL-based implementation of the RA-TLS challenger API + * (cf. ra-challenger.h). + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RATLS_ECDSA +#include +#endif + +#include "ra.h" +#include "wolfssl-ra.h" +#include "ra-challenger.h" +#include "ra-challenger_private.h" + +#ifdef RATLS_ECDSA +#include "ecdsa-sample-data/real/sample_data.h" +#endif + +extern unsigned char ias_sign_ca_cert_der[]; +extern unsigned int ias_sign_ca_cert_der_len; + +void get_quote_from_cert +( + const uint8_t* der_crt, + uint32_t der_crt_len, + sgx_quote_t* q +) +{ + DecodedCert crt; + int ret; + + InitDecodedCert(&crt, (byte*) der_crt, der_crt_len, NULL); + InitSignatureCtx(&crt.sigCtx, NULL, INVALID_DEVID); + ret = ParseCertRelative(&crt, CERT_TYPE, NO_VERIFY, 0); + assert(ret == 0); + + get_quote_from_extension(crt.extensions, crt.extensionsSz, q); + + FreeDecodedCert(&crt); +} + +void get_quote_from_report +( + const uint8_t* report /* in */, + const int report_len /* in */, + sgx_quote_t* quote +) +{ + // Move report into \0 terminated buffer such that we can work + // with str* functions. + char buf[report_len + 1]; + memcpy(buf, report, report_len); + buf[report_len] = '\0'; + + const char* json_string = "\"isvEnclaveQuoteBody\":\""; + char* p_begin = strstr(buf, json_string); + assert(p_begin != NULL); + p_begin += strlen(json_string); + const char* p_end = strchr(p_begin, '"'); + assert(p_end != NULL); + + const int quote_base64_len = p_end - p_begin; + uint8_t* quote_bin = malloc(quote_base64_len); + uint32_t quote_bin_len = quote_base64_len; + + Base64_Decode((const byte*) p_begin, quote_base64_len, + quote_bin, "e_bin_len); + + assert(quote_bin_len <= sizeof(sgx_quote_t)); + memset(quote, 0, sizeof(sgx_quote_t)); + memcpy(quote, quote_bin, quote_bin_len); + free(quote_bin); +} + +static +int verify_report_data_against_server_cert +( + DecodedCert* crt, + sgx_quote_t* quote +) +{ + /* crt->publicKey seems to be the DER encoded public key. The + OpenSSL DER formatted version of the public key obtained with + openssl rsa -in ./server-key.pem -pubout -outform DER -out + server-pubkey.der has an additional 24 bytes + prefix/header. d->pubKeySize is 270 and the server-pubkey.der + file has 294 bytes. That's to be expected according to [1] */ + /* [1] https://crypto.stackexchange.com/questions/14491/why-is-a-2048-bit-public-rsa-key-represented-by-540-hexadecimal-characters-in */ + + /* 2017-12-06, Thomas Knauth, A hard-coded offset into the + DER-encoded public key only works for specific key sizes. The + 24 byte offset is specific to 2048 bit RSA keys. For example, a + 1024 bit RSA key only has an offset of 22. + */ + RsaKey rsaKey; + unsigned int idx = 0; + int ret; + + wc_InitRsaKey(&rsaKey, NULL); + ret = wc_RsaPublicKeyDecode(crt->publicKey, &idx, &rsaKey, crt->pubKeySize); + assert(ret == 0); + + byte shaSum[SHA256_DIGEST_SIZE] = {0, }; + sha256_rsa_pubkey(shaSum, &rsaKey); + wc_FreeRsaKey(&rsaKey); + +#ifdef DEBUG + fprintf(stderr, "SHA256 of server's public key:\n"); + for (int i=0; i < SHA256_DIGEST_SIZE; ++i) fprintf(stderr, "%02x", shaSum[i]); + fprintf(stderr, "\n"); + + fprintf(stderr, "Quote's report data:\n"); + for (int i=0; i < SGX_REPORT_DATA_SIZE; ++i) fprintf(stderr, "%02x", quote->report_body.report_data.d[i]); + fprintf(stderr, "\n"); +#endif + + assert(SHA256_DIGEST_SIZE <= SGX_REPORT_DATA_SIZE); + ret = memcmp(quote->report_body.report_data.d, shaSum, SHA256_DIGEST_SIZE); + assert(ret == 0); + + return ret; +} + +static +int verify_ias_report_signature +( + attestation_verification_report_t* attn_report +) +{ + DecodedCert crt; + int ret; + + uint8_t der[4096]; + int der_len; + der_len = wolfSSL_CertPemToDer(attn_report->ias_sign_cert, attn_report->ias_sign_cert_len, + der, sizeof(der), + CERT_TYPE); + assert(der_len > 0); + + InitDecodedCert(&crt, der, der_len, NULL); + InitSignatureCtx(&crt.sigCtx, NULL, INVALID_DEVID); + ret = ParseCertRelative(&crt, CERT_TYPE, NO_VERIFY, 0); + assert(ret == 0); + + RsaKey rsaKey; + unsigned int idx = 0; + + ret = wc_InitRsaKey(&rsaKey, NULL); + assert(ret == 0); + ret = wc_RsaPublicKeyDecode(crt.publicKey, &idx, &rsaKey, crt.pubKeySize); + assert(ret == 0); + + ret = wc_SignatureVerify(WC_HASH_TYPE_SHA256, + /* This is required such that signature + matches what OpenSSL produces. OpenSSL + embeds the hash in an ASN.1 structure + before signing it. */ + WC_SIGNATURE_TYPE_RSA_W_ENC, + attn_report->ias_report, attn_report->ias_report_len, + attn_report->ias_report_signature, attn_report->ias_report_signature_len, + &rsaKey, sizeof(rsaKey)); + + FreeDecodedCert(&crt); + wc_FreeRsaKey(&rsaKey); + + return ret; +} + +static +int verify_ias_certificate_chain(attestation_verification_report_t* attn_report) { + WOLFSSL_CERT_MANAGER* cm; + + cm = wolfSSL_CertManagerNew(); + assert(cm != NULL); + + /* like load verify locations, 1 for success, < 0 for error */ + int ret = wolfSSL_CertManagerLoadCABuffer(cm, ias_sign_ca_cert_der, + ias_sign_ca_cert_der_len, + SSL_FILETYPE_ASN1); + assert(ret == 1); + + ret = wolfSSL_CertManagerVerifyBuffer(cm, attn_report->ias_sign_cert, + attn_report->ias_sign_cert_len, + SSL_FILETYPE_PEM); + assert(ret == SSL_SUCCESS); + + wolfSSL_CertManagerFree(cm); + cm = NULL; + + return 0; +} + +/** + * Check if isvEnclaveQuoteStatus is "OK" + * (cf. https://software.intel.com/sites/default/files/managed/7e/3b/ias-api-spec.pdf, + * pg. 24). + * + * @return 0 if verified successfully, 1 otherwise. + */ +static +int verify_enclave_quote_status +( + const char* ias_report, + int ias_report_len +) +{ + // Move ias_report into \0 terminated buffer such that we can work + // with str* functions. + char buf[ias_report_len + 1]; + memcpy(buf, ias_report, ias_report_len); + buf[ias_report_len] = '\0'; + + const char* json_string = "\"isvEnclaveQuoteStatus\":\""; + char* p_begin = strstr(buf, json_string); + assert(p_begin != NULL); + p_begin += strlen(json_string); + + const char* status_OK = "OK\""; + if (0 == strncmp(p_begin, status_OK, strlen(status_OK))) return 0; +#ifdef SGX_GROUP_OUT_OF_DATE + const char* status_outdated = "GROUP_OUT_OF_DATE\""; + if (0 == strncmp(p_begin, status_outdated, strlen(status_outdated))) { + printf("WARNING: isvEnclaveQuoteStatus is GROUP_OUT_OF_DATE\n"); + return 0; + } +#endif + return 1; +} + +static +int epid_verify_sgx_cert_extensions +( + uint8_t* der_crt, + uint32_t der_crt_len +) +{ + attestation_verification_report_t attn_report; + + DecodedCert crt; + int ret; + + InitDecodedCert(&crt, der_crt, der_crt_len, NULL); + InitSignatureCtx(&crt.sigCtx, NULL, INVALID_DEVID); + ret = ParseCertRelative(&crt, CERT_TYPE, NO_VERIFY, 0); + assert(ret == 0); + + extract_x509_extensions(crt.extensions, crt.extensionsSz, &attn_report); + + /* Base64 decode attestation report signature. */ + uint8_t sig_base64[sizeof(attn_report.ias_report_signature)]; + memcpy(sig_base64, attn_report.ias_report_signature, attn_report.ias_report_signature_len); + int rc = Base64_Decode(sig_base64, attn_report.ias_report_signature_len, + attn_report.ias_report_signature, &attn_report.ias_report_signature_len); + assert(0 == rc); + + ret = verify_ias_certificate_chain(&attn_report); + assert(ret == 0); + + ret = verify_ias_report_signature(&attn_report); + assert(ret == 0); + + ret = verify_enclave_quote_status((const char*) attn_report.ias_report, + attn_report.ias_report_len); + assert(ret == 0); + + sgx_quote_t quote = {0, }; + get_quote_from_report(attn_report.ias_report, + attn_report.ias_report_len, + "e); + ret = verify_report_data_against_server_cert(&crt, "e); + assert(ret == 0); + + FreeDecodedCert(&crt); + + return 0; +} + +#ifdef RATLS_ECDSA +static +int ecdsa_verify_sgx_cert_extensions +( + uint8_t* der_crt, + uint32_t der_crt_len +) +{ + DecodedCert crt; + int ret; + + InitDecodedCert(&crt, der_crt, der_crt_len, NULL); + InitSignatureCtx(&crt.sigCtx, NULL, INVALID_DEVID); + ret = ParseCertRelative(&crt, CERT_TYPE, NO_VERIFY, 0); + assert(ret == 0); + + ecdsa_attestation_evidence_t evidence; + ecdsa_extract_x509_extensions(crt.extensions, + crt.extensionsSz, + &evidence); + FreeDecodedCert(&crt); + + /* pem_cert_chain := pck cert + pck CA cert + root CA cert */ + /* crls := root ca crl + pck crl */ + /* pem_trusted_root_ca_cert */ + size_t pck_cert_chain_len = evidence.pck_sign_chain_len + evidence.pck_crt_len + 1; + char pck_cert_chain[pck_cert_chain_len]; + memcpy(pck_cert_chain, evidence.pck_crt, evidence.pck_crt_len); + memcpy(pck_cert_chain + evidence.pck_crt_len, evidence.pck_sign_chain, evidence.pck_sign_chain_len); + pck_cert_chain[sizeof(pck_cert_chain) - 1] = '\0'; + + assert(evidence.root_ca_crl_len < sizeof(evidence.root_ca_crl)); + evidence.root_ca_crl[evidence.root_ca_crl_len] = '\0'; + assert(evidence.pck_crl_len < sizeof(evidence.pck_crl)); + evidence.pck_crl[evidence.pck_crl_len] = '\0'; + + const char* const crls[] = {(char*) evidence.root_ca_crl, + (char*) evidence.pck_crl}; + + /* SGXDataCenterAttestationPrimitives/QuoteVerification/Src/ThirdParty/CMakeLists.txt depends on openssl-1.1.0i.tar.gz" */ + /* libQuoteVerification.so seems to link in OpenSSL dependencies statically?! */ + + /* QVL expects zero terminated strings as input! */ + + int pck_crt_status = sgxAttestationVerifyPCKCertificate(pck_cert_chain, crls, + (char*) ecdsa_sample_data_real_trustedRootCaCert_pem); + + assert(evidence.tcb_info_len < sizeof(evidence.tcb_info)); + evidence.tcb_info[evidence.tcb_info_len] = '\0'; + assert(evidence.tcb_sign_chain_len < sizeof(evidence.tcb_sign_chain)); + evidence.tcb_sign_chain[evidence.tcb_sign_chain_len] = '\0'; + int tcb_info_status = sgxAttestationVerifyTCBInfo((char*) evidence.tcb_info, + (char*) evidence.tcb_sign_chain, + (char*) evidence.root_ca_crl, + (char*) ecdsa_sample_data_real_trustedRootCaCert_pem); + + assert(evidence.qe_identity_len < sizeof(evidence.qe_identity)); + evidence.qe_identity[evidence.qe_identity_len] = '\0'; + + int qe_identity_status = sgxAttestationVerifyQEIdentity((char*) evidence.qe_identity, + (char*) evidence.tcb_sign_chain, + (char*) evidence.root_ca_crl, + (char*) ecdsa_sample_data_real_trustedRootCaCert_pem); + + int quote_status = sgxAttestationVerifyQuote(evidence.quote, evidence.quote_len, + (char*) evidence.pck_crt, + (char*) evidence.pck_crl, + (char*) evidence.tcb_info, + (char*) evidence.qe_identity); + + // TODO Update DCAP SDK to newest version. + if (quote_status == STATUS_TCB_OUT_OF_DATE) { + printf("!!! WARNING: quote verification resulted in STATUS_TCB_OUT_OF_DATE\n"); + quote_status = 0; + } + + int report_user_data_status = verify_report_data_against_server_cert(&crt, (sgx_quote_t*) evidence.quote); + + return pck_crt_status || tcb_info_status || qe_identity_status || quote_status || report_user_data_status; +} +#endif + +int verify_sgx_cert_extensions +( + uint8_t* der_crt, + uint32_t der_crt_len +) +{ + if (is_epid_ratls_cert(der_crt, der_crt_len)) { + return epid_verify_sgx_cert_extensions(der_crt, der_crt_len); + } else { +#ifdef RATLS_ECDSA + return ecdsa_verify_sgx_cert_extensions(der_crt, der_crt_len); +#endif + } + assert(0); + // Avoid compiler error: control reaches end of non-void function + // [-Werror=return-type] + return -1; +} diff --git a/stub_enclave/wolfssl-ra.c b/stub_enclave/wolfssl-ra.c new file mode 100644 index 0000000..2806746 --- /dev/null +++ b/stub_enclave/wolfssl-ra.c @@ -0,0 +1,34 @@ +#include +#include + +#include +#include +#include +#include "ra.h" +#include "wolfssl-ra.h" + +void sha256_rsa_pubkey +( + unsigned char hash[SHA256_DIGEST_SIZE], + RsaKey* key +) +{ + // Expect a 3072 bit RSA key. + assert(key->n.used == 48 /* == 3072 / 8 / 8 */); + + uint8_t buf[1024]; + /* SetRsaPublicKey() only exports n and e without wrapping them in + additional ASN.1 (PKCS#1). */ + int pub_rsa_key_der_len = SetRsaPublicKey(buf, key, sizeof(buf), 0); + assert(pub_rsa_key_der_len == rsa_pub_3072_raw_der_len); + + Sha256 sha; + wc_InitSha256(&sha); + wc_Sha256Update(&sha, buf, pub_rsa_key_der_len); + wc_Sha256Final(&sha, hash); +} + +/* This function only exists to make edger8r happy. There must be at + least one trusted (ECALL) function. */ +void dummy(void) { +} diff --git a/stub_enclave/wolfssl-ra.h b/stub_enclave/wolfssl-ra.h new file mode 100644 index 0000000..8657223 --- /dev/null +++ b/stub_enclave/wolfssl-ra.h @@ -0,0 +1,7 @@ +#include + +void sha256_rsa_pubkey +( + unsigned char hash[SHA256_DIGEST_SIZE], + RsaKey* key +); diff --git a/stub_enclave/wolfssl.patch b/stub_enclave/wolfssl.patch new file mode 100644 index 0000000..120f895 --- /dev/null +++ b/stub_enclave/wolfssl.patch @@ -0,0 +1,519 @@ +diff --git a/pre-commit.sh b/pre-commit.sh +index cbac1b5..71c7976 100755 +--- a/pre-commit.sh ++++ b/pre-commit.sh +@@ -3,6 +3,8 @@ + # + # Our "pre-commit" hook. + ++exit 0 ++ + # save current config + echo "\n\nSaving current config\n\n" + cp config.status tmp.status +diff --git a/src/internal.c b/src/internal.c +index a6989c4..9036910 100644 +--- a/src/internal.c ++++ b/src/internal.c +@@ -9777,11 +9777,14 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + ret = DoHandShakeMsgType(ssl, input, inOutIdx, type, size, totalSz); + } + else { +- if (inputLength + ssl->arrays->pendingMsgOffset +- > ssl->arrays->pendingMsgSz) { ++ word32 pendSz = ++ ssl->arrays->pendingMsgSz - ssl->arrays->pendingMsgOffset; + +- return BUFFER_ERROR; +- } ++ /* Catch the case where there may be the remainder of a fragmented ++ * handshake message and the next handshake message in the same ++ * record. */ ++ if (inputLength > pendSz) ++ inputLength = pendSz; + + XMEMCPY(ssl->arrays->pendingMsg + ssl->arrays->pendingMsgOffset, + input + *inOutIdx, inputLength); +@@ -9790,13 +9793,11 @@ static int DoHandShakeMsg(WOLFSSL* ssl, byte* input, word32* inOutIdx, + + if (ssl->arrays->pendingMsgOffset == ssl->arrays->pendingMsgSz) + { +- word32 idx = 0; ++ word32 idx = HANDSHAKE_HEADER_SZ; + ret = DoHandShakeMsgType(ssl, +- ssl->arrays->pendingMsg +- + HANDSHAKE_HEADER_SZ, ++ ssl->arrays->pendingMsg, + &idx, ssl->arrays->pendingMsgType, +- ssl->arrays->pendingMsgSz +- - HANDSHAKE_HEADER_SZ, ++ ssl->arrays->pendingMsgSz - idx, + ssl->arrays->pendingMsgSz); + #ifdef WOLFSSL_ASYNC_CRYPT + if (ret == WC_PENDING_E) { +diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c +index e234253..5cdeae5 100644 +--- a/wolfcrypt/src/asn.c ++++ b/wolfcrypt/src/asn.c +@@ -19,6 +19,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + ++#include + + #ifdef HAVE_CONFIG_H + #include +@@ -61,6 +62,7 @@ ASN Options: + #include + #include + #include ++#include + + #include + #include +@@ -6346,7 +6348,10 @@ int wc_DerToPemEx(const byte* der, word32 derSz, byte* output, word32 outSz, + /* USER RSA ifdef portions used instead of refactor in consideration for + possible fips build */ + /* Write a public RSA key to output */ +-static int SetRsaPublicKey(byte* output, RsaKey* key, ++#if !defined(WOLFSSL_SGX_ATTESTATION) ++static ++#endif ++int SetRsaPublicKey(byte* output, RsaKey* key, + int outLen, int with_header) + { + #ifdef WOLFSSL_SMALL_STACK +@@ -6710,6 +6715,20 @@ typedef struct DerCert { + byte extKeyUsage[MAX_EXTKEYUSAGE_SZ]; /* Extended Key Usage extension */ + byte certPolicies[MAX_CERTPOL_NB*MAX_CERTPOL_SZ]; /* Certificate Policies */ + #endif ++#ifdef WOLFSSL_SGX_ATTESTATION ++ byte iasSigCACert[2048]; ++ byte iasSigCert[2048]; ++ byte iasSig[2048]; ++ byte iasAttestationReport[2048]; ++ byte quote[2048]; ++ byte pckCrt[2048]; ++ byte pckSignChain[4096]; ++ byte tcbInfo[4096]; ++ byte tcbSignChain[4096]; ++ byte qeIdentity[1024]; ++ byte rootCaCrl[1024]; ++ byte pckCrl[1024]; ++#endif + #ifdef WOLFSSL_CERT_REQ + byte attrib[MAX_ATTRIB_SZ]; /* Cert req attributes encoded */ + #endif +@@ -6732,6 +6751,20 @@ typedef struct DerCert { + int extKeyUsageSz; /* encoded ExtendedKeyUsage extension length */ + int certPoliciesSz; /* encoded CertPolicies extension length*/ + #endif ++#ifdef WOLFSSL_SGX_ATTESTATION ++ int iasSigCACertSz; ++ int iasSigCertSz; ++ int iasSigSz; ++ int iasAttestationReportSz; ++ int quoteSz; ++ int pckCrtSz; ++ int pckSignChainSz; ++ int tcbInfoSz; ++ int tcbSignChainSz; ++ int qeIdentitySz; ++ int rootCaCrlSz; ++ int pckCrlSz; ++#endif + #ifdef WOLFSSL_ALT_NAMES + int altNamesSz; /* encoded AltNames extension length */ + #endif +@@ -7104,13 +7137,26 @@ static int SetValidity(byte* output, int daysValid) + + /* subtract 1 day for more compliance */ + local.tm_mday -= 1; ++#if !defined(WOLFSSL_SGX_ATTESTATION) + normalTime = mktime(&local); ++#endif + RebuildTime(&normalTime, &local); + + /* adjust */ + local.tm_year += 1900; + local.tm_mon += 1; + ++#ifdef WOLFSSL_SGX_ATTESTATION ++ /* To work around the abscence of a trusted time source in SGX, we ++ hard-code the certificate validity period. */ ++ bzero(&local, sizeof(local)); ++ local.tm_year = 2020; ++ local.tm_mday = 14; ++ local.tm_wday = 6; /* 6 is Friday */ ++ local.tm_mon = 1; /* 1 is February */ ++ local.tm_hour = 9; ++#endif ++ + SetTime(&local, before + beforeSz); + beforeSz += ASN_GEN_TIME_SZ; + +@@ -7121,13 +7167,24 @@ static int SetValidity(byte* output, int daysValid) + + /* add daysValid */ + local.tm_mday += daysValid; ++#if !defined(WOLFSSL_SGX_ATTESTATION) + normalTime = mktime(&local); ++#endif + RebuildTime(&normalTime, &local); + + /* adjust */ + local.tm_year += 1900; + local.tm_mon += 1; + ++#ifdef WOLFSSL_SGX_ATTESTATION ++ bzero(&local, sizeof(local)); ++ local.tm_year = 2030; ++ local.tm_mday = 14; ++ local.tm_wday = 5; /* 5 is Thursday */ ++ local.tm_mon = 1; /* 1 is February */ ++ local.tm_hour = 9; ++#endif ++ + SetTime(&local, after + afterSz); + afterSz += ASN_GEN_TIME_SZ; + +@@ -7445,7 +7502,16 @@ static int SetKeyUsage(byte* output, word32 outSz, word16 input) + ku, idx); + } + +-static int SetOjectIdValue(byte* output, word32 outSz, int* idx, ++#if !defined(WOLFSSL_SGX_ATTESTATION) ++static ++#endif ++int SetOjectIdValue(byte* output, word32 outSz, int* idx, ++ const byte* oid, word32 oidSz); ++ ++#if !defined(WOLFSSL_SGX_ATTESTATION) ++static ++#endif ++int SetOjectIdValue(byte* output, word32 outSz, int* idx, + const byte* oid, word32 oidSz) + { + /* verify room */ +@@ -7459,6 +7525,53 @@ static int SetOjectIdValue(byte* output, word32 outSz, int* idx, + return 0; + } + ++#ifdef WOLFSSL_SGX_ATTESTATION ++static int SetSGXExt(byte* output, word32 outSz, const byte* oid, int oidSz, const byte *input, word32 length) ++{ ++ byte ext_len[1 + MAX_LENGTH_SZ]; ++ byte ext_enc_len[MAX_LENGTH_SZ]; ++ byte oid_enc[16]; ++ int idx = 0, ext_lenSz; ++ int oid_enc_lenSz = 0; ++ ++ if (output == NULL || input == NULL || oid == NULL) ++ return BAD_FUNC_ARG; ++ ++ ext_lenSz = SetOctetString(length, ext_len); ++ ++ SetLength(length + ext_lenSz, ext_enc_len); ++ ++ SetOjectIdValue(oid_enc, sizeof(oid_enc), &oid_enc_lenSz, oid, oidSz); ++ ++ if (outSz < 3) ++ return BUFFER_E; ++ ++ idx = SetSequence(length + oid_enc_lenSz + ext_lenSz, ++ output); ++ ++ if ((idx + length + oid_enc_lenSz + ext_lenSz) > outSz) ++ return BUFFER_E; ++ ++ /* put oid */ ++ XMEMCPY(output+idx, oid_enc, oid_enc_lenSz); ++ idx += oid_enc_lenSz; ++ ++ /* put encoded len */ ++ /* XMEMCPY(output+idx, ext_enc_len, ext_enc_lenSz); */ ++ /* idx += ext_enc_lenSz; */ ++ ++ /* put octet header */ ++ XMEMCPY(output+idx, ext_len, ext_lenSz); ++ idx += ext_lenSz; ++ ++ /* put value */ ++ XMEMCPY(output+idx, input, length); ++ idx += length; ++ ++ return idx; ++} ++#endif ++ + /* encode Extended Key Usage (RFC 5280 4.2.1.12), return total bytes written */ + static int SetExtKeyUsage(byte* output, word32 outSz, byte input) + { +@@ -8055,6 +8168,103 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, + der->certPoliciesSz = 0; + #endif /* WOLFSSL_CERT_EXT */ + ++#ifdef WOLFSSL_SGX_ATTESTATION ++ if (cert->iasSigCACertSz > 0 && ++ cert->iasSigCertSz > 0 && ++ cert->iasSigSz > 0 && ++ cert->iasAttestationReportSz > 0) { ++ ++// 1.2.840.113741.1337.* ++#define OID(N) {0x2A, 0x86, 0x48, 0x86, 0xF8, 0x4D, 0x8A, 0x39, (N)} ++ ++ unsigned char iasAttestationReportOid[] = OID(0x02); ++ unsigned char iasSigCACertOid[] = OID(0x03); ++ unsigned char iasSigCertOid[] = OID(0x04); ++ unsigned char iasSigOid[] = OID(0x05); ++ ++ der->iasSigCACertSz = SetSGXExt(der->iasSigCACert, sizeof(der->iasSigCACert), ++ iasSigCACertOid, sizeof(iasSigCACertOid), ++ cert->iasSigCACert, cert->iasSigCACertSz); ++ ++ der->iasSigCertSz = SetSGXExt(der->iasSigCert, sizeof(der->iasSigCert), ++ iasSigCertOid, sizeof(iasSigCertOid), ++ cert->iasSigCert, cert->iasSigCertSz); ++ ++ der->iasSigSz = SetSGXExt(der->iasSig, sizeof(der->iasSig), ++ iasSigOid, sizeof(iasSigOid), ++ cert->iasSig, cert->iasSigSz); ++ ++ der->iasAttestationReportSz = SetSGXExt(der->iasAttestationReport, ++ sizeof(der->iasAttestationReport), ++ iasAttestationReportOid, ++ sizeof(iasAttestationReportOid), ++ cert->iasAttestationReport, ++ cert->iasAttestationReportSz); ++ ++ der->extensionsSz += der->iasAttestationReportSz + ++ der->iasSigCACertSz + ++ der->iasSigCertSz + ++ der->iasSigSz; ++ } ++ ++ if (cert->quoteSz > 0 && cert->pckCrtSz > 0 && cert->pckSignChainSz > 0 && ++ cert->tcbInfoSz > 0 && cert->tcbSignChainSz > 0 && cert->qeIdentitySz > 0 && ++ cert->rootCaCrlSz > 0 && cert->pckCrlSz > 0) { ++ ++ const unsigned char quoteOid[] = OID(0x06); ++ der->quoteSz = SetSGXExt(der->quote, sizeof(der->quote), ++ quoteOid, sizeof(quoteOid), ++ cert->quote, cert->quoteSz); ++ assert(der->quoteSz > 0); ++ ++ const unsigned char pckCrtOid[] = OID(0x07); ++ der->pckCrtSz = SetSGXExt(der->pckCrt, sizeof(der->pckCrt), ++ pckCrtOid, sizeof(pckCrtOid), ++ cert->pckCrt, cert->pckCrtSz); ++ assert(der->pckCrtSz > 0); ++ ++ const unsigned char pckSignChainOid[] = OID(0x08); ++ der->pckSignChainSz = SetSGXExt(der->pckSignChain, sizeof(der->pckSignChain), ++ pckSignChainOid, sizeof(pckSignChainOid), ++ cert->pckSignChain, cert->pckSignChainSz); ++ assert(der->pckSignChainSz > 0); ++ ++ const unsigned char tcbInfoOid[] = OID(0x09); ++ der->tcbInfoSz = SetSGXExt(der->tcbInfo, sizeof(der->tcbInfo), ++ tcbInfoOid, sizeof(tcbInfoOid), ++ cert->tcbInfo, cert->tcbInfoSz); ++ assert(der->tcbInfoSz > 0); ++ ++ const unsigned char tcbSignChainOid[] = OID(0x0a); ++ der->tcbSignChainSz = SetSGXExt(der->tcbSignChain, sizeof(der->tcbSignChain), ++ tcbSignChainOid, sizeof(tcbSignChainOid), ++ cert->tcbSignChain, cert->tcbSignChainSz); ++ assert(der->tcbSignChainSz > 0); ++ ++ const unsigned char qeIdentityOid[] = OID(0x0b); ++ der->qeIdentitySz = SetSGXExt(der->qeIdentity, sizeof(der->qeIdentity), ++ qeIdentityOid, sizeof(qeIdentityOid), ++ cert->qeIdentity, cert->qeIdentitySz); ++ assert(der->qeIdentitySz > 0); ++ ++ const unsigned char rootCaCrlOid[] = OID(0x0c); ++ der->rootCaCrlSz = SetSGXExt(der->rootCaCrl, sizeof(der->rootCaCrl), ++ rootCaCrlOid, sizeof(rootCaCrlOid), ++ cert->rootCaCrl, cert->rootCaCrlSz); ++ assert(der->rootCaCrlSz > 0); ++ ++ const unsigned char pckCrlOid[] = OID(0x0d); ++ der->pckCrlSz = SetSGXExt(der->pckCrl, sizeof(der->pckCrl), ++ pckCrlOid, sizeof(pckCrlOid), ++ cert->pckCrl, cert->pckCrlSz); ++ assert(der->pckCrlSz > 0); ++ ++ der->extensionsSz += der->quoteSz + der->pckCrtSz + der->pckSignChainSz + ++ der->tcbInfoSz + der->tcbSignChainSz + der->qeIdentitySz + der->rootCaCrlSz + ++ der->pckCrlSz; ++} ++#endif ++ + /* put extensions */ + if (der->extensionsSz > 0) { + +@@ -8131,6 +8341,88 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey, + return EXTENSIONS_E; + } + #endif /* WOLFSSL_CERT_EXT */ ++#ifdef WOLFSSL_SGX_ATTESTATION ++ if (der->iasSigCACertSz && der->iasSigCertSz && ++ der->iasSigSz && der->iasAttestationReportSz) { ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->iasAttestationReport, der->iasAttestationReportSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->iasSigCACert, der->iasSigCACertSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->iasSigCert, der->iasSigCertSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->iasSig, der->iasSigSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ } ++ ++ if (der->quoteSz > 0 && der->pckCrtSz > 0 && der->pckSignChainSz > 0 && ++ der->tcbInfoSz > 0 && der->tcbSignChainSz > 0 && der->qeIdentitySz > 0 && ++ der->rootCaCrlSz > 0 && der->pckCrlSz > 0) { ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->quote, der->quoteSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->pckCrt, der->pckCrtSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->pckSignChain, der->pckSignChainSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->tcbInfo, der->tcbInfoSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->tcbSignChain, der->tcbSignChainSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->qeIdentity, der->qeIdentitySz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->rootCaCrl, der->rootCaCrlSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++ ++ ret = SetExtensions(der->extensions, sizeof(der->extensions), ++ &der->extensionsSz, ++ der->pckCrl, der->pckCrlSz); ++ if (ret <= 0) ++ return EXTENSIONS_E; ++} ++#endif + } + + der->total = der->versionSz + der->serialSz + der->sigAlgoSz + +diff --git a/wolfssl/internal.h b/wolfssl/internal.h +index 9c77120..3c922dd 100644 +--- a/wolfssl/internal.h ++++ b/wolfssl/internal.h +@@ -1272,7 +1272,7 @@ enum Misc { + + /* max size of a handshake message, currently set to the certificate */ + #ifndef MAX_HANDSHAKE_SZ +- #define MAX_HANDSHAKE_SZ MAX_CERTIFICATE_SZ ++ #define MAX_HANDSHAKE_SZ ((MAX_CERTIFICATE_SZ) * 4) + #endif + + #ifndef SESSION_TICKET_LEN +diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h +index b730846..870ffdb 100644 +--- a/wolfssl/wolfcrypt/asn_public.h ++++ b/wolfssl/wolfcrypt/asn_public.h +@@ -164,6 +164,32 @@ typedef struct Cert { + char certPolicies[CTC_MAX_CERTPOL_NB][CTC_MAX_CERTPOL_SZ]; + word16 certPoliciesNb; /* Number of Cert Policy */ + #endif ++#ifdef WOLFSSL_SGX_ATTESTATION ++ byte iasSigCACert[2048]; ++ int iasSigCACertSz; ++ byte iasSigCert[2048]; ++ int iasSigCertSz; ++ byte iasSig[2048]; ++ int iasSigSz; ++ byte iasAttestationReport[2048]; ++ int iasAttestationReportSz; ++ byte quote[2048]; ++ int quoteSz; ++ byte pckCrt[2048]; ++ int pckCrtSz; ++ byte pckSignChain[4096]; ++ int pckSignChainSz; ++ byte tcbInfo[4096]; ++ int tcbInfoSz; ++ byte tcbSignChain[4096]; ++ int tcbSignChainSz; ++ byte qeIdentity[1024]; ++ int qeIdentitySz; ++ byte rootCaCrl[1024]; ++ int rootCaCrlSz; ++ byte pckCrl[1024]; ++ int pckCrlSz; ++#endif + #ifdef WOLFSSL_CERT_REQ + char challengePw[CTC_NAME_SIZE]; + #endif +@@ -330,6 +356,10 @@ WOLFSSL_API int wc_CreatePKCS8Key(byte* out, word32* outSz, + */ + WOLFSSL_API int wc_GetTime(void* timePtr, word32 timeSize); + ++#ifdef WOLFSSL_SGX_ATTESTATION ++WOLFSSL_API int SetRsaPublicKey(byte* output, RsaKey* key, int outLen, int with_header); ++#endif ++ + #ifdef __cplusplus + } /* extern "C" */ + #endif +diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h +index 6254b72..9a20413 100644 +--- a/wolfssl/wolfcrypt/settings.h ++++ b/wolfssl/wolfcrypt/settings.h +@@ -1228,7 +1228,9 @@ extern void uITRON4_free(void *p) ; + #define WC_RSA_BLINDING + #endif + #define SINGLE_THREADED ++#if !defined(WOLFSSL_SGX_ATTESTATION) + #define NO_ASN_TIME /* can not use headers such as windows.h */ ++#endif + #define HAVE_AESGCM + #define USE_CERT_BUFFERS_2048 + #define USE_FAST_MATH -- GitLab