This article aims at introducing the new programming paradigm of secure enclaves enabled by Intel’s SGX technology. I will give a tutorial of implementing a key vault with signing capabilites.
Set up the development environment
To develop applications with Intel SGX following software components are required:
● Visual Studio
● Intel SGX Platform Software (This is needed to execute SGX applications)
SGX applications can be developed and debugged without SGX hardware. A simulator is shipped with the SGX SDK.
Let’s say hello to the Enclave World
Applications developed for SGX need to incorporate special considerations. SGX applications are divided into two parts. The trusted part of an SGX application is executed within the enclave, while the untrusted part is executed outside. All parts of the application dealing with sensitive data need to be placed within the trusted part.
Between the trusted and untrusted part an interface is implemented. This interface consists of e‑calls and o‑calls. E‑calls are functions within the enclave called from untrusted code, meanwhile o‑calls are functions of the untrusted code called from within the enclave.
These interfaces are defined with a special file format, called the EDL-file. Interfaces are defined by their signature. The signature is assigned to the trusted part of the application if it is an interface of the enclave. Otherwise it is assigned to the untrusted part.
Special considerations need to be taken for buffers or pointers passed as parameters. Within the squared brackets in front of a parameter the direction and the size of a buffer are defined. On the trusted site enclave interface buffers with the direction “in” are read from the normal application memory to the enclave memory, while the direction “out” results in data being passed from enclave memory to the normal application. Untrusted interface directions are opposite to their trusted equivalents.
The first step of the implementation is to set up two projects in Visual Studio. An C++-application containing the untrusted code and a separate project for the enclave. The Intel SGX SDK provides a wizard for Visual Studio that sets up the enclave project correctly.
After creating the projects, the EDL file needs to be filled with the interfaces. These interfaces need to be implemented within the enclave and inside the normal application.
From within the application SGX needs to be enabled with:
Further the enclave must be created, with signed library compiled from the enclaves code:
Now the enclave can be used by calling any of the enclaves e‑calls.
The usage of e‑calls differs from calling normal methods. Two additional parameters have to be provided, first the id of the enclave (eid) and a pointer to a variable that will hold the result of the e‑call. The actual return value of the e‑call will only indicate, whether the e‑call itself was successful, which does not necessarily indicate the successful execution.
To invoke an o‑call from within the enclave, the corresponding method has to be defined in our untrusted application, after that it can be called like a normal function.
Example: Signature Key Vault
As an example, an application to sign messages with ECDSA (Elliptic Curve Digital Signature Algorithm) will be developed. All cryptographic functionality like key generation, signing and verification will be handled within the enclave. Private keys will only be stored within the enclave or sealed and stored on the filesystem. That means untrusted code don’t has access to it. All cryptographic functionality will be implemented with the help of SGXs cryptographic API.
The enclave provides five interfaces, named: esv_init, esv_sealkeys, esv_sign, esv_verify and esv_close. With two interfaces from the untrusted application esv_read_data and esv_write_data, the enclave is able to read and write files.
Esv_init initializes everything necessary to use the signing and verifying interfaces. It receives a optional filename for loading sealed keys from filesystem.
First the context for the elliptic curve cryptography is retrieved. This context has to be used with all calls to cryptographic methods for elliptic curves.
If a file name was provided (sealed_data_file), the file is loaded with the o‑call esv_read_data. Then the data is copied into the memory of the enclave, unsealing cannot work if the provided buffer is located outside of the enclave. The size of the unsealed data is determined with sgx_get_encrypt_txt_len, which result is used to reserve a buffer for the unsealed data. After the buffer is allocated the data is unsealed and written into the destined buffer.
If no sealed data is provided, a new key pair (public, private key) is generated with sgx_ecc256_create_key_pair.
Either way the public and private key are stored in global variables of the enclave.
Esv_sign receives as parameters a message to sign. The message is passed on to sgx_ecdsa_sign, which signs the message and saves the signature in the provided signature buffer. The signature is saved to a file with the filename consisting of the message and the extension “.sig”. It should be noted that strings passed as parameters to o- and e‑calls cannot be altered in size, otherwise the method will crash when returning. Therefore the filename is created with snprintf and saved to a new string. The o‑call esv_write_data is used to write to the file. For the sake of simplicity we use only strings in our example but you could of course also sign other forms of data.
Esv_verify takes a message and its signature. The signature for the message is then verified.
The method sgx_ecdsa_verify executes the signature verification, its result is returned by the ecall. If the signature is valid, the result will be zero, otherwise unequal to zero.
Esv_seal_keys saves the current public and private key stored in the enclave to a file. We use a data structure for that, called “esv_sealed_data_t”. The filename is provided as parameter. To avoid third parties from outside the enclave to access the keys, they are sealed with SGXs data sealing feature.
First the size of the sealed data is calculated with sgx_calc_sealed_data_size. Then a corresponding buffer is allocated. With sgx_seal_data the data is encrypted and saved to the allocated buffer. If the sealing was successful the data is saved to a file, with the o‑call esv_write_data.
If the application ends you can use the method sgx_destroy_enclave to destroy an enclave and release its associated resources and invalidates the enclave ID or handle.