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>
This commit is contained in:
Junxian Xiao 2020-06-09 20:52:26 +08:00
parent 6909629241
commit 86d11e9d44
28 changed files with 910 additions and 860 deletions

@ -1,17 +1,18 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
PROJECT(REMOTE_ATTESTATION LANGUAGES CXX VERSION 0.0.1)
MESSAGE(STATUS "Build Mode: ${BUILD_MODE}")
ADD_COMPILE_OPTIONS(-std=c++11)
if(BUILD_MODE STREQUAL "Debug")
ADD_COMPILE_OPTIONS(-O0 -g2 -DDEBUG -UNDEBUG -UEDEBUG)
endif()
PROJECT(REMOTE_ATTESTATION LANGUAGES CXX VERSION 0.1.0)
MESSAGE(STATUS "BINARY dir " ${CMAKE_CURRENT_BINARY_DIR})
MESSAGE(STATUS "SOURCE dir " ${CMAKE_CURRENT_SOURCE_DIR})
SET(SGXSDK_INSTALL_DIR /opt/intel/sgxsdk)
SET(OCCLUM_INSTALL_DIR /usr/local/occlum/x86_64-linux-musl)
if(BUILD_MODE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g2 -DDEBUG -UNDEBUG -UEDEBUG")
endif()
FILE(GLOB LIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/src/*.cpp)
SET(RALIB occlumra)
@ -33,14 +34,14 @@ FILE(GLOB APP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/app/*.cpp)
ADD_EXECUTABLE(${DEMOAPP} ${APP_SRCS})
TARGET_INCLUDE_DIRECTORIES(
${DEMOAPP} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/app
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/lib/include
${SGXSDK_INSTALL_DIR}/include
${OCCLUM_INSTALL_DIR}/include
)
TARGET_LINK_LIBRARIES(${DEMOAPP}
-L${CMAKE_CURRENT_BINARY_DIR} -l${RALIB}
-L${OCCLUM_INSTALL_DIR}/lib -lcurl
-L${OCCLUM_INSTALL_DIR}/lib -lcurl -lcrypto
-Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}:${OCCLUM_INSTALL_DIR}/lib
)
ADD_DEPENDENCIES(${DEMOAPP} ${RALIB})

@ -29,8 +29,8 @@ Build the code in debug mode with "--debug", otherwise it's in Relese mode by de
**Step 2.** Run this demo on Occlum
Build the occlum image and run the RA test application.
Build the occlum image and run the RA test application. Log level is "off" by default.
```
./run_on_occlum.sh
./run_on_occlum.sh [off|trace]
```

@ -3,14 +3,9 @@
#include <string>
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/log.h"
#include "sofaenclave/ra_conf.h"
constexpr char kConfValueEnable[] = "enable";
constexpr char kConfValueDisable[] = "disable";
constexpr char kConfValueTrue[] = "true";
constexpr char kConfValueFalse[] = "false";
#include "tee/common/error.h"
#include "tee/common/log.h"
#include "tee/ra_conf_api.h"
constexpr char kRaConf[] = "ra_config.json";
@ -20,8 +15,7 @@ constexpr char kConfIasKey[] = "ias_sp_key_file";
constexpr char kConfIasAccessKey[] = "ias_access_key";
constexpr char kConfSPID[] = "enclave_spid";
#define RA_CONF_STR(name) SofaeConfGetStr(kRaConf, name)
#define RA_CONF_INT(name, value) SofaeConfGetInt(kRaConf, name, value)
#define RA_CONF_ARRARY(name, value) SofaeConfGetStrArray(kRaConf, name, value)
#define RA_CONF_STR(name) TeeConfGetStr(kRaConf, name)
#define RA_CONF_FILE(name) TeeConfGetStr(kRaConf, name)
#endif // REMOTE_ATTESTATION_RA_CONFIG_H_

@ -1,67 +1,28 @@
#include <cstring>
#include <string>
#include "./ra_config.h"
#include "sofaenclave/ra_manager.h"
static uint8_t 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;
}
}
static std::vector<uint8_t> HexStr2Bytes(const uint8_t* str) {
int len = strlen(RCAST(const char *, str)) / 2;
std::vector<uint8_t> dst(len);
for (int i = 0; i < len; i++) {
dst[i] = (Hex2Dec(str[i * 2] & 0xFF) << 4) +
(Hex2Dec(str[i * 2 + 1] & 0xFF));
}
return dst;
}
#include "app/ra_config.h"
#include "tee/ra_quote.h"
int main() {
printf("Remote attestation testing ...\n");
std::string endpoint = RA_CONF_STR(kConfIasServer);
std::string cert = RA_CONF_STR(kConfIasCert);
std::string key = RA_CONF_STR(kConfIasKey);
std::string access_key = RA_CONF_STR(kConfIasAccessKey);
std::string spid_str = RA_CONF_STR(kConfSPID);
// Don't need to set IAS key/cert when we used accesskey authentication
RaIasServerCfg ias_server;
ias_server.endpoint = RA_CONF_STR(kConfIasServer);
ias_server.accesskey = RA_CONF_STR(kConfIasAccessKey);
std::string spid = RA_CONF_STR(kConfSPID);
if (spid_str.empty()) {
printf("Please specify the right SPID in configuration file!\n");
return -1;
}
// 64Byts report data for adding some project special things if necessary
sgx_report_data_t report_data = {0};
SofaeServerCfg ias_server = {endpoint, cert, key, access_key};
SofaeEnclaveQuote quote = {0};
SofaeQuoteArgs quote_args = {0};
quote_args.quote_type = SGX_LINKABLE_SIGNATURE;
quote_args.quote.as_buf = RCAST(uint8_t *, &quote);
quote_args.quote_buf_len = sizeof(SofaeEnclaveQuote);
std::vector<uint8_t> spid_vec = HexStr2Bytes(
RCAST(const uint8_t *, spid_str.c_str()));
std::memcpy(RCAST(void *, &quote_args.spid.id),
RCAST(const void *, spid_vec.data()), sizeof(quote_args.spid));
sofaenclave::occlum::IasReport ias_report;
int ret = GetQuoteAndFetchIasReport(ias_server, &quote_args, &ias_report);
ra::occlum::RaEnclaveQuote ra;
ra::occlum::RaIasReport ias_report;
int ret = ra.GetEnclaveIasReport(ias_server, spid, report_data, &ias_report);
if (ret) {
printf("Fail to get quote or fetch report, erro code is %x!\n", ret);
printf("Fail to get quote or fetch report, error code is %x!\n", ret);
} else {
printf("Test getting quote and fetching report successfully!\n");
}
return ret;
}

@ -1,108 +1,144 @@
#!/usr/bin/env bash
export CC=occlum-gcc
export CXX=occlum-g++
THISDIR="$(dirname $(readlink -f $0))"
INSTALLDIR="/usr/local/occlum/x86_64-linux-musl"
OCCLUMCC="/usr/local/occlum/bin/occlum-gcc"
OCCLUMCXX="/usr/local/occlum/bin/occlum-g++"
export CC=$OCCLUMCC
export CXX=$OCCLUMCXX
export PATH=$PATH:$INSTALLDIR/bin
export PKG_CONFIG_LIBDIR=$PKG_CONFIG_LIBDIR:$INSTALLDIR/lib
DEPSDIR="$THISDIR/deps"
BUILDMODE="Release"
[ "$1" == "--debug" ] && BUILDMODE="Debug"
ALL_COMPONENTS="openssl libcurl demo"
OPENSSLDIR=openssl
CURLDIR=curl
CPPCODECDIR=cppcodec
RAPIDJSONDIR=rapidjson
mkdir -p $DEPSDIR || exit 1
SHOW_HELP() {
LOG_INFO "Usage: $0 [component-name]\n"
LOG_INFO "Build component in [$ALL_COMPONENTS] or all by default\n"
exit 0
}
# Download OpenSSL 1.1.1
OPENSSLDIR="${DEPSDIR}/openssl"
if [ ! -d "$OPENSSLDIR" ] ; then
echo "Downloading openssl ..."
cd "$DEPSDIR" && \
wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1.tar.gz && \
tar -xvf OpenSSL_1_1_1.tar.gz && \
mv openssl-OpenSSL_1_1_1 openssl && \
echo "Download openssl successfully" || exit 1
else
echo "The openssl code is already existent"
fi
LOG_DEBUG() {
echo -e "\033[36m$@\033[0m"
}
# Download curl 7.29.0
CURLDIR="${DEPSDIR}/curl"
if [ ! -d "$CURLDIR" ] ; then
echo "Downloading curl ..."
cd "$DEPSDIR" && \
wget https://github.com/curl/curl/archive/curl-7_70_0.tar.gz && \
tar -xvf curl-7_70_0.tar.gz && \
mv curl-curl-7_70_0 curl && \
echo "Download curl successfully" || exit 1
else
echo "The curl code is already existent"
fi
LOG_INFO() {
echo -e "\033[32m$@\033[0m"
}
# Download other dependencies
CPPCODECDIR="${DEPSDIR}/cppcodec"
if [ ! -d "$CPPCODECDIR" ] ; then
echo "Downloading cppcodec ..."
cd "$DEPSDIR" && \
wget -O cppcodec-v0.2.tar.gz \
https://github.com/tplgy/cppcodec/archive/v0.2.tar.gz && \
tar -xvf cppcodec-v0.2.tar.gz && \
mv cppcodec-0.2 cppcodec && \
echo "Download cppcodec successfully" || exit 1
else
echo "The cppcodec code is already existent"
fi
RAPIDJSONDIR="${DEPSDIR}/rapidjson"
if [ ! -d "$RAPIDJSONDIR" ] ; then
echo "Downloading rapidjson ..."
cd "$DEPSDIR" && \
wget -O rapidjson-v1.1.0.tar.gz \
https://github.com/Tencent/rapidjson/archive/v1.1.0.tar.gz && \
tar -xvf rapidjson-v1.1.0.tar.gz && \
mv rapidjson-1.1.0 rapidjson && \
echo "Download cppcodec successfully" || exit 1
else
echo "The cppcodec code is already existent"
fi
LOG_ERROR() {
echo -e "\033[31m$@\033[0m"
}
ERROR_EXIT() {
LOG_ERROR "$@" && exit 1
}
# Build and install openssl
if [ ! -f "$INSTALLDIR/lib/libcrypto.so" ] ; then
echo "Building openssl ..."
cd "$OPENSSLDIR" && \
CC=occlum-gcc ./config \
--prefix=$INSTALLDIR \
TRYGET() {
local dst=$1
local url=$2
local pkg=${3:-$(basename $url)}
local flag="./occlum_demo_source"
# Download package tarball
if [ ! -e $pkg ] ; then
LOG_DEBUG "Downloading $pkg ..."
wget $url -O $pkg || ERROR_EXIT "Fail to download $pkg"
else
LOG_INFO "[READY] $pkg"
fi
# Prepare the source code directory
if [ ! -f $dst/$flag ] ; then
LOG_DEBUG "Preparing source code: $dst ..."
mkdir -p $dst && \
tar -xvf $pkg -C $dst --strip-components 1 >/dev/null || \
ERROR_EXIT "Fail to extract archive file $pkg"
touch $dst/$flag && \
LOG_DEBUG "Prepare $(basename $dst) source code successfully"
else
LOG_INFO "[READY] $dst"
fi
}
openssl_check() {
[ -f "$INSTALLDIR/lib/libcrypto.so" ] || return 1
}
openssl_build() {
cd "$DEPSDIR/$OPENSSLDIR" && \
CC=$OCCLUMCC CXX=$OCCLUMCXX \
./config --prefix=$INSTALLDIR \
--openssldir=/usr/local/occlum/ssl \
--with-rand-seed=rdcpu \
no-zlib no-async no-tests && \
make -j${nproc} && \
sudo make install && \
echo "Build openssl successfully" || exit 1
else
echo "The openssl library is aleady existent"
fi
make -j && make install
}
# Build and install libcurl
if [ ! -f "$INSTALLDIR/lib/libcurl.so" ] ; then
cd "$CURLDIR"
libcurl_check() {
[ -f "$INSTALLDIR/lib/libcurl.so" ] || return 1
}
libcurl_build() {
cd "$DEPSDIR/$CURLDIR"
if [ ! -f ./configure ] ; then
echo "Building configure file ..."
LOG_DEBUG "Building configure file ..."
./buildconf || exit 1
fi
echo "Building curl ..."
CC=occlum-gcc CXX=occlum-g++ ./configure \
CC=$OCCLUMCC CXX=$OCCLUMCXX \
./configure \
--prefix=$INSTALLDIR \
--with-ssl=$INSTALLDIR \
--without-zlib && \
make -j${nproc} && \
sudo make install && \
echo "Build curl successfully" || exit 1
else
echo "The curl library is aleady existent"
make -j && make install
}
demo_check() {
return 1 # return false to always build it
}
demo_build() {
cd "$THISDIR"
rm -rf build && mkdir build && cd build && \
cmake ../ \
-DCMAKE_NO_SYSTEM_FROM_IMPORTED=TRUE \
-DCMAKE_CXX_COMPILER=$OCCLUMCXX \
-DBUILD_MODE=${BUILDMODE} && \
make -j $BUILDVERBOSE && \
cp $THISDIR/build/libocclumra.a $INSTALLDIR/lib
}
# Show help menu
[ "$1" == "-h" -o "$1" == "--help" ] && SHOW_HELP
# Check the build mode
BUILDMODE="Release"
BUILDVERBOSE=""
if [ "$1" == "--debug" ] ; then
BUILDMODE="Debug"
BUILDVERBOSE="VERBOSE=1"
shift;
fi
# Build the remote attestation library and demo application
echo "Build demo source code"
cd "$THISDIR" && rm -rf ./build && mkdir -p build
cd build && \
cmake -DCMAKE_CXX_COMPILER=occlum-g++ -DBUILD_MODE=${BUILDMODE} ../ && \
make -j$(nproc)
# Build specified component or all by default
BUILD_COMPONENTS="${1:-$ALL_COMPONENTS}"
# Download all components once here together
mkdir -p $DEPSDIR && cd $DEPSDIR || exit 1
TRYGET $OPENSSLDIR https://github.com/openssl/openssl/archive/OpenSSL_1_1_1.tar.gz
TRYGET $CURLDIR https://github.com/curl/curl/archive/curl-7_70_0.tar.gz
TRYGET $CPPCODECDIR https://github.com/tplgy/cppcodec/archive/v0.2.tar.gz cppcodec-0.2.tar.gz
TRYGET $RAPIDJSONDIR https://github.com/Tencent/rapidjson/archive/v1.1.0.tar.gz rapidjson-1.1.0.tar.gz
for i in $BUILD_COMPONENTS ; do
${i}_check && LOG_INFO "[READY] build check for $i" && continue
LOG_DEBUG "Building $i ..." && ${i}_build && \
LOG_DEBUG "Build $i successfully" || ERROR_EXIT "Fail to build $i"
done

@ -1,39 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_ERROR_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_ERROR_H_
/* We want to use SofaeErrorCode to include the error code from Intel SDK and
* also the SOFAEnclave code, so we use the same unsigned int type here.*/
typedef int SofaeErrorCode;
#define SOFAE_MK_ERROR(x) (0xFFFF0000&((x) << 16))
#define SOFAE_SUCCESS (0x00000000)
#define SOFAE_ERROR_GENERIC SOFAE_MK_ERROR(0x0001)
#define SOFAE_ERROR_PARAMETERS SOFAE_MK_ERROR(0x0002)
#define SOFAE_ERROR_MALLOC SOFAE_MK_ERROR(0x0003)
#define SOFAE_ERROR_ENCLAVE_NOTINITIALIZED SOFAE_MK_ERROR(0x0004)
#define SOFAE_ERROR_REPORT_DATA_SIZE SOFAE_MK_ERROR(0x0005)
#define SOFAE_ERROR_PARSE_CONFIGURATIONS SOFAE_MK_ERROR(0x0006)
#define SOFAE_ERROR_PARSE_COMMANDLINE SOFAE_MK_ERROR(0x0007)
#define SOFAE_ERROR_FILE_OPEN SOFAE_MK_ERROR(0x0101)
#define SOFAE_ERROR_FILE_READ SOFAE_MK_ERROR(0x0102)
#define SOFAE_ERROR_FILE_WRITE SOFAE_MK_ERROR(0x0103)
#define SOFAE_ERROR_CONF_LOAD SOFAE_MK_ERROR(0x0201)
#define SOFAE_ERROR_CONF_NOTEXIST SOFAE_MK_ERROR(0x0202)
#define SOFAE_ERROR_IAS_CLIENT_INIT SOFAE_MK_ERROR(0x0501)
#define SOFAE_ERROR_IAS_CLIENT_CONNECT SOFAE_MK_ERROR(0x0502)
#define SOFAE_ERROR_IAS_CLIENT_GETSIGRL SOFAE_MK_ERROR(0x0503)
#define SOFAE_ERROR_IAS_CLIENT_GETREPORT SOFAE_MK_ERROR(0x0504)
#define SOFAE_ERROR_IAS_CLIENT_UNESCAPE SOFAE_MK_ERROR(0x0505)
#define SOFAE_ERROR_IAS_LOAD_CACHED_REPORT SOFAE_MK_ERROR(0x0506)
#define SOFAE_ERROR_SDK_UNEXPECTED SOFAE_MK_ERROR(0x0FFF)
#define SOFAE_ERROR_CODE(rc) (rc)
#define SOFAE_ERROR_MERGE(ecallcode, retcode) ((ecallcode) | (retcode))
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_ERROR_H_

@ -1,22 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_LOG_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_LOG_H_
#include <string>
extern "C" int printf(const char *fmt, ...);
#ifdef DEBUG
#define SOFAE_LOG_DEBUG(fmt, ...) \
printf("[DEBUG][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#else
#define SOFAE_LOG_DEBUG(fmt, ...)
#endif
#define SOFAE_LOG_INFO(fmt, ...) \
printf("[INFO][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define SOFAE_LOG_WARN(fmt, ...) \
printf("[WARN][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define SOFAE_LOG_ERROR(fmt, ...) \
printf("[ERROR][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_LOG_H_

@ -1,23 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_RA_CONF_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_RA_CONF_H_
#include <string>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
std::string SofaeConfGetStr(const std::string& conf_file, const char* name,
const std::string& default_value = "");
SofaeErrorCode SofaeConfGetStrArray(const std::string& conf_file,
const char* name,
std::vector<std::string>* values);
SofaeErrorCode SofaeConfGetInt(const std::string& conf_file, const char* name,
int* value);
#ifdef __cplusplus
}
#endif
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_RA_CONF_H_

@ -1,27 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_DEVICE_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_DEVICE_H_
#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 <string>
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/type.h"
namespace sofaenclave {
namespace occlum {
SofaeErrorCode SgxDeviceGetGroupID(sgx_epid_group_id_t* gid);
SofaeErrorCode SgxDeviceGetQuote(SofaeQuoteArgs* quote_args);
} // namespace occlum
} // namespace sofaenclave
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_DEVICE_H_

@ -1,46 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_IAS_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_IAS_H_
#include <mutex>
#include <string>
#include "./sgx_uae_epid.h"
#include "./sgx_urts.h"
#include "./sgx_utils.h"
#include "curl/curl.h"
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/type.h"
#include "sofaenclave/ra_report.h"
namespace sofaenclave {
namespace occlum {
class RaIasClient {
public:
/// Connect to the HTTP IAS proxy server
explicit RaIasClient(const std::string& url);
/// Connect to the HTTPS IAS
explicit RaIasClient(const SofaeServerCfg& ias_server);
~RaIasClient();
SofaeErrorCode GetSigRL(const sgx_epid_group_id_t& gid, std::string* sigrl);
SofaeErrorCode FetchReport(const std::string& quote, IasReport* ias_report);
private:
void InitIasConnection(const std::string& url);
CURL* curl_ = NULL;
curl_slist* headers_ = NULL;
std::string server_endpoint_;
static std::mutex init_mutex_;
};
} // namespace occlum
} // namespace sofaenclave
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_IAS_H_

@ -1,67 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_RA_JSON_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_RA_JSON_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "rapidjson/document.h"
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/log.h"
#include "sofaenclave/common/type.h"
namespace sofaenclave {
namespace occlum {
typedef std::shared_ptr<rapidjson::Document> SofaeJsonDocPtr;
typedef std::map<std::string, SofaeJsonDocPtr> SofaeJsonConfMap;
class JsonConfig {
public:
// Gets the singleton UnitTest object.
static JsonConfig* GetInstance();
// To support both rapidjson::Document and rapidjson::Value
template <typename T>
static bool CheckString(const T& conf, const char* name);
template <typename T>
static bool CheckArray(const T& conf, const char* name);
template <typename T>
static bool CheckInt(const T& conf, const char* name);
template <typename T>
static bool CheckObj(const T& conf, const char* name);
template <typename T>
static std::string GetStr(const T& conf, const char* name,
const std::string& default_val = "");
template <typename T>
static SofaeErrorCode GetStrArray(const T& conf, const char* name,
std::vector<std::string>* values);
template <typename T>
static SofaeErrorCode GetInt(const T& conf, const char* name, int* value);
// Load configuration files and then parse and get value(s)
std::string ConfGetStr(const std::string& conf_file, const char* name,
const std::string& default_val = "");
SofaeErrorCode ConfGetStrArray(const std::string& conf_file, const char* name,
std::vector<std::string>* values);
SofaeErrorCode ConfGetInt(const std::string& conf_file, const char* name,
int* value);
private:
// Hide construction functions
JsonConfig() {}
JsonConfig(const JsonConfig&);
void operator=(JsonConfig const&);
std::string GetConfigFilename(const std::string& filename);
SofaeErrorCode LoadConfiguration(const std::string& filename);
SofaeJsonConfMap cfgs_;
};
} // namespace occlum
} // namespace sofaenclave
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_RA_JSON_H_

@ -1,91 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_MANAGER_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_MANAGER_H_
#include <string>
#include "./sgx_quote.h"
#include "./sgx_report.h"
#include "./sgx_tseal.h"
#include "./sgx_urts.h"
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/type.h"
#include "./ra_report.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialization for getting enclave quote
* @param gid return GID for getting SigRL from attestation server
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
SofaeErrorCode InitializeQuote(sgx_epid_group_id_t* gid);
/**
* @brief Get enclave quote for remote attestation
* @param quote_args All the input parameters required by get quote function.
* The output buffer is also in this structure. Please
* refer to the description of it in type.h header file.
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
SofaeErrorCode GetQuote(SofaeQuoteArgs* quote_args);
/**
* @brief Fetch IAS report after ge.
* @param ias_server Specify the IAS server address, certificate and key.
* If HTTP proxy server is used, certificate and key are
* optional.
* @param gid input GID for getting SigRL from attestation server
* @param sigrl The string including the response from IAS
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
SofaeErrorCode FetchIasSigRL(const SofaeServerCfg& ias_server,
const sgx_epid_group_id_t& gid,
std::string* sigrl);
/**
* @brief Fetch IAS report after get quote by GetQuote() function.
* @param ias_server Specify the IAS server address, certificate and key.
* If HTTP proxy server is used, certificate and key are
* optional.
* @param quote The input quote data returned by GetQuote() function
* @param ias_report The output IAS report strings wrapped by IasReport
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
SofaeErrorCode FetchIasReport(const SofaeServerCfg& ias_server,
sgx_quote_t* quote,
SofaeIasReport* ias_report);
/**
* @brief All together to initialize quote, get quote and then fetch IAS report.
* @param ias_server Specify the IAS server address, certificate and key.
* If HTTP proxy server is used, certificate and key are
* optional.
* @param quote_args All the input parameters required by get quote function.
* The output buffer is also in this structure. Please
* refer to the description of it in type.h header file.
* @param ias_report The output IAS report strings wrapped by IasReport
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
SofaeErrorCode GetQuoteAndFetchIasReport(const SofaeServerCfg& ias_server,
SofaeQuoteArgs* quote_args,
SofaeIasReport* ias_report);
#ifdef __cplusplus
}
#endif
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_MANAGER_H_

@ -1,42 +0,0 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_REPORT_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_REPORT_H_
#include <string>
namespace sofaenclave {
namespace occlum {
#define DECLARE_IAS_REPORT_CLASS_MEMBER(x) \
public: \
std::string& x(); \
const std::string& x() const; \
void set_##x(const std::string& value); \
void set_##x(const char* value); \
void set_##x(const char* value, size_t size); \
\
private: \
std::string x##_
class IasReport {
public:
IasReport() {}
~IasReport() {}
DECLARE_IAS_REPORT_CLASS_MEMBER(b64_signature);
DECLARE_IAS_REPORT_CLASS_MEMBER(signing_cert);
DECLARE_IAS_REPORT_CLASS_MEMBER(advisory_url);
DECLARE_IAS_REPORT_CLASS_MEMBER(advisory_ids);
DECLARE_IAS_REPORT_CLASS_MEMBER(response_body);
DECLARE_IAS_REPORT_CLASS_MEMBER(epid_pseudonym);
DECLARE_IAS_REPORT_CLASS_MEMBER(quote_status);
DECLARE_IAS_REPORT_CLASS_MEMBER(b16_platform_info_blob);
DECLARE_IAS_REPORT_CLASS_MEMBER(b64_quote_body);
};
} // namespace occlum
} // namespace sofaenclave
// For coding convenience
using SofaeIasReport = sofaenclave::occlum::IasReport;
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_REPORT_H_

@ -0,0 +1,43 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_ERROR_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_ERROR_H_
/* clang-format off */
/* Define TeeErrorCode to include the error code
* from both Intel SDK and ourself code */
typedef int TeeErrorCode;
#define TEE_MK_ERROR(x) (0xFFFF0000&((x) << 16))
#define TEE_SUCCESS (0x00000000)
#define TEE_ERROR_GENERIC TEE_MK_ERROR(0x0001)
#define TEE_ERROR_PARAMETERS TEE_MK_ERROR(0x0002)
#define TEE_ERROR_MALLOC TEE_MK_ERROR(0x0003)
#define TEE_ERROR_ENCLAVE_NOTINITIALIZED TEE_MK_ERROR(0x0004)
#define TEE_ERROR_REPORT_DATA_SIZE TEE_MK_ERROR(0x0005)
#define TEE_ERROR_PARSE_CONFIGURATIONS TEE_MK_ERROR(0x0006)
#define TEE_ERROR_PARSE_COMMANDLINE TEE_MK_ERROR(0x0007)
#define TEE_ERROR_FILE_OPEN TEE_MK_ERROR(0x0101)
#define TEE_ERROR_FILE_READ TEE_MK_ERROR(0x0102)
#define TEE_ERROR_FILE_WRITE TEE_MK_ERROR(0x0103)
#define TEE_ERROR_CONF_LOAD TEE_MK_ERROR(0x0201)
#define TEE_ERROR_CONF_NOTEXIST TEE_MK_ERROR(0x0202)
#define TEE_ERROR_IAS_CLIENT_INIT TEE_MK_ERROR(0x0501)
#define TEE_ERROR_IAS_CLIENT_CONNECT TEE_MK_ERROR(0x0502)
#define TEE_ERROR_IAS_CLIENT_GETSIGRL TEE_MK_ERROR(0x0503)
#define TEE_ERROR_IAS_CLIENT_GETREPORT TEE_MK_ERROR(0x0504)
#define TEE_ERROR_IAS_CLIENT_UNESCAPE TEE_MK_ERROR(0x0505)
#define TEE_ERROR_IAS_LOAD_CACHED_REPORT TEE_MK_ERROR(0x0506)
#define TEE_ERROR_SDK_UNEXPECTED TEE_MK_ERROR(0x0FFF)
#define TEE_ERROR_CODE(rc) (rc)
#define TEE_ERROR_MERGE(ecallcode, retcode) ((ecallcode) | (retcode))
/* clang-format on */
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_ERROR_H_

@ -0,0 +1,46 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_LOG_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_LOG_H_
#include <string>
extern "C" int printf(const char* fmt, ...);
#ifdef DEBUG
#define TEE_LOG_DEBUG(fmt, ...) \
printf("[DEBUG][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define TEE_LOG_BUFFER(name, ptr, size) \
do { \
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(ptr); \
int len = static_cast<int>((size)); \
printf("Buffer %s[%p], length: %d(0x%x)\n", (name), buffer, len, len); \
for (int i = 0; i < len; i++) { \
if (i && (0 == i % 16)) printf("\n"); \
printf("%02x ", buffer[i]); \
} \
printf("\n"); \
} while (0)
#else
#define TEE_LOG_DEBUG(fmt, ...)
#define TEE_LOG_BUFFER(name, ptr, size)
#endif
#define TEE_LOG_INFO(fmt, ...) \
printf("[INFO][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define TEE_LOG_WARN(fmt, ...) \
printf("[WARN][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define TEE_LOG_ERROR(fmt, ...) \
printf("[ERROR][%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define TEE_LOG_ERROR_TRACE() TEE_LOG_ERROR("[Function] %s", __FUNCTION__)
#define TEE_CHECK_RETURN(r) \
do { \
int ret = (r); \
if (ret != 0) { \
TEE_LOG_ERROR_TRACE(); \
return ret; \
} \
} while (0)
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_LOG_H_

@ -1,5 +1,5 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_TYPE_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_TYPE_H_
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_TYPE_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_TYPE_H_
#include <string>
@ -10,10 +10,12 @@
#define RCAST(t, v) reinterpret_cast<t>((v))
#define SCAST(t, v) static_cast<t>((v))
#define CCAST(t, v) const_cast<t>((v))
#define RCCAST(t, v) reinterpret_cast<t>(const_cast<char*>((v)))
#define SOFAE_UNREFERENCED_PARAMETER(p) static_cast<void>((p))
typedef uint8_t SofaeEnclaveQuote[4096];
#define TEE_UNREFERENCED_PARAMETER(p) \
do { \
static_cast<void>((p)); \
} while (0)
/**
* report_data Input report data which will be included in quote data.
@ -40,20 +42,20 @@ typedef struct {
uint8_t* as_buf;
sgx_quote_t* as_quote;
} quote; // output
} SofaeQuoteArgs;
} EnclaveQuoteArgs;
/**
* endpoint http://xxx.xxx.xxx.xxx:<port> for HTTP IAS proxy server
* or https://xxx.xxx.xxx.xxx:<port> for IAS server. Key and
* certificate must be provoided for HTTPS IAS server.
* cert Service provider certificate file path
* key Service provider private key file path
* endpoint https://xxx.xxx.xxx.xxx:<port> for Intel Attestation Service.
* cert Service provider certificate file path.
* key Service provider private key file path.
* accesskey Service provider access key, see also here:
* https://api.portal.trustedservices.intel.com/EPID-attestation
*/
typedef struct {
std::string endpoint;
std::string cert;
std::string key;
std::string accesskey;
} SofaeServerCfg;
} RaIasServerCfg;
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_TYPE_H_
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_TYPE_H_

@ -0,0 +1,32 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_TEE_RA_CONF_API_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_TEE_RA_CONF_API_H_
#include <string>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
/// Get the string type option in configuration file
std::string TeeConfGetStr(const std::string& conf_file, const char* name,
const std::string& default_value = "");
/// If the value of option is filename in the configuration file,
/// use the function to read the file content and return it as string.
std::string TeeConfGetFileStr(const std::string& conf_file, const char* name,
const std::string& default_value = "");
/// Get the array type option in configuration file
TeeErrorCode TeeConfGetStrArray(const std::string& conf_file, const char* name,
std::vector<std::string>* values);
/// Get the integer type option in configuration file
TeeErrorCode TeeConfGetInt(const std::string& conf_file, const char* name,
int* value);
#ifdef __cplusplus
}
#endif
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_TEE_RA_CONF_API_H_

@ -0,0 +1,88 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_IAS_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_IAS_H_
#include <mutex>
#include <string>
#include "./sgx_uae_epid.h"
#include "./sgx_urts.h"
#include "./sgx_utils.h"
#include "curl/curl.h"
#include "tee/common/error.h"
#include "tee/common/type.h"
#define IAS_REPORT_CLASS_MEMBER(x) \
public: \
std::string& x() { \
return x##_; \
} \
const std::string& x() const { \
return x##_; \
} \
std::string* mutable_##x() { \
return &x##_; \
} \
void set_##x(const std::string& value) { \
x##_ = value; \
} \
void set_##x(const char* value) { \
x##_ = value; \
} \
void set_##x(const char* value, size_t size) { \
x##_ = value; \
} \
\
private: \
std::string x##_
namespace ra {
namespace occlum {
/// Data structure to hold the IAS sigrl API response
typedef struct {
std::string b64_sigrl;
} RaIasSigrl;
/// Data structure to hold the IAS sigrl API response
/// Use this class to simulate the protobuf class
/// don't need to introduce the protobuf dependency
class RaIasReport {
IAS_REPORT_CLASS_MEMBER(b64_signature);
IAS_REPORT_CLASS_MEMBER(signing_cert);
IAS_REPORT_CLASS_MEMBER(advisory_url);
IAS_REPORT_CLASS_MEMBER(advisory_ids);
IAS_REPORT_CLASS_MEMBER(response_body);
IAS_REPORT_CLASS_MEMBER(epid_pseudonym);
IAS_REPORT_CLASS_MEMBER(quote_status);
IAS_REPORT_CLASS_MEMBER(b16_platform_info_blob);
IAS_REPORT_CLASS_MEMBER(b64_quote_body);
};
/// HTTPS client for connecting to IAS
class RaIasClient {
public:
explicit RaIasClient(const RaIasServerCfg& ias_server);
~RaIasClient();
/// api: /sigrl/<gid>
TeeErrorCode GetSigRL(const sgx_epid_group_id_t& gid, std::string* sigrl);
/// api: /report
TeeErrorCode FetchReport(const std::string& quote, RaIasReport* ias_report);
private:
void InitIasConnection(const std::string& url);
CURL* curl_ = NULL;
curl_slist* headers_ = NULL;
std::string server_endpoint_;
static std::mutex init_mutex_;
};
} // namespace occlum
} // namespace ra
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_IAS_H_

@ -0,0 +1,72 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_TEE_RA_JSON_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_TEE_RA_JSON_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "rapidjson/document.h"
#include "tee/common/error.h"
#include "tee/common/log.h"
#include "tee/common/type.h"
namespace ra {
namespace occlum {
typedef std::shared_ptr<rapidjson::Document> TeeJsonDocPtr;
typedef std::map<std::string, TeeJsonDocPtr> TeeJsonConfMap;
class JsonConfig {
public:
// Gets the singleton Unit Test object.
static JsonConfig* GetInstance();
// To support both rapidjson::Document and rapidjson::Value
template <typename T>
static bool CheckString(const T& conf, const char* name);
template <typename T>
static bool CheckArray(const T& conf, const char* name);
template <typename T>
static bool CheckInt(const T& conf, const char* name);
template <typename T>
static bool CheckObj(const T& conf, const char* name);
template <typename T>
static std::string GetStr(const T& conf, const char* name,
const std::string& default_val = "");
template <typename T>
static TeeErrorCode GetStrArray(const T& conf, const char* name,
std::vector<std::string>* values);
template <typename T>
static TeeErrorCode GetInt(const T& conf, const char* name, int* value);
// Load configuration files and then parse and get value(s)
std::string ConfGetStr(const std::string& conf_file, const char* name,
const std::string& default_val = "");
std::string ConfGetFileStr(const std::string& conf_file, const char* name,
const std::string& default_val = "");
TeeErrorCode ConfGetStrArray(const std::string& conf_file, const char* name,
std::vector<std::string>* values);
TeeErrorCode ConfGetInt(const std::string& conf_file, const char* name,
int* value);
private:
// Hide construction functions
JsonConfig() {}
JsonConfig(const JsonConfig&);
void operator=(JsonConfig const&);
std::string ReadStringFile(const std::string& filename);
bool ConfigFileExists(const std::string& filename);
std::string GetConfigFilename(const std::string& filename);
TeeErrorCode LoadConfiguration(const std::string& filename);
TeeJsonConfMap cfgs_;
};
} // namespace occlum
} // namespace ra
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_TEE_RA_JSON_H_

@ -0,0 +1,51 @@
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_QUOTE_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_QUOTE_H_
#include <string>
#include <vector>
#include "./sgx_quote.h"
#include "./sgx_report.h"
#include "./sgx_tseal.h"
#include "./sgx_urts.h"
#include "tee/common/error.h"
#include "tee/common/type.h"
#include "tee/ra_ias.h"
namespace ra {
namespace occlum {
class RaEnclaveQuote {
public:
// The methods that warp the ioctl device interfaces
static TeeErrorCode SgxDeviceInitQuote(sgx_epid_group_id_t* gid);
static TeeErrorCode SgxDeviceGetQuote(EnclaveQuoteArgs* quote_args);
// The methods which are higher wrapper of quote and IasClient together.
TeeErrorCode GetEnclaveQuoteB64(const RaIasServerCfg& ias_server,
const std::string& spid,
const sgx_report_data_t& report_data,
std::string* quote_b64);
TeeErrorCode GetEnclaveIasReport(const RaIasServerCfg& ias_server,
const std::string& spid,
const sgx_report_data_t& report_data,
RaIasReport* ias_report);
private:
uint8_t Hex2Dec(const char hex);
TeeErrorCode GetSpidFromHexStr(const std::string& spid_str);
TeeErrorCode GetIasSigRL(const RaIasServerCfg& ias_server);
TeeErrorCode GetEnclaveQuote(const RaIasServerCfg& ias_server,
const std::string& spid,
const sgx_report_data_t& report_data);
std::vector<uint8_t> quote_buf_;
EnclaveQuoteArgs quote_args_;
};
} // namespace occlum
} // namespace ra
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_QUOTE_H_

@ -0,0 +1,44 @@
/**
* @brief This header file provides the C APIs to use /dev/sgx device directly.
*
* As a C++ language developer, you can also use the C++ classes declared
* in ra_quote.h file. The C++ classes provide more convenient metheds.
*/
#ifndef REMOTE_ATTESTATION_LIB_INCLUDE_RA_QUOTE_API_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_RA_QUOTE_API_H_
#include <string>
#include "tee/common/error.h"
#include "tee/common/type.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialization for getting enclave quote
* @param gid return GID for getting SigRL from attestation server
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
TeeErrorCode InitializeQuote(sgx_epid_group_id_t* gid);
/**
* @brief Get enclave quote for remote attestation
* @param quote_args All the input parameters required by get quote function.
* The output buffer is also in this structure. Please
* refer to the description of it in type.h header file.
* @return Function run successfully or failed
* @retval 0 on success
* @retval Others when failed
*/
TeeErrorCode GetQuote(EnclaveQuoteArgs* quote_args);
#ifdef __cplusplus
}
#endif
#endif // REMOTE_ATTESTATION_LIB_INCLUDE_RA_MANAGER_API_H_

@ -1,67 +0,0 @@
#include <string>
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/log.h"
#include "sofaenclave/ra_device.h"
namespace sofaenclave {
namespace occlum {
#define SGXIOC_GET_EPID_GROUP_ID _IOR('s', 1, sgx_epid_group_id_t)
#define SGXIOC_GEN_QUOTE _IOWR('s', 2, SofaeQuoteArgs)
constexpr char kSgxDeviceName[] = "/dev/sgx";
SofaeErrorCode SgxDeviceGetGroupID(sgx_epid_group_id_t* gid) {
int sgx_fd;
if ((sgx_fd = open(kSgxDeviceName, O_RDONLY)) < 0) {
SOFAE_LOG_ERROR("Fail to open %s", kSgxDeviceName);
return SOFAE_ERROR_FILE_OPEN;
}
SofaeErrorCode ret = SOFAE_SUCCESS;
if (ioctl(sgx_fd, SGXIOC_GET_EPID_GROUP_ID, gid) < 0) {
SOFAE_LOG_ERROR("Fail to get group id from %s", kSgxDeviceName);
ret = SOFAE_ERROR_SDK_UNEXPECTED;
}
close(sgx_fd);
return ret;
}
SofaeErrorCode SgxDeviceGetQuote(SofaeQuoteArgs* quote_args) {
int sgx_fd;
if ((sgx_fd = open(kSgxDeviceName, O_RDONLY)) < 0) {
SOFAE_LOG_ERROR("Fail to open %s", kSgxDeviceName);
return SOFAE_ERROR_FILE_OPEN;
}
SofaeErrorCode ret = SOFAE_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;
SOFAE_LOG_DEBUG("SgxDeviceGetQuote length=%ld", signature_len);
if (signature_len == 0) {
SOFAE_LOG_ERROR("Invalid quote from %s", kSgxDeviceName);
ret = SOFAE_ERROR_SDK_UNEXPECTED;
}
break;
}
else if (errno != EAGAIN) {
SOFAE_LOG_ERROR("Fail to get quote from %s", kSgxDeviceName);
ret = SOFAE_ERROR_SDK_UNEXPECTED;
break;
}
else {
SOFAE_LOG_WARN("/dev/sgx is temporarily busy. Try again after 1s.");
sleep(1);
}
}
close(sgx_fd);
return ret;
}
} // namespace occlum
} // namespace sofaenclave

