Skip to content

Commit

Permalink
Switch default to V2 and continue to operate if caching is unavailable (
Browse files Browse the repository at this point in the history
#97)

- Disable caching if there are permissions issues with the caching folder
- Attempt a few more environment variables and add a fallback location for the cache directory
- Change the windows default cache directory to LocalLow
- Updates the Jenkins file for the build pipeline (switches to use OE SDK's docker image)
- Changes the default collateral version to v2
  • Loading branch information
deschuma committed Apr 24, 2020
1 parent 35f155e commit 8152cfd
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 71 deletions.
16 changes: 12 additions & 4 deletions .jenkins/Jenkinsfile
Expand Up @@ -54,6 +54,9 @@ def ACCContainerTest(String label, String version) {
// Run the OE tests from the git repository with the currently
// generated az-dcap-client deb package installed
def task = """
sudo apt-get purge az-dcap-client -y
sudo apt-get update
sudo apt-get install sudo libcurl4-openssl-dev wget -y
cd ${WORKSPACE}/src/Linux
dpkg-buildpackage -us -uc
sudo dpkg -i ${WORKSPACE}/src/az-dcap-client_*_amd64.deb
Expand All @@ -63,7 +66,7 @@ def ACCContainerTest(String label, String version) {
ninja -v
ctest --output-on-failure
"""
oe.ContainerRun("${DOCKER_REGISTRY}/az-dcap-tools-${version}", 'clang-7', task, '--cap-add=SYS_PTRACE --device /dev/sgx:/dev/sgx')
oe.ContainerRun("${DOCKER_REGISTRY}/oetools-full-${version}:latest", "clang-7", task, "--cap-add=SYS_PTRACE --device /dev/sgx:/dev/sgx")
}
}
}
Expand All @@ -79,6 +82,9 @@ def ACCTestOeRelease(String label, String version) {
// Run the OE samples bundled with the published OE package, having
// the currently generated az-dcap-client deb package installed
def task = """
sudo apt-get purge az-dcap-client -y
sudo apt-get update
sudo apt-get install sudo libcurl4-openssl-dev wget -y
cd ${WORKSPACE}/src/Linux
dpkg-buildpackage -us -uc
sudo dpkg -i ${WORKSPACE}/src/az-dcap-client_*_amd64.deb
Expand All @@ -92,7 +98,7 @@ def ACCTestOeRelease(String label, String version) {
make run
done
"""
oe.ContainerRun("${DOCKER_REGISTRY}/az-dcap-tools-${version}", 'clang-7', task, '--cap-add=SYS_PTRACE --device /dev/sgx:/dev/sgx')
oe.ContainerRun("${DOCKER_REGISTRY}/oetools-full-${version}:latest", "clang-7", task, "--cap-add=SYS_PTRACE --device /dev/sgx:/dev/sgx")
}
}
}
Expand Down Expand Up @@ -138,5 +144,7 @@ parallel "ACC1604 SGX1-FLC Container RelWithDebInfo" : { ACCContainerTest('ACC-1
"ACC1804 SGX1-FLC gcc RelWithDebInfo" : { ACCTest('ACC-1804', '18.04', 'gcc', 'RelWithDebInfo') },
"ACC1604 OpenEnclave Release Test" : { ACCTestOeRelease('ACC-1604','16.04') },
"ACC1804 OpenEnclave Release Test" : { ACCTestOeRelease('ACC-1804','18.04') },
"ACCWin DCAP Debug Test" : { DCAPBuildTest('SGXFLC-Windows', 'Debug') },
"ACCWin DCAP Release Test" : { DCAPBuildTest('SGXFLC-Windows', 'Release') }
"ACCWin 2016 DCAP Debug Test" : { DCAPBuildTest('SGXFLC-Windows-2016-DCAP', 'Debug') },
"ACCWin 2016 DCAP Release Test" : { DCAPBuildTest('SGXFLC-Windows-2016-DCAP', 'Release') },
"ACCWin 2019 DCAP Debug Test" : { DCAPBuildTest('SGXFLC-Windows-2019-DCAP', 'Debug') },
"ACCWin 2019 DCAP Release Test" : { DCAPBuildTest('SGXFLC-Windows-2019-DCAP', 'Release') }
68 changes: 45 additions & 23 deletions src/Linux/local_cache.cpp
Expand Up @@ -21,7 +21,11 @@ constexpr uint16_t CACHE_V1 = 1;

constexpr locale_t NULL_LOCALE = reinterpret_cast<locale_t>(0);

static std::string g_cache_dirname;
static std::string g_cache_dirname = "";
static std::mutex cache_directory_lock;

static constexpr size_t CACHE_LOCATIONS = 5;
static const char *cache_locations[CACHE_LOCATIONS];

//
// Various exception helpers
Expand Down Expand Up @@ -180,41 +184,57 @@ static void make_dir(const std::string& dirname, mode_t mode)
}
}

