This tutorial demonstrates how to pass data between an application and a secure Intel® Software Guard Extensions (Intel® SGX) enclave with directional enclave pointers. The user is expected to know how to set up an Intel SGX enclave and application in Microsoft Visual Studio*. Prior Intel SGX knowledge is not required, but the Intel SGX user guide may be helpful. Familiarity with C/C++ is assumed.
My setup:
- HP Envy* x360 - Windows* 10 x64
- Intel® Core™ i7-6500U
- Microsoft Visual Studio Professional 2012
- Intel® Software Guard Extensions SDK/PSW V1.1.30214.80
Enclave Code:
The enclave functions will be declared based on the following EDL file:
EDL file
enclave {
trusted {
//ECALLS
public void enclaveInFunction([in, size=len] char *buf, size_t len);
public void enclaveOutFunction([out, size=len] char *buf, size_t len);
public void enclaveInOutFunction([in, out, size=len] char *buf, size_t len);
};
};
|
enclaveInFunction()
This function demonstrates the use of an 'in' enclave byusing external/non-enclave variable to set an internal/enclave value. Data is sent from the application into the enclave.
enclaveOutFunction()
This function demonstrates the use of an 'out' enclave by changing the value of an externally provided input parameter. Data is sent from the enclave to the application
enclaveInOutFunction()
This function demonstrates the use of both an 'in' and 'out' enclave by swapping the values of the input string and the internal enclave string. Data is exchanged between the application and enclave.
Enclave code
#include "Enclave1_t.h"
#include "sgx_trts.h"
#include <stdlib.h>
#include <string.h>
#define MAX_BUF_LEN 100
char enclaveString[MAX_BUF_LEN] = "Internal enclave string is not initialized";
void enclaveOutFunction(char *buf, size_t len)
{
if(len < MAX_BUF_LEN)
buf = (char*)malloc(MAX_BUF_LEN);
memcpy(buf,enclaveString,strlen(enclaveString)+1);
}
void enclaveInFunction(char *buf, size_t len)
{
if(len <= (size_t)MAX_BUF_LEN)
memcpy(enclaveString,buf,strlen(buf)+1);
}
void enclaveInOutFunction(char *buf, size_t len)
{
char *tmp = (char*)malloc(MAX_BUF_LEN*sizeof(char));
memcpy(tmp,buf,strlen(buf)+1);
memcpy(buf,enclaveString,strlen(enclaveString)+1);
memcpy(enclaveString,tmp,strlen(tmp)+1);
free(tmp);
}
|
Create an Application:
Remember, SGX enclave code has no console output. In fact, output commands and libraries such as stdio cannot be used in a VS SGX enclave project. To test the enclave function, we will create a console application that calls the enclave functions.
Application Code
#include "stdafx.h"
#include "sgx_urts.h"
#include "Enclave1_u.h"
#include <stdio.h>
#include "sgx_capable.h"
#include "sgx_uae_service.h"
#define ENCLAVE_FILE _T("Enclave1.signed.dll")
#define MAX_BUF_LEN 100
int main()
{
sgx_enclave_id_t enclaveId = NULL;
sgx_status_t ret = SGX_SUCCESS;
sgx_launch_token_t token = {0};
sgx_launch_token_t *launchToken = NULL;
int updated, i=0;
char buffer[MAX_BUF_LEN] = "Initial string, before enclave calls";
if(sgx_is_capable(&updated) != SGX_ENABLED)
{
printf("Error %#x: SGX is not enabled on this device\n", ret);
return -1;
}
printf("%i: %s\n", i++, buffer);
ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &token, &updated,
&enclaveId, NULL);
if(ret != SGX_SUCCESS)
{
printf("Error %#x: cannot create enclave\n", ret);
return -1;
}
enclaveOutFunction(enclaveId, buffer, MAX_BUF_LEN);
printf("%i: %s\n", i++, buffer);
//set the internal enclave function
strcpy_s(buffer,"Changed the enclave string");
enclaveInFunction(enclaveId, buffer, MAX_BUF_LEN);
//swap values with enclave string
strcpy_s(buffer,"New value application string");
enclaveInOutFunction(enclaveId, buffer, MAX_BUF_LEN);
//now, buffer should be "Changed the enclave string"
printf("%i: %s\n", i++, buffer);
//swap again; next output should be "New value for application string"
enclaveInOutFunction(enclaveId, buffer, MAX_BUF_LEN);
printf("%i: %s\n", i++, buffer);
//grab the pre-swapped string "Changed the enclave string"
enclaveOutFunction(enclaveId, buffer, MAX_BUF_LEN);
printf("%i: %s\n", i++, buffer);
if(sgx_destroy_enclave(enclaveId) != SGX_SUCCESS)
{
printf("Error %x: cant destroy enclave\n", ret);
return -1;
}
else printf("DONE\n");
getchar();
return 0;
}
|
Final output should be:
0: Initial string, before enclave calls
1: Internal enclave string is not initialized
2: Changed the enclave string
3: New value application string
4: Changed the enclave string
DONE