Intel SGX - Theory vs Reality

October 23, 2015

On September 26th 2013, Intel published the Intel Software Guard Extensions programming reference. They added 19 new instructions which allows the creation and execution of an trusted "enclave" on an untrusted host. Some great benefits are coming with that technology.

In this post I will discuss some of the advertised features of SGX and how the reality meets the expectations.

Theory

The motivation for SGX:

Allow application developers to protect sensitive data from unauthorized access or modification by rogue software running at higher privilege levels.

Enable applications to preserve the confidentiality and integrity of sensitive code and data without disrupting the ability of legitimate system software to schedule and manage the use of platform resources.

Enable applications to define secure regions of code and data that maintain confidentiality even when an attacker has physical control of the platform and can conduct direct attacks on memory.

These both points are huge. Now you can run your code inside a secure enclave. Even if the system is compromised, your keys and your confidential data is not getting stolen. So far so good, lets go on with the feature list.

Enable the platform to measure an application’s trusted code and produce a signed attestation, rooted in the processor, that includes this measurement and other certification that the code has been correctly initialized in a trust able environment.

Ok that sounds interesting. The platform, the Skylake CPU itself, can measure and attestate the code. So the CPU is the only thing that is trusted in the system. Where to the certificates come? Are they self signed by the developer? Or by Intel?

Enable consumers of computing devices to retain control of their platforms and the freedom to install and uninstall applications and services as they choose.

The consumer has the freedom to install and uninstall encrypted applications which can not be decrypted by him. Good, at least the executed code is save..

Enable the development of trusted applications using familiar tools and processes.

Enable software vendors to deliver trusted applications and updates at their cadence, using the distribution channels of their choice.

Okay, it is just an ISA Extension. So I have to use a new compiler, assembler, kernel which can interpret these new instructions and a new BIOS to activate SGX.

That is the motivation behind SGX and these are the reasons many people really want to use that technology. Some guys spotted a little detail which is very well hidden in the manuals and not explained by Intel. That is the sad reality we encounter here.

Reality

EINIT

When you want to initialize a new enclave you have to call EINIT with the parameters SIGSTRUCT and EINITTOKEN. The SIGSTRUCT is an enclave signature structure and contains information about the enclave. The EINITTOKEN is described in the programming reference 2.14 on page 30.

The EINIT token is used by EINIT to verify that the enclave is permitted to launch.

It contains:

MAC - A cryptographic MAC on EINITTOKEN using Launch key

So the EINITTOKEN is MACed with a Launch Key. What is that Launch Key? Where do I get it? Do I really need it?

Lets have a look at the "EINIT—Initialize an Enclave for Execution" operation starting on page 90.

Signed by Intel - no Launch Key

/* if EINITTOKEN.VALID[0] is 0, verify the enclave is signed by Intel */
IF (TMP_TOKEN.VALID[0] = 0)
    IF (TMP_MRSIGNER != CSR_INTELPUBKEYHASH)
        RFLAG.ZF <- 1;
        RAX <- SGX_INVALID_EINITTOKEN;
        goto EXIT;
    FI;
    goto COMMIT;
FI;

All enclaves signed by Intel are valid. No Launch Key needed there.

Not signed by Intel - you need the Launch Key

What happens when the enclave is not signed by Intel:

/* Derive Launch key used to calculate EINITTOKEN.MAC */
HARDCODED_PKCS1_5_PADDING[15:0] <- 0100H;
HARDCODED_PKCS1_5_PADDING[2655:16] <- SignExtend330Byte(-1); // 330 bytes of 0FFH
HARDCODED_PKCS1_5_PADDING[2815:2656] <- 2004000501020403650148866009060D30313000H;
TMP_KEYDEPENDENCIES.KEYNAME <- LAUNCH_KEY;
...
TMP_KEYDEPENDENCIES.PADDING <- HARDCODED_PKCS1_5_PADDING;
/* Calculate the derived key */
TMP_EINITTOKENKEY <- derivekey(TMP_KEYDEPENDENCIES);

Looks like there is a hard coded secret embedded in each CPU.

/* Verify EINITTOKEN was generated using this CPU's Launch key and that it has not been modified since issuing by the Launch
Enclave. Only 192 bytes of EINITOKEN are CMACed */
IF (TMP_TOKEN.MAC != CMAC(TMP_EINITTOKENKEY, TMP_TOKEN[1535:0] ) )
    RFLAG.ZF <- 1;
    RAX <- SGX_INVALID_EINIT_TOKEN;
    goto EXIT;
FI;

The EINIT is only successful if the INITTOKENs MAC is the same like the MAC of the derived TMP_KEYDEPENDENCIES and first bytes of the EINITTOKEN.

So if we aren't from Intel, we need that Launch Key. It is possible to send an EGETKEY instruction with a KEYREQUEST Data structure (2.17 p32). The field KEYNAME can contain the value 0 for a LAUNCH_LEY. Looks like we found it. Lets call EGETKEY to get our Launch Key.

EGETKEY(LAUNCHKEY)

EGETKEY—Retrieves a Cryptographic Key (p138) is described as following:

The ENCLU[EGETKEY] instruction returns a 128-bit secret key from the processor specific key hierarchy. The register RBX contains the effective address of a KEYREQUEST structure, which the instruction interprets to determine the key being requested. [...] This instruction leaf can only be executed inside an enclave.

So to launch an enclave you need the Launch Key which can be only generated inside an enclave. Jethro Beekman allready mentioned that there is a Chicken - Egg problem here..

So the only way to get an enclave running is to start an Intel launch enclave to get the Launch Key for your own enclave. So the launch enclave must be executed on every system before you can execute a custom enclave with the derived Launch Key.

If you think that this is bad, but acceptable, because you can generate Launch Keys with our own enclave afterwards you are possibly wrong.

ATTRIBUTES.LAUNCHKEY

CASE (DS:RBX.KEYNAME)
    EINITTOKEN_KEY:
        /* Check ENCLAVE has LAUNCH capability */
        IF (TMP_CURRENTSECS.ATTRIBUTES.LAUNCHKEY = 0) THEN
            RFLAGS.ZF <- 1;
            RAX <- SGX_INVALID_ATTRIBUTE;
            goto EXIT;
        FI;
        ...

Note that Intel renamed the LAUNCH_KEY to EINITTOKEN_KEY there. It seems like there is an undocumented enclave attribute LAUNCHKEY which must be set if the enclave wants to generate Launch Keys.

Intels Launch Enclave could simply deny Launch Keys to Enclaves with ATTRIBUTES.LAUNCHKEY = 1. So Intel is in full control which enclaves can be executed and which not.

the Launch Enclave

There is a thread on the Intel Developer Zone. An user is asking for exactly that Launch Enclave.

The principle engineer of the SGX program responded with:

The SGX software stack that makes use of the SGX instruction set, and includes the Quoting Enclave, is being made available on a licensed basis to developers looking to bring products to the market for SKL platforms

I hope Intel provides the SGX software stack to all developers and not just the Airforce and Microsoft like in the past.

to be continued..