static void load_cache_locations()
{
cache_locations[0] = ::getenv("AZDCAP_CACHE");
cache_locations[1] = ::getenv("XDG_CACHE_HOME");
cache_locations[2] = ::getenv("HOME");
cache_locations[3] = ::getenv("TMPDIR");

// The fallback location isn't an environment variable
cache_locations[4] = "/tmp/";
}

static void init_callback()
{
const char * env_home = ::getenv("HOME");
const char * env_azdcap_cache = ::getenv("AZDCAP_CACHE");
load_cache_locations();
const std::string application_name("/.az-dcap-client/");

std::string dirname;
std::string all_locations;

if (env_azdcap_cache != 0 && (strcmp(env_azdcap_cache,"") != 0))
{
dirname = env_azdcap_cache;
}
else if (env_home != 0 && (strcmp(env_home,"") != 0))
// Try the cache locations in order
for (auto &cache_location : cache_locations)
{
dirname = std::string(env_home);
if (cache_location != 0 && strcmp(cache_location, "") != 0)
{
dirname = cache_location + application_name;
make_dir(dirname, 0777);
g_cache_dirname = dirname;
return;
}
}
else

// Collect all of the environment variables for the error message
std::string environment_variable_list;
for (size_t i = 0; i < CACHE_LOCATIONS - 1; ++i)
{
// Throwing exception if the expected HOME
// environment variable is not defined.

throw std::runtime_error("HOME and AZDCAPCACHE environment variables not defined");
environment_variable_list += cache_locations[i];
if (i != CACHE_LOCATIONS - 2)
{
environment_variable_list += ",";
}
}

dirname += application_name;

make_dir(dirname, 0700);

g_cache_dirname = dirname;
throw std::runtime_error("No cache location was found. Please define one of the following environment variables to enable caching: " + environment_variable_list);
}

static void init()
{
static std::once_flag init_flag;
std::call_once(init_flag, init_callback);
std::lock_guard<std::mutex> lock(cache_directory_lock);
if (g_cache_dirname == "")
{
init_callback();
}
}

static std::string sha256(size_t data_size, const void* data)
Expand Down Expand Up @@ -244,6 +264,7 @@ static std::string sha256(const std::string& input)

static std::string get_file_name(const std::string& id)
{
std::lock_guard<std::mutex> lock(cache_directory_lock);
return g_cache_dirname + "/" + sha256(id);
}

