Security Guard Extensions
Full Title
The Security Guard Extensions (SGX) are Intel's 2015 implementation of a Trusted Execution Environment added on-chip.
Context
The Trusted Execution Environment was originally build in its own silicon chip, but with increased integrations as been brought on-chip with the main processor.
Problems
- There are two ways to protect main memory used by a secure co-processor.
- Encrypt all data that flows into and out of the secure processor. This was the method used by the first Intel co-process in 1996.
- Allocate some sections of main memory to the secure processor.
The problem is that with SGX memory that was used by the secure processor can be released without being cleared. This allows other processes to read memory that hold secure information, like private key material.
- See the report APIC fail: Intel 'Sunny Cove' chips with SGX spill secrets 2022-08-09
Solution
- From The Magic of Intel’s SGX A Tutorial on Programming a Secure Enclave.
The easiest way to isolate a compute environment is to stand up a separate network that is not connected to the corporate LAN. If the security job is small enough, then you use this guide on Intel’s Security Guard Extension for your programming projects to ensure security from the hardware layer on. Intel introduced the Security Guard Extensions (SGX) in the 3rd quarter of 2015 together with the start of the new Skylake processor series. The focus of SGX is to protect sensitive data against untrusted user, even on already compromised systems, with the help of hard implemented security and crypto mechanism inside the CPU. New instructions and memory access changes making it possible for the software developer to create encrypted enclaves containing sensible data from banking apps or key wallets while retaining confidentiality and integrity. These enclaves are only accessible from inside itself and plain text is only visible while it is processed inside the CPU, keeping the stored information safe, even from privileged software like VMM’s, BIOS or OS’.
This wiki page will answer following points:
- Why is my sensible data safe from unauthorized access and modification?
- How is my sensible data kept confidential and integrity protected?
- Where are possible gateways to break the SGX protection?
And further:
- How can I build my own SGX protected applications?
- What do I need for programming with SGX?
- What does the application user need for using SGX / Is the app user capable of using the SGX functionality I built into my app?
Let’s bone up the theory about apps and enclaves
The security goals of SGX are to protect the confidentiality and integrity of its enclaves. This means untrusted parties like applications or system software should not be able to gain information from the enclave or manipulate the enclaves data and code. We start with information of the data structure and the general architecture of SGX, which lead to the desired safety. In the SGX model an app is divided into a trusted and an untrusted part. The untrusted part is the one communicating with the rest of the system as well as creating the enclave, which is considered as the safe part of the app. Inside the enclave the sensible data is stored. Fixed starting positions inside the enclave ensure the correct execution inside the enclave. To enter this enclave, the CPU has to be in enclave mode, which acts like a switch into the safe world. Further enclave instances are isolated from each other, so they can only interact through their untrusted part. A specific enclave can only be addressed by its trusted app part. This makes it even impossible for malicious programs to get into an enclave, when the CPU is in enclave mode, but the access command comes from an (for the enclave) untrusted memory address.
- The enclave bunker
Enclaves are stored in the Enclave Page Cache (EPC). Following figure shows the specific SGX structures, including data used to security check and manage the enclave entry points. These are, besides the SIGSTRUCT and the Version Page Array, enclave related elements. Each enclave has its own SECS, one or more TCS’ and corresponding SSA’s. The EPC in general has it’s SIGSTRUCT and VA Page.
Further the Enclave Page Cache Map (EPCM) is used to manage the security attributes of the Enclave Pages. The EPCM contains further information for each page listed in the EPC. The figure below lists the data acquired for each page.
The EPC is located inside the Processor Reserved Memory (PRM) inside the DRAM, the EPCM is a look-up table inside the CPU with enclave related data. Since we store our data outside the CPU in the PRM, we must ensure its safeness by encrypting it with the help of the Memory Encryption Engine (MEE). This way the data in the PRM is nothing more than noise to other parties, only the MEE is capable to real time decrypt the data inside the CPU. Therefore, the CPU is the only place in the system capable of reading the clear data stored inside the enclaves. The CPU as our doorman As we have seen before, the only participant privileged to enter the EPC, respectively the PRM, is the CPU. The method of deciding whether the processor can enter this secure area depends on the mode, the CPU is running at. SGX implements an Enclave Mode, which the CPU must enter to get specific memory access semantics. This mode gets enabled, once internal enclave code wants to run inside its specific enclave area in the EPC. To sum up, there are three requirements an access must fulfil to get protected memory access: the processor runs in enclave mode, the requested page is part of the same enclave the access has been requested and the page access must be through the right specific virtual address.
If a running enclave is stopped or interrupted, any context information like registers are removed from the CPU, therefore by interrupting the enclave an attacker cannot gain any in-formation from the enclave. But before this happens, related registers are evacuated into their explicit enclave, where they are saved in an encrypted state in the EPC in the PRM on the DRAM. Image for post Blue line: Enclave 1 can access every page inside its own enclave. Additionally, it can access non PRM memory. That means, that only our enclave can run commands inside itself. Further the enclave can run commands outside its safe space trough the untrusted side of its app. Access from the PRM into the enclave is only possible through defined call functionalities for entering an enclave trough the untrusted app side, there is no other way entering an enclave.
Red line: If code inside a page from e.g. enclave n wants to enter a page of enclave 1, it gets redirected to a nonexistent memory. This is backed by the virtual memory address check of the MMU. If an access is tried from a virtual address outside the explicit enclaves’ virtual address, it gets either redirected to nonexistent memory or it throws a signal fault. This behavior prevents attackers entering from the safe PRM area to neighboring enclaves, just because of the point, that the CPU is running in enclave mode. Entering from the non PRM area is generally blocked by the circumstance, that the CPU isn’t running in enclave mode. More detailed information for SGX structures available @ quarkslab blog entry about Intel SGX and good paperwork @ Intel, Innovative Instructions and Software Model for Isolated Execution Prepare your development environment To develop applications with Intel SGX following software components are required:
- Visual Studio
- Intel SGX SDK
- 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 world The link to the example on github
- Design - 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.
- Implementation - 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 enclave's 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.