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) 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 "BINARY dir " ${CMAKE_CURRENT_BINARY_DIR})
MESSAGE(STATUS "SOURCE dir " ${CMAKE_CURRENT_SOURCE_DIR}) MESSAGE(STATUS "SOURCE dir " ${CMAKE_CURRENT_SOURCE_DIR})
SET(SGXSDK_INSTALL_DIR /opt/intel/sgxsdk) SET(SGXSDK_INSTALL_DIR /opt/intel/sgxsdk)
SET(OCCLUM_INSTALL_DIR /usr/local/occlum/x86_64-linux-musl) 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) FILE(GLOB LIB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/lib/src/*.cpp)
SET(RALIB occlumra) SET(RALIB occlumra)
@ -33,14 +34,14 @@ FILE(GLOB APP_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/app/*.cpp)
ADD_EXECUTABLE(${DEMOAPP} ${APP_SRCS}) ADD_EXECUTABLE(${DEMOAPP} ${APP_SRCS})
TARGET_INCLUDE_DIRECTORIES( TARGET_INCLUDE_DIRECTORIES(
${DEMOAPP} PUBLIC ${DEMOAPP} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/app ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/lib/include ${CMAKE_CURRENT_SOURCE_DIR}/lib/include
${SGXSDK_INSTALL_DIR}/include ${SGXSDK_INSTALL_DIR}/include
${OCCLUM_INSTALL_DIR}/include ${OCCLUM_INSTALL_DIR}/include
) )
TARGET_LINK_LIBRARIES(${DEMOAPP} TARGET_LINK_LIBRARIES(${DEMOAPP}
-L${CMAKE_CURRENT_BINARY_DIR} -l${RALIB} -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 -Wl,-rpath=${CMAKE_CURRENT_BINARY_DIR}:${OCCLUM_INSTALL_DIR}/lib
) )
ADD_DEPENDENCIES(${DEMOAPP} ${RALIB}) 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 **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 <string>
#include "sofaenclave/common/error.h" #include "tee/common/error.h"
#include "sofaenclave/common/log.h" #include "tee/common/log.h"
#include "sofaenclave/ra_conf.h" #include "tee/ra_conf_api.h"
constexpr char kConfValueEnable[] = "enable";
constexpr char kConfValueDisable[] = "disable";
constexpr char kConfValueTrue[] = "true";
constexpr char kConfValueFalse[] = "false";
constexpr char kRaConf[] = "ra_config.json"; 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 kConfIasAccessKey[] = "ias_access_key";
constexpr char kConfSPID[] = "enclave_spid"; constexpr char kConfSPID[] = "enclave_spid";
#define RA_CONF_STR(name) SofaeConfGetStr(kRaConf, name) #define RA_CONF_STR(name) TeeConfGetStr(kRaConf, name)
#define RA_CONF_INT(name, value) SofaeConfGetInt(kRaConf, name, value) #define RA_CONF_FILE(name) TeeConfGetStr(kRaConf, name)
#define RA_CONF_ARRARY(name, value) SofaeConfGetStrArray(kRaConf, name, value)
#endif // REMOTE_ATTESTATION_RA_CONFIG_H_ #endif // REMOTE_ATTESTATION_RA_CONFIG_H_

@ -1,67 +1,28 @@
#include <cstring>
#include <string> #include <string>
#include "./ra_config.h" #include "app/ra_config.h"
#include "sofaenclave/ra_manager.h" #include "tee/ra_quote.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;
}
int main() { int main() {
printf("Remote attestation testing ...\n"); printf("Remote attestation testing ...\n");
std::string endpoint = RA_CONF_STR(kConfIasServer); // Don't need to set IAS key/cert when we used accesskey authentication
std::string cert = RA_CONF_STR(kConfIasCert); RaIasServerCfg ias_server;
std::string key = RA_CONF_STR(kConfIasKey); ias_server.endpoint = RA_CONF_STR(kConfIasServer);
std::string access_key = RA_CONF_STR(kConfIasAccessKey); ias_server.accesskey = RA_CONF_STR(kConfIasAccessKey);
std::string spid_str = RA_CONF_STR(kConfSPID); std::string spid = RA_CONF_STR(kConfSPID);
if (spid_str.empty()) { // 64Byts report data for adding some project special things if necessary
printf("Please specify the right SPID in configuration file!\n"); sgx_report_data_t report_data = {0};
return -1;
}
SofaeServerCfg ias_server = {endpoint, cert, key, access_key}; ra::occlum::RaEnclaveQuote ra;
SofaeEnclaveQuote quote = {0}; ra::occlum::RaIasReport ias_report;
SofaeQuoteArgs quote_args = {0}; int ret = ra.GetEnclaveIasReport(ias_server, spid, report_data, &ias_report);
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);
if (ret) { 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 { } else {
printf("Test getting quote and fetching report successfully!\n"); printf("Test getting quote and fetching report successfully!\n");
} }
return ret; return ret;
} }

@ -1,108 +1,144 @@
#!/usr/bin/env bash #!/usr/bin/env bash
export CC=occlum-gcc
export CXX=occlum-g++
THISDIR="$(dirname $(readlink -f $0))" THISDIR="$(dirname $(readlink -f $0))"
INSTALLDIR="/usr/local/occlum/x86_64-linux-musl" 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" DEPSDIR="$THISDIR/deps"
BUILDMODE="Release" ALL_COMPONENTS="openssl libcurl demo"
[ "$1" == "--debug" ] && BUILDMODE="Debug" 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 LOG_DEBUG() {
OPENSSLDIR="${DEPSDIR}/openssl" echo -e "\033[36m$@\033[0m"
if [ ! -d "$OPENSSLDIR" ] ; then }
echo "Downloading openssl ..."
cd "$DEPSDIR" && \ LOG_INFO() {
wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1.tar.gz && \ echo -e "\033[32m$@\033[0m"
tar -xvf OpenSSL_1_1_1.tar.gz && \ }
mv openssl-OpenSSL_1_1_1 openssl && \
echo "Download openssl successfully" || exit 1 LOG_ERROR() {
echo -e "\033[31m$@\033[0m"
}
ERROR_EXIT() {
LOG_ERROR "$@" && exit 1
}
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 else
echo "The openssl code is already existent" LOG_INFO "[READY] $pkg"
fi fi
# Download curl 7.29.0 # Prepare the source code directory
CURLDIR="${DEPSDIR}/curl" if [ ! -f $dst/$flag ] ; then
if [ ! -d "$CURLDIR" ] ; then LOG_DEBUG "Preparing source code: $dst ..."
echo "Downloading curl ..." mkdir -p $dst && \
cd "$DEPSDIR" && \ tar -xvf $pkg -C $dst --strip-components 1 >/dev/null || \
wget https://github.com/curl/curl/archive/curl-7_70_0.tar.gz && \ ERROR_EXIT "Fail to extract archive file $pkg"
tar -xvf curl-7_70_0.tar.gz && \ touch $dst/$flag && \
mv curl-curl-7_70_0 curl && \ LOG_DEBUG "Prepare $(basename $dst) source code successfully"
echo "Download curl successfully" || exit 1
else else
echo "The curl code is already existent" LOG_INFO "[READY] $dst"
fi fi
}
# Download other dependencies openssl_check() {
CPPCODECDIR="${DEPSDIR}/cppcodec" [ -f "$INSTALLDIR/lib/libcrypto.so" ] || return 1
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
openssl_build() {
# Build and install openssl cd "$DEPSDIR/$OPENSSLDIR" && \
if [ ! -f "$INSTALLDIR/lib/libcrypto.so" ] ; then CC=$OCCLUMCC CXX=$OCCLUMCXX \
echo "Building openssl ..." ./config --prefix=$INSTALLDIR \
cd "$OPENSSLDIR" && \
CC=occlum-gcc ./config \
--prefix=$INSTALLDIR \
--openssldir=/usr/local/occlum/ssl \ --openssldir=/usr/local/occlum/ssl \
--with-rand-seed=rdcpu \ --with-rand-seed=rdcpu \
no-zlib no-async no-tests && \ no-zlib no-async no-tests && \
make -j${nproc} && \ make -j && make install
sudo make install && \ }
echo "Build openssl successfully" || exit 1
else
echo "The openssl library is aleady existent"
fi
# Build and install libcurl libcurl_check() {
if [ ! -f "$INSTALLDIR/lib/libcurl.so" ] ; then [ -f "$INSTALLDIR/lib/libcurl.so" ] || return 1
cd "$CURLDIR" }
libcurl_build() {
cd "$DEPSDIR/$CURLDIR"
if [ ! -f ./configure ] ; then if [ ! -f ./configure ] ; then
echo "Building configure file ..." LOG_DEBUG "Building configure file ..."
./buildconf || exit 1 ./buildconf || exit 1
fi fi
echo "Building curl ..." CC=$OCCLUMCC CXX=$OCCLUMCXX \
CC=occlum-gcc CXX=occlum-g++ ./configure \ ./configure \
--prefix=$INSTALLDIR \ --prefix=$INSTALLDIR \
--with-ssl=$INSTALLDIR \ --with-ssl=$INSTALLDIR \
--without-zlib && \ --without-zlib && \
make -j${nproc} && \ make -j && make install
sudo make install && \ }
echo "Build curl successfully" || exit 1
else demo_check() {
echo "The curl library is aleady existent" 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 fi
# Build the remote attestation library and demo application # Build specified component or all by default
echo "Build demo source code" BUILD_COMPONENTS="${1:-$ALL_COMPONENTS}"
cd "$THISDIR" && rm -rf ./build && mkdir -p build
cd build && \ # Download all components once here together
cmake -DCMAKE_CXX_COMPILER=occlum-g++ -DBUILD_MODE=${BUILDMODE} ../ && \ mkdir -p $DEPSDIR && cd $DEPSDIR || exit 1
make -j$(nproc) 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_ #ifndef REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_TYPE_H_
#define REMOTE_ATTESTATION_LIB_INCLUDE_SOFAENCLAVE_COMMON_TYPE_H_ #define REMOTE_ATTESTATION_LIB_INCLUDE_TEE_COMMON_TYPE_H_
#include <string> #include <string>
@ -10,10 +10,12 @@
#define RCAST(t, v) reinterpret_cast<t>((v)) #define RCAST(t, v) reinterpret_cast<t>((v))
#define SCAST(t, v) static_cast<t>((v)) #define SCAST(t, v) static_cast<t>((v))
#define CCAST(t, v) const_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)) #define TEE_UNREFERENCED_PARAMETER(p) \
do { \
typedef uint8_t SofaeEnclaveQuote[4096]; static_cast<void>((p)); \
} while (0)
/** /**
* report_data Input report data which will be included in quote data. * report_data Input report data which will be included in quote data.
@ -40,20 +42,20 @@ typedef struct {
uint8_t* as_buf; uint8_t* as_buf;
sgx_quote_t* as_quote; sgx_quote_t* as_quote;
} quote; // output } quote; // output
} SofaeQuoteArgs; } EnclaveQuoteArgs;
/** /**
* endpoint http://xxx.xxx.xxx.xxx:<port> for HTTP IAS proxy server * endpoint https://xxx.xxx.xxx.xxx:<port> for Intel Attestation Service.
* or https://xxx.xxx.xxx.xxx:<port> for IAS server. Key and * cert Service provider certificate file path.
* certificate must be provoided for HTTPS IAS server. * key Service provider private key file path.
* cert Service provider certificate file path * accesskey Service provider access key, see also here:
* key Service provider private key file path * https://api.portal.trustedservices.intel.com/EPID-attestation
*/ */
typedef struct { typedef struct {
std::string endpoint; std::string endpoint;
std::string cert; std::string cert;
std::string key; std::string key;
std::string accesskey; 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 <string>
#include <vector> #include <vector>
#include "sofaenclave/common/error.h" #include "tee/common/error.h"
#include "sofaenclave/common/log.h" #include "tee/common/log.h"
#include "sofaenclave/common/type.h" #include "tee/common/type.h"
#include "sofaenclave/ra_json.h"
#include "sofaenclave/ra_ias.h" #include "tee/ra_ias.h"
#include "tee/ra_json.h"
// use cppcodec/base64 // use cppcodec/base64
#include "cppcodec/base64_rfc4648.hpp" #include "cppcodec/base64_rfc4648.hpp"
using base64 = cppcodec::base64_rfc4648; using base64 = cppcodec::base64_rfc4648;
namespace sofaenclave { namespace ra {
namespace occlum { namespace occlum {
constexpr char kStrEpidPseudonym[] = "epidPseudonym"; constexpr char kStrEpidPseudonym[] = "epidPseudonym";
@ -26,10 +27,6 @@ constexpr char kStrHeaderCaAk[] = "X-IASReport-Signing-Certificate:";
constexpr char kStrHeaderAdvisoryUrl[] = "advisory-url:"; constexpr char kStrHeaderAdvisoryUrl[] = "advisory-url:";
constexpr char kStrHeaderAdvisoryIDs[] = "advisory-ids:"; 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 header_str = header;
std::string ending("\n\r"); 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, static size_t ParseSigrlResponseBody(const void* contents, size_t size,
size_t nmemb, void* response) { size_t nmemb, void* response) {
size_t content_length = size * nmemb; size_t content_length = size * nmemb;
SofaeIasSigrl *sigrl = RCAST(SofaeIasSigrl *, response); RaIasSigrl* sigrl = RCAST(RaIasSigrl*, response);
if (content_length == 0) { if (content_length == 0) {
sigrl->b64_sigrl.clear(); sigrl->b64_sigrl.clear();
SOFAE_LOG_DEBUG("GetSigRL: Empty"); TEE_LOG_DEBUG("GetSigRL: Empty");
} else { } else {
sigrl->b64_sigrl.assign(RCAST(const char*, contents), content_length); sigrl->b64_sigrl.assign(RCAST(const char*, contents), content_length);
SOFAE_LOG_DEBUG("GetSigRL: %s", sigrl->b64_sigrl.c_str()); TEE_LOG_DEBUG("GetSigRL: %s", sigrl->b64_sigrl.c_str());
} }
return content_length; return content_length;
} }
@ -64,7 +61,7 @@ static size_t ParseSigrlResponseHeader(const void* contents, size_t size,
size_t len = size * nmemb; 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; return len;
} }
@ -72,18 +69,19 @@ static size_t ParseReportResponseBody(const void* contents, size_t size,
size_t nmemb, void* response) { 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; 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; rapidjson::Document doc;
if (doc.Parse(body).HasParseError()) { if (!doc.Parse(report->response_body().data()).HasParseError()) {
SOFAE_LOG_ERROR("Fail to parse report response body");
} else {
report->set_epid_pseudonym(JsonConfig::GetStr(doc, kStrEpidPseudonym)); report->set_epid_pseudonym(JsonConfig::GetStr(doc, kStrEpidPseudonym));
report->set_quote_status(JsonConfig::GetStr(doc, kStrQuoteStatus)); report->set_quote_status(JsonConfig::GetStr(doc, kStrQuoteStatus));
report->set_b16_platform_info_blob(JsonConfig::GetStr(doc, kStrPlatform)); report->set_b16_platform_info_blob(JsonConfig::GetStr(doc, kStrPlatform));
report->set_b64_quote_body(JsonConfig::GetStr(doc, kStrQuoteBody)); 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; return content_length;
@ -93,7 +91,7 @@ static size_t ParseReportResponseHeader(const void* contents, size_t size,
size_t nmemb, void* response) { size_t nmemb, void* response) {
size_t len = size * nmemb; size_t len = size * nmemb;
const char* header = RCAST(const char*, contents); const char* header = RCAST(const char*, contents);
IasReport *report = RCAST(IasReport *, response); RaIasReport* report = RCAST(RaIasReport*, response);
if (strncmp(header, kStrHeaderSig, strlen(kStrHeaderSig)) == 0) { if (strncmp(header, kStrHeaderSig, strlen(kStrHeaderSig)) == 0) {
report->set_b64_signature(GetHeaderValue(header, kStrHeaderSig)); report->set_b64_signature(GetHeaderValue(header, kStrHeaderSig));
@ -156,11 +154,7 @@ void RaIasClient::InitIasConnection(const std::string& endpoint) {
server_endpoint_ = endpoint; server_endpoint_ = endpoint;
} }
RaIasClient::RaIasClient(const std::string& endpoint) { RaIasClient::RaIasClient(const RaIasServerCfg& ias_server) {
InitIasConnection(endpoint);
}
RaIasClient::RaIasClient(const SofaeServerCfg& ias_server) {
// Configure the other normal settings firstly. // Configure the other normal settings firstly.
InitIasConnection(ias_server.endpoint); InitIasConnection(ias_server.endpoint);
@ -172,11 +166,11 @@ RaIasClient::RaIasClient(const SofaeServerCfg& ias_server) {
headers_ = curl_slist_append(headers_, header_access_key.c_str()); 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())) { (ias_server.accesskey.empty())) {
const char* ias_cert_key_type = "PEM"; const char* ias_cert_key_type = "PEM";
SOFAE_LOG_DEBUG("IAS cert: %s", ias_server.cert.c_str()); TEE_LOG_DEBUG("IAS cert: %s", ias_server.cert.c_str());
SOFAE_LOG_DEBUG("IAS key: %s", ias_server.key.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_SSLCERT, ias_server.cert.c_str());
curl_easy_setopt(curl_, CURLOPT_SSLKEY, ias_server.key.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, TeeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
std::string* sigrl) { std::string* sigrl) {
if (!curl_) { if (!curl_) {
SOFAE_LOG_ERROR("IAS client is not initialized"); TEE_LOG_ERROR("IAS client is not initialized");
return SOFAE_ERROR_IAS_CLIENT_INIT; return TEE_ERROR_IAS_CLIENT_INIT;
} }
/* Set the URL */ /* Set the URL */
@ -213,11 +207,11 @@ 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], snprintf(tmp_gid_vec.data(), tmp_gid_vec.size(), "%02X%02X%02X%02X", gid[3],
gid[2], gid[1], gid[0]); gid[2], gid[1], gid[0]);
url += std::string(tmp_gid_vec.data()); 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()); curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
/* Set the sigrl request header and body handler function and data */ /* 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_WRITEFUNCTION, ParseSigrlResponseBody);
curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, ParseSigrlResponseHeader); curl_easy_setopt(curl_, CURLOPT_HEADERFUNCTION, ParseSigrlResponseHeader);
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, RCAST(void*, &ias_sigrl)); curl_easy_setopt(curl_, CURLOPT_WRITEDATA, RCAST(void*, &ias_sigrl));
@ -225,8 +219,8 @@ SofaeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
CURLcode rc = curl_easy_perform(curl_); CURLcode rc = curl_easy_perform(curl_);
if (rc != CURLE_OK) { if (rc != CURLE_OK) {
SOFAE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc)); TEE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc));
return SOFAE_ERROR_IAS_CLIENT_CONNECT; return TEE_ERROR_IAS_CLIENT_CONNECT;
} }
if (!ias_sigrl.b64_sigrl.empty()) { if (!ias_sigrl.b64_sigrl.empty()) {
@ -234,37 +228,37 @@ SofaeErrorCode RaIasClient::GetSigRL(const sgx_epid_group_id_t& gid,
try { try {
sigrl_vec = base64::decode(ias_sigrl.b64_sigrl); sigrl_vec = base64::decode(ias_sigrl.b64_sigrl);
} catch (std::exception& e) { } catch (std::exception& e) {
SOFAE_LOG_ERROR("Cannot decode base64 sigrl: %s", e.what()); TEE_LOG_ERROR("Cannot decode base64 sigrl: %s", e.what());
return SOFAE_ERROR_IAS_CLIENT_GETSIGRL; 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, TeeErrorCode RaIasClient::FetchReport(const std::string& quote,
IasReport *ias_report) { RaIasReport* ias_report) {
/* should not be empty is not to use cache */ /* should not be empty is not to use cache */
if (quote.empty()) { if (quote.empty()) {
SOFAE_LOG_ERROR("Invalid base64 quote value"); TEE_LOG_ERROR("Invalid base64 quote value");
return SOFAE_ERROR_PARAMETERS; return TEE_ERROR_PARAMETERS;
} }
if (!curl_) { if (!curl_) {
SOFAE_LOG_ERROR("IAS client is not initialized!"); TEE_LOG_ERROR("IAS client is not initialized!");
return SOFAE_ERROR_IAS_CLIENT_INIT; return TEE_ERROR_IAS_CLIENT_INIT;
} }
/* Set the report url */ /* Set the report url */
std::string url = server_endpoint_ + "/report"; 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()); curl_easy_setopt(curl_, CURLOPT_URL, url.c_str());
/* Set the post data */ /* Set the post data */
SOFAE_LOG_DEBUG("Quote length: %ld", quote.length()); TEE_LOG_DEBUG("Quote length: %ld", quote.length());
std::string b64_quote = base64::encode(RCAST(const char*, quote.c_str()), std::string b64_quote = base64::encode(RCAST(const char*, quote.c_str()),
SCAST(size_t, quote.length())); 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\": \""; std::string post_data = "{\"isvEnclaveQuote\": \"";
post_data += b64_quote; post_data += b64_quote;
post_data += "\"}"; post_data += "\"}";
@ -278,8 +272,8 @@ SofaeErrorCode RaIasClient::FetchReport(const std::string& quote,
CURLcode rc = curl_easy_perform(curl_); CURLcode rc = curl_easy_perform(curl_);
if (rc != CURLE_OK) { if (rc != CURLE_OK) {
SOFAE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc)); TEE_LOG_ERROR("Fail to connect server: %s\n", curl_easy_strerror(rc));
return SOFAE_ERROR_IAS_CLIENT_CONNECT; return TEE_ERROR_IAS_CLIENT_CONNECT;
} }
/* deal with the escaped certificates */ /* deal with the escaped certificates */
@ -292,16 +286,16 @@ SofaeErrorCode RaIasClient::FetchReport(const std::string& quote,
ias_report->set_signing_cert(p_unescape, unescape_len); ias_report->set_signing_cert(p_unescape, unescape_len);
curl_free(p_unescape); curl_free(p_unescape);
} else { } else {
SOFAE_LOG_ERROR("Fail to convert the escaped certificate in response."); TEE_LOG_ERROR("Fail to convert the escaped certificate in response.");
return SOFAE_ERROR_IAS_CLIENT_UNESCAPE; return TEE_ERROR_IAS_CLIENT_UNESCAPE;
} }
} else { } else {
SOFAE_LOG_ERROR("Fail to get quote report from IAS"); TEE_LOG_ERROR("Fail to get quote report from IAS");
return SOFAE_ERROR_IAS_CLIENT_GETREPORT; return TEE_ERROR_IAS_CLIENT_GETREPORT;
} }
return SOFAE_SUCCESS; return TEE_SUCCESS;
} }
} // namespace occlum } // namespace occlum
} // namespace sofaenclave } // namespace ra

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