Create and Execute an Intel SGX Enclave

January 5, 2016

Intel released its SGX SDK for Windows to the public. They included the launch enclave, which is needed to start own enclaves. They also provided some documentation about the usage of the SDK. I want to describe how you get your own enclave running in 5 minutes. I followed the SDK User Guide

If you are not shure if SGX is enabled on your machine you can execute the test_sgx.c from my repo: SGX-hardware It should print at least sgx 1 supported: 1.

Before we can start, you have to install the SDK. I am using it with Visual Studio 2012 Professional.

Create the Enclave

We want to create the enclave first. In Visual Studio go to File > New > Project and than Templates > Visual C++ > Intel SGX Enclave Project. Choose a project name or the enclave like: enclave_test_save. You don't have to change anything in the project wizard. A new signing key will be generated if no one is given.

In the project go to the Source Files and choose the enclave_test_save.cpp. Implement some secure functions that you want to call from the outside of the enclave. Or just copy my example:

#include "enclave_test_save_t.h"

#include "sgx_trts.h"
#include <cstring>

char savedString[100] = "Default Enclave savedText";
int savedInt = -1;

// change a buffer with a constant string
void enclaveChangeBuffer(char *buf, size_t len)
{
    const char *secret = "Hello Enclave!";
    if (len > strlen(secret))
    {
        memcpy(buf, secret, strlen(secret) + 1);
    } else {
        memcpy(buf, "false", strlen("false") + 1);
    }
}

// write a var to the buffer
void enclaveStringSave(char *input, size_t len) {
    if ((strlen(input) + 1) < 100)
    {
        memcpy(savedString, input, strlen(input) + 1);      
    } else {
        memcpy(input, "false", strlen("false") + 1);
    }
}

// save the buffer to a var
void enclaveStringLoad(char *output, size_t len) {
    if (len > strlen(savedString))
    {
        memcpy(output, savedString, strlen(savedString) + 1);
    } else {
        memcpy(output, "false", strlen("false") + 1);
    }
}

// save a int to a var
void enclaveSaveInt(int input) {
    savedInt = input;
}

// return a var
int enclaveLoadInt() {
    return savedInt;
}

Define ECALLs

Know open the enclave_test_save.edl file which is used to define the trusted interfaces. Define your own trusted ECALLs to your functions or copy the following:

enclave {
    trusted {
        /* define ECALLs here. */
        public void enclaveChangeBuffer([out, size=len] char* buf, size_t len);
        public void enclaveStringSave([in, size=len] char *input, size_t len);
        public void enclaveStringLoad([out, size=len] char *output, size_t len);
        public void enclaveSaveInt(int input);
        public int enclaveLoadInt();
    };

    untrusted {
        /* define OCALLs here. */
    
    };
};

You are know ready to build the enclave. Hit the Build button and have a look at the Enclave configuration in the output. By default Debug Mode for the Enclave is enabled, so you are able to analyze the enclave afterwards.

Create the Application

Now lets build a small application which calls the enclave functions. Go to File > New > Project and choose Templates > Visual C++ > Win32 Console Application. I named the application: app_test_save

At first, we have to import the enclaves edl file via the Intel SGX Extensions Add-In. Right click on the project app_test_save and choose Intel SGX Configuration > Import Enclave Click on Import EDL and choose the enclave_test_save.edl. Check the CheckBox of the edl file in the Import Enclave Window and press OK. You can now use the enclave functions in the main application. Here my example code for the app_test_save.cpp.

#include "stdafx.h"

#define ENCLAVE_FILE _T("enclave_test_save.signed.dll")
#define MAX_BUF_LEN 100

#include "sgx_urts.h"
#include "enclave_test_save_u.h"


int main()
{
    sgx_enclave_id_t   eid;
    sgx_status_t       ret   = SGX_SUCCESS;
    sgx_launch_token_t token = {0};
    int updated = 0;
    char buffer[MAX_BUF_LEN] = "Hello World!";
    char secret[MAX_BUF_LEN] = "My secret string";
    char retSecret[MAX_BUF_LEN] = "";
    int secretIntValue = 0;
    int *secretIntPointer = &secretIntValue;

    ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &token, &updated, &eid, NULL);

    if (ret != SGX_SUCCESS) {
        printf("\nApp: error %#x, failed to create enclave.\n", ret);
    }

    // A bunch of Enclave calls (ECALL) will happen here.

    printf("\nApp: Buffertests:\n");

    // Change the buffer in the enclave
    printf("App: Buffer before change: %s\n", buffer);
    enclaveChangeBuffer(eid, buffer, MAX_BUF_LEN);
    printf("App: Buffer after change: %s\n", buffer);


    printf("\nApp: Stringtests:\n");

    // Load a string from enclave
    // should return the default savedString from the enclave
    enclaveStringLoad(eid, retSecret, MAX_BUF_LEN);
    printf("App: Returned Secret: %s\n", retSecret);

    // Save a string in the enclave
    enclaveStringSave(eid, secret, strlen(secret)+1);
    printf("App: Saved Secret: %s\n", secret);

    // Load a string from enclave
    // should return our secret string 
    enclaveStringLoad(eid, retSecret, MAX_BUF_LEN);
    printf("App: Load Secret: %s\n", retSecret);


    printf("\nApp: Integertests:\n");

    // Load integer from enclave
    // should return defauld savedInt from enclave
    enclaveLoadInt(eid, secretIntPointer);
    printf("App: secretIntValue first load: %d\n", secretIntValue);

    // Save integer to enclave
    enclaveSaveInt(eid, 1337);
    printf("App: saved a 1337 to the enclave. \n", 1337);

    // Load integer from enclave
    // should return our saved 1337
    enclaveLoadInt(eid, secretIntPointer);
    printf("App: secretIntValue second load after 1337 was saved: %d\n", secretIntValue);


    // Destroy the enclave when all Enclave calls finished.
    if(SGX_SUCCESS != sgx_destroy_enclave(eid))
        printf("\nApp: error, failed to destroy enclave.\n");

    getchar();
    return 0;
}

Following the original documentation you should be able to run the application now.

If you get the error:

[sgx_create_enclavew ..\urts\win\urts.cpp:83] Couldn't open file with CreateFile()

App: error 0x200f, failed to create enclave.

SGX couldn't find the enclave file. The solution is to move the enclave_test_save.signed.dll into the same folder where the app_test_save.exe is located.

Finally when executing the application this output should appear:

Photo

SGX Drivers?!

Some additional information about the SGX Drivers. It seems odd, that Microsoft, Intel and Dell distribute SGX drivers. To use SGX you don't need any driver. You can communicate directly with the CPU to get the SGX functionality. But the Drivers provide Interfaces to make the usage of SGX much more easier. When using the SDK an AESM Service is started. The aesm_service.exe is located at C:\Program Files\Intel\IntelSGXPSW\bin\x64\Release. In the same folder are multiple *.signed.dll files which are encrypted enclaves. One of these enclave is maybe the launch enclave which is used to start every other enclave.

Photo

We don't really know what these enclaves are doing. Maybe Intel provides some more Information when the Linux SDK will be made available in this year.