Enclave Example

Now let’s start with an enclave Hello world coding example.

Code is available under HelloEnclave at https://github.com/sangfansh/SGX101_sample_code.git. It is a simplified version of SampleEnclave example at Linux SGX SDK.

The App.h head file defines the application we are going to create. Here, enclave initialization token is define as the “enclave.token” file and the signed enclave shared object after compilation will be “enclave.signed.so” (line 52, 53).

A global sgx_enclave_id_t is also declared to uniquely identify the enclave (line 55).

Now let’s move to App.cpp.

As it is in the untrusted application, we must include “sgx_urts.h”, the SGX untrusted runtime system, for SGX to work correctly with the application. We also include “Enclave_u.h”, which will include all of the ECALL proxies generated from the EDL file after compilation.

Line 48-150 just summarize all the possible error code caused by enclave operation.

The critical function here is initialize_enclave(void) at line 157. It first retrieves the launch token from previous transactions if available. If not, just use an empty buffer to record it. Then it calls sgx_create_enclave() function provided by urts library to officially initialize the enclave instance. The sgx_create_enclave() will performs an implicit ECALL. The implicit ECALL initiates enclave runtime initialization flow described in the Enclave Lifecycle tutorial. The actual enclave instance shared object will be saved as “enclave.signed.so”, which is signed by the CPU as indicated by the filename. And the enclave id will be saved in “global_eid” for future access.

We can ignore the ocall_print_string() function as it was in the original sample code.

In the main body of the application, we first initialize the enclave by calling initialize_enclave(). Then call our printf_helloworld() function, which will be discussed later.

Finally, we destroy the enclave instance by calling sgx_destroy_enclave() provided by urts library. It will perform the implicit ECALL that performs instructions that destry the targeted enclave.

Since our purpose of this example application is to print something from the enclave instead from the untrusted application directly, the enclave part should only contain the function that performs this task.

The enclave header file declares the printf_helloworld() function, which will be responsible for our purpose. This function call will be protected by the enclave so outside world won’t know the secret being processed. But for demonstration purposes, we will just print out the secret from the enclave to the screen by calling this function.

We define the printf_helloworld() function as a part of the enclave protected code path, which just prints out “Hello World” to the console. In reality, the secret string should be passed into the enclave from outside world, and will be protected by the enclave. Now since the untrusted application cannot access the enclave content directly, in order for the untrusted function to call enclave functions, we have to rely on the assistance of proxy functions, which will be generated by the Edger8r tool from EDL file after compilation. 

The proxy functions are responsible for:

  • Marshaling data into and out of the enclave
  • Placing the return value of the real ECALL or OCALL in an address referenced by a pointer parameter
  • Returning the success or failure of the ECALL or OCALL itself as an sgx_status_t value

Note that this means each ECALL or OCALL has potentially two return values. There’s the success of the ECALL or OCALL itself, meaning, were we able to successfully enter or exit the enclave, and then the return value of the function being called in the ECALL or OCALL.

Additional arguments will added to the parameter list for each proxy function and the proxy functions now return a type of sgx_status_t instead of the original return types. The first additional parameter is the enclave identifier, eid. The second argument to the proxy function is a pointer to an address that will store the return value from the original enclave function if it has a return value. Since our printf_helloworld() function does not have a return value, the proxy function generated for it will look like 

We can verify that after compiling the whole project.

Therefore, in order to let the Edger8r generate the corresponding proxy functions, we put our function printf_helloworld() in the trusted section of “Enclave.edl”. 

By now, the whole hello world application has acquired all the required parts and should be ready to go.

Compile the project by typing make inside project directory. It should output something like this:

Then execute the application by typing ./app. “Hello World” should be printed to the console. And the message is coming form within the enclave to the outside world!

We can verify the proxy function generated in “Enclave_u.c” has the signature mentioned above (line 21).

Congratulations you have created your first enclave application!