#include #include #include #include #include #include #include #include #include #include #include #include #include "tee/common/log.h" #include "tee/ra_ias.h" #include "tee/ra_quote.h" #include "cppcodec/base64_rfc4648.hpp" #include "openssl/rand.h" using base64 = cppcodec::base64_rfc4648; #define SGXIOC_GET_EPID_GROUP_ID _IOR('s', 1, sgx_epid_group_id_t) #define SGXIOC_GEN_QUOTE _IOWR('s', 2, EnclaveQuoteArgs) constexpr char kSgxDeviceName[] = "/dev/sgx"; namespace ra { namespace occlum { TeeErrorCode RaEnclaveQuote::SgxDeviceInitQuote(sgx_epid_group_id_t* gid) { int sgx_fd; if ((sgx_fd = open(kSgxDeviceName, O_RDONLY)) < 0) { TEE_LOG_ERROR("Fail to open %s", kSgxDeviceName); return TEE_ERROR_FILE_OPEN; } TeeErrorCode ret = TEE_SUCCESS; if (ioctl(sgx_fd, SGXIOC_GET_EPID_GROUP_ID, gid) < 0) { TEE_LOG_ERROR("Fail to get group id from %s", kSgxDeviceName); ret = TEE_ERROR_SDK_UNEXPECTED; } close(sgx_fd); return ret; } TeeErrorCode RaEnclaveQuote::SgxDeviceGetQuote(EnclaveQuoteArgs* quote_args) { if (!quote_args->quote.as_buf || (quote_args->quote_buf_len == 0)) { TEE_LOG_ERROR("Invalid quote buffer or len"); return TEE_ERROR_PARAMETERS; } int sgx_fd; if ((sgx_fd = open(kSgxDeviceName, O_RDONLY)) < 0) { TEE_LOG_ERROR("Fail to open %s", kSgxDeviceName); return TEE_ERROR_FILE_OPEN; } TeeErrorCode ret = TEE_SUCCESS; int count = 3; while (count--) { if (ioctl(sgx_fd, SGXIOC_GEN_QUOTE, quote_args) == 0) { uint32_t signature_len = quote_args->quote.as_quote->signature_len; TEE_LOG_DEBUG("SgxDeviceGetQuote length=%ld", signature_len); if (signature_len == 0) { TEE_LOG_ERROR("Invalid quote from %s", kSgxDeviceName); ret = TEE_ERROR_SDK_UNEXPECTED; } break; } else if (errno != EAGAIN) { TEE_LOG_ERROR("Fail to get quote from %s", kSgxDeviceName); ret = TEE_ERROR_SDK_UNEXPECTED; break; } else { TEE_LOG_WARN("/dev/sgx is temporarily busy. Try again after 1s."); sleep(1); } } close(sgx_fd); return ret; } uint8_t RaEnclaveQuote::Hex2Dec(const char hex) { if (('0' <= hex) && (hex <= '9')) { return hex - '0'; } else if (('a' <= hex) && (hex <= 'f')) { return hex - 'a' + 10; } else if (('A' <= hex) && (hex <= 'F')) { return hex - 'A' + 10; } else { // Otherwise return zero for none HEX charactor return 0; } } TeeErrorCode RaEnclaveQuote::GetSpidFromHexStr(const std::string& spid_str) { const char* src = spid_str.data(); const int len = sizeof(sgx_spid_t); uint8_t* dst = RCAST(uint8_t*, quote_args_.spid.id); if ((spid_str.empty()) || ((len * 2) != spid_str.length())) { TEE_LOG_ERROR("Empty SPID or Invalid SPID hexstring length!\n"); return TEE_ERROR_PARAMETERS; } for (int i = 0; i < len; i++) { dst[i] = (Hex2Dec(src[i * 2] & 0xFF) << 4) + (Hex2Dec(src[i * 2 + 1] & 0xFF)); } return TEE_SUCCESS; } TeeErrorCode RaEnclaveQuote::GetIasSigRL(const RaIasServerCfg& ias_server) { // Initialize the quote firstly sgx_epid_group_id_t gid = {0}; TEE_CHECK_RETURN(SgxDeviceInitQuote(&gid)); // Try to Get the IAS SigRL, do nothing if failed RaIasClient ias_client(ias_server); std::string sigrl_str; TEE_CHECK_RETURN(ias_client.GetSigRL(gid, &sigrl_str)); // If there is valid SigRL if (!sigrl_str.empty()) { TEE_LOG_DEBUG("Set the SigRL, length=%ld", sigrl_str.size()); quote_args_.sigrl_ptr = RCAST(const uint8_t*, sigrl_str.data()); quote_args_.sigrl_len = sigrl_str.size(); } return TEE_SUCCESS; } TeeErrorCode RaEnclaveQuote::GetEnclaveQuote( const RaIasServerCfg& ias_server, const std::string& spid, const sgx_report_data_t& report_data) { // Firstly, eset all the data constexpr int kMaxQuoteLen = 4096; quote_buf_.resize(kMaxQuoteLen, 0); memset(RCAST(void*, "e_args_), 0, sizeof(EnclaveQuoteArgs)); // Initialize the arguments quote_args_.quote.as_buf = quote_buf_.data(); quote_args_.quote_buf_len = quote_buf_.size(); quote_args_.quote_type = SGX_LINKABLE_SIGNATURE; std::memcpy(RCAST(void*, quote_args_.report_data.d), RCAST(const void*, report_data.d), sizeof(sgx_report_data_t)); RAND_bytes(quote_args_.nonce.rand, sizeof(sgx_quote_nonce_t)); TEE_CHECK_RETURN(GetSpidFromHexStr(spid)); TEE_CHECK_RETURN(GetIasSigRL(ias_server)); // Finally, get quote via ioctl device TEE_CHECK_RETURN(SgxDeviceGetQuote("e_args_)); return TEE_SUCCESS; } TeeErrorCode RaEnclaveQuote::GetEnclaveQuoteB64( const RaIasServerCfg& ias_server, const std::string& spid, const sgx_report_data_t& report_data, std::string* quote_b64) { // Get the enclave quote TEE_CHECK_RETURN(GetEnclaveQuote(ias_server, spid, report_data)); // Convert the quote data to base64 format char* quote_ptr = RCAST(char*, quote_args_.quote.as_quote); size_t quote_len = sizeof(sgx_quote_t) + quote_args_.quote.as_quote->signature_len; std::string tmp_quote_b64 = base64::encode(quote_ptr, quote_len); quote_b64->assign(tmp_quote_b64); TEE_LOG_DEBUG("QuoteB64[%lu]: %s", quote_b64->length(), quote_b64->c_str()); return TEE_SUCCESS; } TeeErrorCode RaEnclaveQuote::GetEnclaveIasReport( const RaIasServerCfg& ias_server, const std::string& spid, const sgx_report_data_t& report_data, RaIasReport* ias_report) { // Get the enclave quote TEE_CHECK_RETURN(GetEnclaveQuote(ias_server, spid, report_data)); // Convert the quote data to a new string for calling IAS client method ra::occlum::RaIasClient ias_client(ias_server); size_t quote_len = sizeof(sgx_quote_t) + quote_args_.quote.as_quote->signature_len; std::string quote_str(RCAST(char*, quote_args_.quote.as_quote), quote_len); TEE_CHECK_RETURN(ias_client.FetchReport(quote_str, ias_report)); return TEE_SUCCESS; } } // namespace occlum } // namespace ra #ifdef __cplusplus extern "C" { #endif TeeErrorCode InitializeQuote(sgx_epid_group_id_t* gid) { return ra::occlum::RaEnclaveQuote::SgxDeviceInitQuote(gid); } TeeErrorCode GetQuote(EnclaveQuoteArgs* quote_args) { return ra::occlum::RaEnclaveQuote::SgxDeviceGetQuote(quote_args); } #ifdef __cplusplus } #endif