Expand Down Expand Up @@ -288,6 +309,7 @@ void local_cache_clear()
{
init();

std::lock_guard<std::mutex> lock(cache_directory_lock);
constexpr int MAX_FDS = 4;
int rc = nftw(g_cache_dirname.c_str(), delete_path, MAX_FDS, FTW_DEPTH);
if (rc != 0)
Expand All @@ -314,7 +336,7 @@ void local_cache_add(

file cache_entry;
cache_entry.throw_on_error();
cache_entry.open(get_file_name(id), O_CREAT | O_WRONLY, 0600);
cache_entry.open(get_file_name(id), O_CREAT | O_WRONLY, 0666);
cache_entry.truncate();
cache_entry.write(&header, sizeof(header));
cache_entry.write(data, data_size);
Expand Down
124 changes: 94 additions & 30 deletions src/UnitTests/test_quote_prov.cpp
Expand Up @@ -11,6 +11,7 @@
#include <ctime>
#include <memory>
#include <sstream>
#include <sys/stat.h>

#if defined(__LINUX__)
#include <tgmath.h>
Expand All @@ -21,6 +22,12 @@
#include <windows.h>
#endif

#if defined __LINUX__
typedef void * libary_type_t;
#else
typedef HINSTANCE libary_type_t;
#endif

typedef quote3_error_t (*sgx_ql_get_quote_config_t)(
const sgx_ql_pck_cert_id_t* p_pck_cert_id,
sgx_ql_config_t** pp_quote_config);
Expand Down Expand Up @@ -73,6 +80,22 @@ static sgx_ql_get_root_ca_crl_t sgx_ql_get_root_ca_crl;
// Test FMSPC
static constexpr uint8_t TEST_FMSPC[] = {0x00, 0x90, 0x6E, 0xA1, 0x00, 0x00};

// Test input (choose an arbitrary Azure server)
static uint8_t qe_id[16] = {
0x00, 0xfb, 0xe6, 0x73, 0x33, 0x36, 0xea, 0xf7,
0xa4, 0xe3, 0xd8, 0xb9, 0x66, 0xa8, 0x2e, 0x64
};

static sgx_cpu_svn_t cpusvn = {
0x04, 0x04, 0x02, 0x04, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

static sgx_isv_svn_t pcesvn = 6;

static sgx_ql_pck_cert_id_t id = {qe_id, sizeof(qe_id), &cpusvn, &pcesvn, 0};


static void Log(sgx_ql_log_level_t level, const char* message)
{
char const* levelText = "ERROR";
Expand Down Expand Up @@ -193,27 +216,13 @@ static void GetCertsTest()
{
TEST_START();

// Setup the input (choose an arbitrary Azure server)
uint8_t qe_id[16] = {
0x00, 0xfb, 0xe6, 0x73, 0x33, 0x36, 0xea, 0xf7,
0xa4, 0xe3, 0xd8, 0xb9, 0x66, 0xa8, 0x2e, 0x64
};
sgx_cpu_svn_t cpusvn = {
0x04, 0x04, 0x02, 0x04, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

sgx_isv_svn_t pcesvn = 6;

sgx_ql_pck_cert_id_t id = {qe_id, sizeof(qe_id), &cpusvn, &pcesvn, 0};

sgx_ql_config_t* config = nullptr;
// Get the cert data
sgx_ql_config_t* config;
Log(SGX_QL_LOG_INFO , "Calling sgx_ql_get_quote_config");
assert(SGX_QL_SUCCESS == sgx_ql_get_quote_config(&id, &config));
Log(SGX_QL_LOG_INFO , "sgx_ql_get_quote_config returned");
assert(nullptr != config);

// Just sanity check a few fields. Parsing the certs would require a big
// dependency like OpenSSL that we don't necessarily want.
constexpr sgx_cpu_svn_t CPU_SVN_MAPPED = {
Expand Down Expand Up @@ -359,7 +368,7 @@ constexpr auto CURL_TOLERANCE = 0.002;
constexpr auto CURL_TOLERANCE = 0.04;
#endif

void RunQuoteProviderTests()
void RunQuoteProviderTests(bool caching_enabled=true)
{
std::clock_t start;
double duration_curl;
Expand All @@ -386,12 +395,63 @@ void RunQuoteProviderTests()
GetRootCACrlTest();
GetVerificationCollateralTest();

// Ensure that there is a signficiant enough difference between the cert
// fetch to the end point and cert fetch to local cache and that local cache
// call is fast enough
assert(fabs(duration_curl - duration_local) > CURL_TOLERANCE);
assert(duration_local < CURL_TOLERANCE);
if (caching_enabled)
{
// Ensure that there is a signficiant enough difference between the cert
// fetch to the end point and cert fetch to local cache and that local cache
// call is fast enough
assert(fabs(duration_curl - duration_local) > CURL_TOLERANCE);
assert(duration_local < CURL_TOLERANCE);
}
}

#if defined __LINUX__
void ReloadLibrary(libary_type_t *library)
{

dlclose(*library);
*library = LoadFunctions();
assert(SGX_PLAT_ERROR_OK == sgx_ql_set_logging_function(Log));
}

void RunCachePermissionTests(libary_type_t *library)
{
TEST_START();

auto permissions = {0700, 0400, 0200, 0000};
auto permission_folder = "./test_permissions";
#if defined __LINUX__
setenv("AZDCAP_CACHE", permission_folder, 1);
#endif

// Create the parent folder before the library runs
for (auto permission : permissions)
{
ReloadLibrary(library);
assert(0 == mkdir(permission_folder, permission));

RunQuoteProviderTests(permission == 0700);
assert(0 == chmod(permission_folder, 0700));
assert(0 == system("rm -rf ./test_permissions"));
}

// Change the permissions on the parent folder after the
// library has used it
for (auto permission : permissions)
{
ReloadLibrary(library);
assert(0 == mkdir(permission_folder, 0700));
RunQuoteProviderTests(true);

assert(0 == chmod(permission_folder, permission));
RunQuoteProviderTests(false);
assert(0 == chmod(permission_folder, 0700));
assert(0 == system("rm -rf ./test_permissions"));
}

TEST_PASSED();
}
#endif

void SetupEnvironment(std::string version)
{
Expand Down Expand Up @@ -419,32 +479,36 @@ void SetupEnvironment(std::string version)

extern void QuoteProvTests()
{
#if defined __LINUX__
void* library = LoadFunctions();
#else
HINSTANCE library = LoadFunctions();
#endif
libary_type_t library = LoadFunctions();

assert(SGX_PLAT_ERROR_OK == sgx_ql_set_logging_function(Log));

//
// First pass: Get the data from the service
// Get the data from the service
//
SetupEnvironment("");
RunQuoteProviderTests();

//
// Second pass: Get the V1 collateral specifically
// Get the V1 collateral specifically
//
SetupEnvironment("v1");
RunQuoteProviderTests();

//
// Second pass: Get the V2 data from the service
// Get the V2 data from the service
//
SetupEnvironment("v2");
RunQuoteProviderTests();
GetQveIdentityTest();

#if defined __LINUX__
//
// Run tests to make sure libray can operate
// even if access to filesystem is restricted
//
RunCachePermissionTests(&library);
#endif

#if defined __LINUX__
dlclose(library);
Expand Down
2 changes: 1 addition & 1 deletion src/Windows/GeneratePackage/Azure.DCAP.Windows.nuspec
Expand Up @@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>Microsoft.Azure.DCAP</id>
<version>1.3.0</version>
<version>1.4.0</version>
<!-- Authors contain text that appears directly on the gallery -->
<authors>Microsoft</authors>
<owners>Microsoft</owners>
Expand Down
5 changes: 2 additions & 3 deletions src/Windows/README.MD
Expand Up @@ -19,12 +19,11 @@ cd src\Windows
> If you get an error like the script cannot be loaded because the execution of scripts is disabled on this system, run `Set-ExecutionPolicy bypass` and accept the changes.
# Build the Installer
To build the installer Visual Studio 2017 and the WIX toolset are required.
To build the installer Visual Studio 2017 or 2019 and the WIX toolset are required.
1. Downlad the WIX Toolset from https://wixtoolset.org/releases/ and install the recommended Toolset
1. Install the Wix Toolset Visual Studio 2017 Extension. From Visual Studio select Tools->Extensions and Updates and search for "Wix Toolset Visual Studio 2017 Extension"
1. Install the Wix Toolset Visual Studio Extension. From Visual Studio search for "Wix Toolset Visual Studio Extension"
1. Reload the project or re-open `src/Windows/dcap_provider.sln`


# Packaging
1. Run the build script in Release mode
1. Run `nuget pack` in the GeneratePackage directory. If you need to bump the version number
Expand Down

0 comments on commit 8152cfd

Please sign in to comment.