occlum/demos/remote_attestation/lib/src/ra_quote.cpp
Junxian Xiao 86d11e9d44 Refactor the remote attestation demo
This commits consists of three major changes:

1. Support a new interface to get the base64 quote only.
This is useful in the case that application sends the quote
to service provider server and get the final IAS report there.
The application itself doesn't depend on IAS in this case.

2. Improve the C++ programming style. Now, we only provide
C++ classes and limited C APIs(for configuration and sgx device).

3. Use the more general keywords as names prefix.

Signed-off-by: Junxian Xiao <junxian.xjx@antfin.com>
2020-06-23 16:59:33 +08:00

210 lines
6.2 KiB
C++

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#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*, &quote_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(&quote_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