@ -2,17 +2,18 @@
#include <string>
#include <vector>
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/log.h"
#include "sofaenclave/common/type.h"
#include "sofaenclave/ra_json.h"
#include "sofaenclave/ra_ias.h"
#include "tee/common/error.h"
#include "tee/common/log.h"
#include "tee/common/type.h"
#include "tee/ra_ias.h"
#include "tee/ra_json.h"
// use cppcodec/base64
#include "cppcodec/base64_rfc4648.hpp"
using base64 = cppcodec::base64_rfc4648;
namespace sofaenclave {
namespace ra {
namespace occlum {
constexpr char kStrEpidPseudonym[] = "epidPseudonym";
@ -26,11 +27,7 @@ constexpr char kStrHeaderCaAk[] = "X-IASReport-Signing-Certificate:";
constexpr char kStrHeaderAdvisoryUrl[] = "advisory-url:";
constexpr char kStrHeaderAdvisoryIDs[] = "advisory-ids:";
typedef struct {
std::string b64_sigrl;
} SofaeIasSigrl;
static std::string GetHeaderValue(const char *header, const char *name) {
static std::string GetHeaderValue(const char* header, const char* name) {
std::string header_str = header;
std::string ending("\n\r");
@ -47,14 +44,14 @@ static std::string GetHeaderValue(const char *header, const char *name) {
static size_t ParseSigrlResponseBody(const void* contents, size_t size,
size_t nmemb, void* response) {
size_t content_length = size * nmemb;
SofaeIasSigrl *sigrl = RCAST(SofaeIasSigrl *, response);
RaIasSigrl* sigrl = RCAST(RaIasSigrl*, response);
if (content_length == 0) {
sigrl->b64_sigrl.clear();
SOFAE_LOG_DEBUG("GetSigRL: Empty");
TEE_LOG_DEBUG("GetSigRL: Empty");
} else {
sigrl->b64_sigrl.assign(RCAST(const char *, contents), content_length);
SOFAE_LOG_DEBUG("GetSigRL: %s", sigrl->b64_sigrl.c_str());
sigrl->b64_sigrl.assign(RCAST(const char*, contents), content_length);
TEE_LOG_DEBUG("GetSigRL: %s", sigrl->b64_sigrl.c_str());
}
return content_length;
}
@ -62,28 +59,29 @@ static size_t ParseSigrlResponseBody(const void* contents, size_t size,
static size_t ParseSigrlResponseHeader(const void* contents, size_t size,
size_t nmemb, void* response) {
size_t len = size * nmemb;
const char *header = RCAST(const char *, contents);
const char* header = RCAST(const char*, contents);
SOFAE_LOG_DEBUG("IAS Get SigRL %s", header);
TEE_LOG_DEBUG("IAS Get SigRL %s", header);
return len;
}
static size_t ParseReportResponseBody(const void* contents, size_t size,
size_t nmemb, void* response) {
const char *body = RCAST(const char *, contents);
const char* body = RCAST(const char*, contents);
size_t content_length = size * nmemb;
IasReport *report = RCAST(IasReport *, response);
RaIasReport* report = RCAST(RaIasReport*, response);
report->set_response_body(body, content_length);
// The json response body maybe will be splited into two times
report->mutable_response_body()->append(body, content_length);
rapidjson::Document doc;
if (doc.Parse(body).HasParseError()) {
SOFAE_LOG_ERROR("Fail to parse report response body");
} else {
if (!doc.Parse(report->response_body().data()).HasParseError()) {
report->set_epid_pseudonym(JsonConfig::GetStr(doc, kStrEpidPseudonym));
report->set_quote_status(JsonConfig::GetStr(doc, kStrQuoteStatus));
report->set_b16_platform_info_blob(JsonConfig::GetStr(doc, kStrPlatform));
report->set_b64_quote_body(JsonConfig::GetStr(doc, kStrQuoteBody));
} else if (body[content_length - 1] == '}') {
TEE_LOG_ERROR("Fail to parse report response body");
}
return content_length;
@ -92,8 +90,8 @@ static size_t ParseReportResponseBody(const void* contents, size_t size,
static size_t ParseReportResponseHeader(const void* contents, size_t size,
size_t nmemb, void* response) {
size_t len = size * nmemb;
const char *header = RCAST(const char *, contents);
IasReport *report = RCAST(IasReport *, response);
const char* header = RCAST(const char*, contents);
RaIasReport* report = RCAST(RaIasReport*, response);
if (strncmp(header, kStrHeaderSig, strlen(kStrHeaderSig)) == 0) {
report->set_b64_signature(GetHeaderValue(header, kStrHeaderSig));
@ -156,11 +154,7 @@ void RaIasClient::InitIasConnection(const std::string& endpoint) {
server_endpoint_ = endpoint;
}
RaIasClient::RaIasClient(const std::string& endpoint) {
InitIasConnection(endpoint);
}
RaIasClient::RaIasClient(const SofaeServerCfg& ias_server) {
RaIasClient::RaIasClient(const RaIasServerCfg& ias_server) {
// Configure the other normal settings firstly.
InitIasConnection(ias_server.endpoint);
@ -172,11 +166,11 @@ RaIasClient::RaIasClient(const SofaeServerCfg& ias_server) {
headers_ = curl_slist_append(headers_, header_access_key.c_str());
}
if (curl_ && (ias_server.endpoint.find("https://") != std::string::npos) && \
if (curl_ && (ias_server.endpoint.find("https://") != std::string::npos) &&
(ias_server.accesskey.empty())) {
const char *ias_cert_key_type = "PEM";
SOFAE_LOG_DEBUG("IAS cert: %s", ias_server.cert.c_str());
SOFAE_LOG_DEBUG("IAS key: %s", ias_server.key.c_str());
const char* ias_cert_key_type = "PEM";
TEE_LOG_DEBUG("IAS cert: %s", ias_server.cert.c_str());
TEE_LOG_DEBUG("IAS key: %s", ias_server.key.c_str());
curl_easy_setopt(curl_, CURLOPT_SSLCERT, ias_server.cert.c_str());
curl_easy_setopt(curl_, CURLOPT_SSLKEY, ias_server.key.c_str());
@ -200,11 +194,11 @@ RaIasClient::~RaIasClient() {
}
}
SofaeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
std::string *sigrl) {
TeeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
std::string* sigrl) {
if (!curl_) {
SOFAE_LOG_ERROR("IAS client is not initialized");
return SOFAE_ERROR_IAS_CLIENT_INIT;
TEE_LOG_ERROR("IAS client is not initialized");
return TEE_ERROR_IAS_CLIENT_INIT;
}
/* Set the URL */
@ -213,20 +207,20 @@ SofaeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
snprintf(tmp_gid_vec.data(), tmp_gid_vec.size(), "%02X%02X%02X%02X", gid[3],
gid[2], gid[1], gid[0]);
url += std::string(tmp_gid_vec.data());
SOFAE_LOG_DEBUG("URL: %s", url.c_str());
TEE_LOG_DEBUG("URL: %s", url.c_str());
curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
/* Set the sigrl request header and body handler function and data */
SofaeIasSigrl ias_sigrl;
RaIasSigrl ias_sigrl;
curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, ParseSigrlResponseBody);
curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, ParseSigrlResponseHeader);
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, RCAST(void *, &ias_sigrl));
curl_easy_setopt(curl_, CURLOPT_WRITEHEADER, RCAST(void *, &ias_sigrl));
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, RCAST(void*, &ias_sigrl));
curl_easy_setopt(curl_, CURLOPT_WRITEHEADER, RCAST(void*, &ias_sigrl));
CURLcode rc = curl_easy_perform(curl_);
if (rc != CURLE_OK) {
SOFAE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc));
return SOFAE_ERROR_IAS_CLIENT_CONNECT;
TEE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc));
return TEE_ERROR_IAS_CLIENT_CONNECT;
}
if (!ias_sigrl.b64_sigrl.empty()) {
@ -234,37 +228,37 @@ SofaeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
try {
sigrl_vec = base64::decode(ias_sigrl.b64_sigrl);
} catch (std::exception& e) {
SOFAE_LOG_ERROR("Cannot decode base64 sigrl: %s", e.what());
return SOFAE_ERROR_IAS_CLIENT_GETSIGRL;
TEE_LOG_ERROR("Cannot decode base64 sigrl: %s", e.what());
return TEE_ERROR_IAS_CLIENT_GETSIGRL;
}
sigrl->assign(RCAST(const char *, sigrl_vec.data()), sigrl_vec.size());
sigrl->assign(RCAST(const char*, sigrl_vec.data()), sigrl_vec.size());
}
return SOFAE_SUCCESS;
return TEE_SUCCESS;
}
SofaeErrorCode RaIasClient::FetchReport(const std::string& quote,
IasReport *ias_report) {
TeeErrorCode RaIasClient::FetchReport(const std::string& quote,
RaIasReport* ias_report) {
/* should not be empty is not to use cache */
if (quote.empty()) {
SOFAE_LOG_ERROR("Invalid base64 quote value");
return SOFAE_ERROR_PARAMETERS;
TEE_LOG_ERROR("Invalid base64 quote value");
return TEE_ERROR_PARAMETERS;
}
if (!curl_) {
SOFAE_LOG_ERROR("IAS client is not initialized!");
return SOFAE_ERROR_IAS_CLIENT_INIT;
TEE_LOG_ERROR("IAS client is not initialized!");
return TEE_ERROR_IAS_CLIENT_INIT;
}
/* Set the report url */
std::string url = server_endpoint_ + "/report";
SOFAE_LOG_DEBUG("URL: %s", url.c_str());
TEE_LOG_DEBUG("URL: %s", url.c_str());
curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
/* Set the post data */
SOFAE_LOG_DEBUG("Quote length: %ld", quote.length());
std::string b64_quote = base64::encode(RCAST(const char *, quote.c_str()),
TEE_LOG_DEBUG("Quote length: %ld", quote.length());
std::string b64_quote = base64::encode(RCAST(const char*, quote.c_str()),
SCAST(size_t, quote.length()));
SOFAE_LOG_DEBUG("QUTEO[%lu]: %s", b64_quote.length(), b64_quote.c_str());
TEE_LOG_DEBUG("QUTEO[%lu]: %s", b64_quote.length(), b64_quote.c_str());
std::string post_data = "{\"isvEnclaveQuote\": \"";
post_data += b64_quote;
post_data += "\"}";
@ -273,35 +267,35 @@ SofaeErrorCode RaIasClient::FetchReport(const std::string& quote,
/* Set the report request header and body handler function and data */
curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, ParseReportResponseBody);
curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, ParseReportResponseHeader);
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, RCAST(void *, ias_report));
curl_easy_setopt(curl_, CURLOPT_WRITEHEADER, RCAST(void *, ias_report));
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, RCAST(void*, ias_report));
curl_easy_setopt(curl_, CURLOPT_WRITEHEADER, RCAST(void*, ias_report));
CURLcode rc = curl_easy_perform(curl_);
if (rc != CURLE_OK) {
SOFAE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc));
return SOFAE_ERROR_IAS_CLIENT_CONNECT;
TEE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc));
return TEE_ERROR_IAS_CLIENT_CONNECT;
}
/* deal with the escaped certificates */
std::string signing_cert = ias_report->signing_cert();
if (!signing_cert.empty()) {
int unescape_len = 0;
char *p_unescape = curl_easy_unescape(curl_, signing_cert.data(),
char* p_unescape = curl_easy_unescape(curl_, signing_cert.data(),
signing_cert.length(), &unescape_len);
if (p_unescape && unescape_len) {
ias_report->set_signing_cert(p_unescape, unescape_len);
curl_free(p_unescape);
} else {
SOFAE_LOG_ERROR("Fail to convert the escaped certificate in response.");
return SOFAE_ERROR_IAS_CLIENT_UNESCAPE;
TEE_LOG_ERROR("Fail to convert the escaped certificate in response.");
return TEE_ERROR_IAS_CLIENT_UNESCAPE;
}
} else {
SOFAE_LOG_ERROR("Fail to get quote report from IAS");
return SOFAE_ERROR_IAS_CLIENT_GETREPORT;
TEE_LOG_ERROR("Fail to get quote report from IAS");
return TEE_ERROR_IAS_CLIENT_GETREPORT;
}
return SOFAE_SUCCESS;
return TEE_SUCCESS;
}
} // namespace occlum
} // namespace sofaenclave
} // namespace ra

@ -3,19 +3,20 @@
#include <string>
#include <vector>
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/log.h"
#include "sofaenclave/ra_json.h"
#include "tee/common/error.h"
#include "tee/common/log.h"
#include "tee/ra_json.h"
namespace sofaenclave {
namespace ra {
namespace occlum {
static SofaeErrorCode FsReadString(const std::string& filename,
std::string* str) {
std::string JsonConfig::ReadStringFile(const std::string& filename) {
std::string str;
std::ifstream ifs(filename, std::ios::binary | std::ios::in);
if (!ifs) {
SOFAE_LOG_ERROR("Fail to open file \"%s\"\n", filename.c_str());
return SOFAE_ERROR_FILE_OPEN;
TEE_LOG_ERROR("Fail to open file \"%s\"\n", filename.c_str());
return str;
}
ifs.seekg(0, std::ios::end);
@ -25,15 +26,15 @@ static SofaeErrorCode FsReadString(const std::string& filename,
std::vector<char> buf(length);
ifs.read(buf.data(), length);
if (ifs.fail()) {
SOFAE_LOG_ERROR("Fail to read file \"%s\"\n", filename.c_str());
return SOFAE_ERROR_FILE_READ;
TEE_LOG_ERROR("Fail to read file \"%s\"\n", filename.c_str());
return str;
}
str->assign(buf.data(), length);
return SOFAE_SUCCESS;
str.assign(buf.data(), length);
return str;
}
static bool FsFileExists(const std::string& filename) {
bool JsonConfig::ConfigFileExists(const std::string& filename) {
std::ifstream ifs(filename, std::ios::binary | std::ios::in);
return ifs.good();
}
@ -46,7 +47,7 @@ JsonConfig* JsonConfig::GetInstance() {
template <typename T>
bool JsonConfig::CheckString(const T& conf, const char* name) {
if (!conf.HasMember(name) || !conf[name].IsString()) {
SOFAE_LOG_DEBUG("%s is missed or not string in config file", name);
TEE_LOG_DEBUG("%s is missed or not string in config file", name);
return false;
}
return true;
@ -55,7 +56,7 @@ bool JsonConfig::CheckString(const T& conf, const char* name) {
template <typename T>
bool JsonConfig::CheckArray(const T& conf, const char* name) {
if (!conf.HasMember(name) || !conf[name].IsArray()) {
SOFAE_LOG_DEBUG("%s is missed or not array in config file", name);
TEE_LOG_DEBUG("%s is missed or not array in config file", name);
return false;
}
return true;
@ -64,7 +65,7 @@ bool JsonConfig::CheckArray(const T& conf, const char* name) {
template <typename T>
bool JsonConfig::CheckInt(const T& conf, const char* name) {
if (!conf.HasMember(name) || !conf[name].IsInt()) {
SOFAE_LOG_DEBUG("%s is missed or not integer in config file", name);
TEE_LOG_DEBUG("%s is missed or not integer in config file", name);
return false;
}
return true;
@ -73,7 +74,7 @@ bool JsonConfig::CheckInt(const T& conf, const char* name) {
template <typename T>
bool JsonConfig::CheckObj(const T& conf, const char* name) {
if (!conf.HasMember(name) || !conf[name].IsObject()) {
SOFAE_LOG_DEBUG("%s is missed or not object in config file", name);
TEE_LOG_DEBUG("%s is missed or not object in config file", name);
return false;
}
return true;
@ -84,106 +85,106 @@ std::string JsonConfig::GetStr(const T& conf, const char* name,
const std::string& default_val) {
if (CheckString(conf, name)) {
std::string value = conf[name].GetString();
SOFAE_LOG_DEBUG("%s=%s", name, value.c_str());
TEE_LOG_DEBUG("%s=%s", name, value.c_str());
return value;
} else {
SOFAE_LOG_DEBUG("Not string type, %s=%s[default]", name, default_val);
TEE_LOG_DEBUG("Not string type, %s=%s[default]", name, default_val);
return default_val;
}
}
template <typename T>
SofaeErrorCode JsonConfig::GetStrArray(const T& conf, const char* name,
std::vector<std::string>* values) {
TeeErrorCode JsonConfig::GetStrArray(const T& conf, const char* name,
std::vector<std::string>* values) {
if (CheckArray(conf, name)) {
const rapidjson::Value& val_array = conf[name];
size_t count = val_array.Size();
for (size_t i = 0; i < count; i++) {
if (val_array[i].IsString()) {
std::string val_str = val_array[i].GetString();
SOFAE_LOG_DEBUG("%s[%ld]=%s", name, i, val_str.c_str());
TEE_LOG_DEBUG("%s[%ld]=%s", name, i, val_str.c_str());
values->push_back(val_str);
} else {
SOFAE_LOG_ERROR("Invalid string type in Array");
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
TEE_LOG_ERROR("Invalid string type in Array");
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
}
} else {
SOFAE_LOG_DEBUG("Invalid Array type");
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
TEE_LOG_DEBUG("Invalid Array type");
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
return SOFAE_SUCCESS;
return TEE_SUCCESS;
}
template <typename T>
SofaeErrorCode JsonConfig::GetInt(const T& conf, const char* name, int* value) {
TeeErrorCode JsonConfig::GetInt(const T& conf, const char* name, int* value) {
if (!CheckInt(conf, name)) {
SOFAE_LOG_ERROR("Not integer type: %s", name);
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
TEE_LOG_ERROR("Not integer type: %s", name);
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
*value = conf[name].GetInt();
SOFAE_LOG_DEBUG("%s=%d", name, *value);
return SOFAE_SUCCESS;
TEE_LOG_DEBUG("%s=%d", name, *value);
return TEE_SUCCESS;
}
std::string JsonConfig::GetConfigFilename(const std::string& filename) {
// First priority, the absolute path filename or file in current directory
if (FsFileExists(filename)) {
SOFAE_LOG_DEBUG("Configuration file: %s", filename.c_str());
if (ConfigFileExists(filename)) {
TEE_LOG_DEBUG("Configuration file: %s", filename.c_str());
return filename;
}
// Finally, try to find configuration file in /etc directory
std::string etcpath = "/etc/";
etcpath += filename;
if (FsFileExists(etcpath)) {
SOFAE_LOG_DEBUG("Configuration file: %s", etcpath.c_str());
if (ConfigFileExists(etcpath)) {
TEE_LOG_DEBUG("Configuration file: %s", etcpath.c_str());
return etcpath;
}
// If cannot find configuration file, return empty string
SOFAE_LOG_ERROR("Cannot find configuration file: %s", filename.c_str());
TEE_LOG_ERROR("Cannot find configuration file: %s", filename.c_str());
return "";
}
SofaeErrorCode JsonConfig::LoadConfiguration(const std::string& filename) {
TeeErrorCode JsonConfig::LoadConfiguration(const std::string& filename) {
if (filename.empty()) {
SOFAE_LOG_ERROR("Empty configuration file name");
return SOFAE_ERROR_CONF_NOTEXIST;
TEE_LOG_ERROR("Empty configuration file name");
return TEE_ERROR_CONF_NOTEXIST;
}
std::string config_file = GetConfigFilename(filename);
if (config_file.empty()) {
SOFAE_LOG_ERROR("Fail to find configuration file");
return SOFAE_ERROR_CONF_NOTEXIST;
TEE_LOG_ERROR("Fail to find configuration file");
return TEE_ERROR_CONF_NOTEXIST;
}
std::string config_str;
if (FsReadString(config_file, &config_str) != SOFAE_SUCCESS) {
SOFAE_LOG_ERROR("Fail to read configuration file");
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
std::string config_str = ReadStringFile(config_file);
if (config_str.empty()) {
TEE_LOG_ERROR("Fail to read configuration file");
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
SofaeJsonDocPtr doc(new rapidjson::Document);
TeeJsonDocPtr doc(new rapidjson::Document);
if (doc.get()->Parse(config_str.data()).HasParseError()) {
SOFAE_LOG_ERROR("Fail to parse json configration file");
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
TEE_LOG_ERROR("Fail to parse json configration file");
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
cfgs_.emplace(filename, doc);
SOFAE_LOG_DEBUG("Load configuration file %s successfully", filename.c_str());
return SOFAE_SUCCESS;
TEE_LOG_DEBUG("Load configuration file %s successfully", filename.c_str());
return TEE_SUCCESS;
}
std::string JsonConfig::ConfGetStr(const std::string& conf_file,
const char* name,
const std::string& default_val) {
SOFAE_LOG_DEBUG("Get %s from %s", name, conf_file.c_str());
TEE_LOG_DEBUG("Get %s from %s", name, conf_file.c_str());
if (cfgs_.find(conf_file) == cfgs_.end()) {
if (LoadConfiguration(conf_file) != SOFAE_SUCCESS) {
SOFAE_LOG_DEBUG("Load config failed, %s=%s[default]", name, default_val);
if (LoadConfiguration(conf_file) != TEE_SUCCESS) {
TEE_LOG_DEBUG("Load config failed, %s=%s[default]", name, default_val);
return default_val;
}
}
@ -191,29 +192,37 @@ std::string JsonConfig::ConfGetStr(const std::string& conf_file,
return GetStr(*cfgs_[conf_file].get(), name, default_val);
}
SofaeErrorCode JsonConfig::ConfGetStrArray(const std::string& conf_file,
const char* name,
std::vector<std::string>* values) {
SOFAE_LOG_DEBUG("Get %s from %s", name, conf_file.c_str());
std::string JsonConfig::ConfGetFileStr(const std::string& conf_file,
const char* name,
const std::string& default_val) {
TEE_LOG_DEBUG("Get string from %s", name);
std::string filename = ConfGetStr(conf_file, name, default_val);
return ReadStringFile(filename);
}
TeeErrorCode JsonConfig::ConfGetStrArray(const std::string& conf_file,
const char* name,
std::vector<std::string>* values) {
TEE_LOG_DEBUG("Get %s from %s", name, conf_file.c_str());
if (cfgs_.find(conf_file) == cfgs_.end()) {
if (LoadConfiguration(conf_file) != SOFAE_SUCCESS) {
SOFAE_LOG_DEBUG("Fail to load configuration file");
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
if (LoadConfiguration(conf_file) != TEE_SUCCESS) {
TEE_LOG_DEBUG("Fail to load configuration file");
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
}
return GetStrArray(*cfgs_[conf_file].get(), name, values);
}
SofaeErrorCode JsonConfig::ConfGetInt(const std::string& conf_file,
const char* name, int* value) {
SOFAE_LOG_DEBUG("Get %s from %s", name, conf_file.c_str());
TeeErrorCode JsonConfig::ConfGetInt(const std::string& conf_file,
const char* name, int* value) {
TEE_LOG_DEBUG("Get %s from %s", name, conf_file.c_str());
if (cfgs_.find(conf_file) == cfgs_.end()) {
if (LoadConfiguration(conf_file) != SOFAE_SUCCESS) {
SOFAE_LOG_ERROR("Fail to load configuration file");
return SOFAE_ERROR_PARSE_CONFIGURATIONS;
if (LoadConfiguration(conf_file) != TEE_SUCCESS) {
TEE_LOG_ERROR("Fail to load configuration file");
return TEE_ERROR_PARSE_CONFIGURATIONS;
}
}
@ -221,29 +230,34 @@ SofaeErrorCode JsonConfig::ConfGetInt(const std::string& conf_file,
}
} // namespace occlum
} // namespace sofaenclave
} // namespace ra
#ifdef __cplusplus
extern "C" {
#endif
std::string SofaeConfGetStr(const std::string& conf_file, const char* name,
const std::string& default_val) {
return sofaenclave::occlum::JsonConfig::GetInstance()->ConfGetStr(
conf_file, name, default_val);
std::string TeeConfGetStr(const std::string& conf_file, const char* name,
const std::string& default_val) {
return ra::occlum::JsonConfig::GetInstance()->ConfGetStr(conf_file, name,
default_val);
}
SofaeErrorCode SofaeConfGetStrArray(const std::string& conf_file,
const char* name,
std::vector<std::string>* values) {
return sofaenclave::occlum::JsonConfig::GetInstance()->ConfGetStrArray(
conf_file, name, values);
std::string TeeConfGetFileStr(const std::string& conf_file, const char* name,
const std::string& default_val) {
return ra::occlum::JsonConfig::GetInstance()->ConfGetFileStr(conf_file, name,
default_val);
}
SofaeErrorCode SofaeConfGetInt(const std::string& conf_file, const char* name,
int* value) {
return sofaenclave::occlum::JsonConfig::GetInstance()->ConfGetInt(
conf_file, name, value);
TeeErrorCode TeeConfGetStrArray(const std::string& conf_file, const char* name,
std::vector<std::string>* values) {
return ra::occlum::JsonConfig::GetInstance()->ConfGetStrArray(conf_file, name,
values);
}
TeeErrorCode TeeConfGetInt(const std::string& conf_file, const char* name,
int* value) {
return ra::occlum::JsonConfig::GetInstance()->ConfGetInt(conf_file, name,
value);
}
#ifdef __cplusplus

@ -1,88 +0,0 @@
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include "./sgx_quote.h"
#include "./sgx_tseal.h"
#include "sofaenclave/common/error.h"
#include "sofaenclave/common/log.h"
#include "sofaenclave/common/type.h"
#include "sofaenclave/ra_device.h"
#include "sofaenclave/ra_ias.h"
#include "sofaenclave/ra_manager.h"
// use cppcodec/base64
#include "cppcodec/base64_rfc4648.hpp"
using base64 = cppcodec::base64_rfc4648;
#ifdef __cplusplus
extern "C" {
#endif
SofaeErrorCode InitializeQuote(sgx_epid_group_id_t* gid) {
return sofaenclave::occlum::SgxDeviceGetGroupID(gid);
}
SofaeErrorCode GetQuote(SofaeQuoteArgs* quote_args) {
if (!quote_args->quote.as_buf || (quote_args->quote_buf_len == 0)) {
SOFAE_LOG_ERROR("Invalid quote buffer or len");
return SOFAE_ERROR_PARAMETERS;
}
return sofaenclave::occlum::SgxDeviceGetQuote(quote_args);
}
SofaeErrorCode FetchIasSigRL(const SofaeServerCfg& ias_server,
const sgx_epid_group_id_t& gid,
std::string* sigrl) {
sofaenclave::occlum::RaIasClient ias_client(ias_server);
return ias_client.GetSigRL(gid, sigrl);
}
SofaeErrorCode FetchIasReport(const SofaeServerCfg& ias_server,
sgx_quote_t* quote,
SofaeIasReport* ias_report) {
sofaenclave::occlum::RaIasClient ias_client(ias_server);
std::string quote_str(RCAST(char*, quote),
sizeof(sgx_quote_t) + quote->signature_len);
return ias_client.FetchReport(quote_str, ias_report);
}
SofaeErrorCode GetQuoteAndFetchIasReport(const SofaeServerCfg& ias_server,
SofaeQuoteArgs* quote_args,
SofaeIasReport* ias_report) {
// Initialize the quote firstly
sgx_epid_group_id_t gid = {0};
SofaeErrorCode ret = InitializeQuote(&gid);
if (ret != SOFAE_SUCCESS) {
return ret;
}
// If there is no SigRL, try to fetch it.
if (!quote_args->sigrl_ptr || (quote_args->sigrl_len == 0)) {
std::string sigrl_str;
ret = FetchIasSigRL(ias_server, gid, &sigrl_str);
if (ret != SOFAE_SUCCESS) {
return ret;
}
if (!sigrl_str.empty()) {
quote_args->sigrl_ptr = RCAST(const uint8_t *, sigrl_str.data());
quote_args->sigrl_len = sigrl_str.length();
}
}
// Get the quote, assuming quote buffer is allocated out of this function
ret = GetQuote(quote_args);
if (ret != SOFAE_SUCCESS) {
return ret;
}
// Fetch the IAS report based on the quote output buffer
return FetchIasReport(ias_server, quote_args->quote.as_quote, ias_report);
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1,209 @@
#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

@ -1,26 +0,0 @@
#include <string>
#include "sofaenclave/ra_report.h"
namespace sofaenclave {
namespace occlum {
#define IMPLEMENT_IAS_REPORT_CLASS_MEMBER(x); \
std::string& IasReport::x() { return x##_; } \
const std::string& IasReport::x() const { return x##_; } \
void IasReport::set_##x(const std::string& value) { x##_ = value; } \
void IasReport::set_##x(const char* value) { x##_ = value; } \
void IasReport::set_##x(const char* value, size_t size) { x##_ = value; }
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(b64_signature);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(signing_cert);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(advisory_url);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(advisory_ids);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(response_body);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(epid_pseudonym);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(quote_status);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(b16_platform_info_blob);
IMPLEMENT_IAS_REPORT_CLASS_MEMBER(b64_quote_body);
} // namespace occlum
} // namespace sofaenclave

@ -22,4 +22,5 @@ cp /usr/local/occlum/x86_64-linux-musl/lib/libcurl.so.4 image/lib
occlum build
# 3. Run application
occlum run /bin/$DEMPOAPP
LOG_LEVEL=${1:-off}
OCCLUM_LOG_LEVEL=$LEVEL occlum run /bin/$DEMPOAPP