DEV Community

Cover image for Hello World is Hard: Surviving the SGX Setup
Max Jiang
Max Jiang

Posted on

Hello World is Hard: Surviving the SGX Setup

Welcome back to the Confidential Computing Chronicles.

In last post, we discussed why you should be paranoid about your cloud provider. Today, we stop philosophizing and start typing.

If you are a Python developer who complains when pip install takes more than 10 seconds, take a deep breath. Intel SGX (Software Guard Extensions) is not a library; it’s an architectural lifestyle change.

Building a "Hello World" in SGX isn't just print("Hello"). It involves:

  1. Checking if your CPU even supports it (spoiler: it’s complicated).

  2. Fighting with Linux Kernel drivers.

  3. Signing cryptographic contracts. :D

  4. Writing a "Bridge" between two worlds.

Let’s get into it.

Step 0: The Hardware Lottery (Do I have SGX?)

Here is the sad truth: Intel deprecated SGX on consumer CPUs (11th Gen Core and newer) to focus on Server CPUs (Xeon Scalable).

  • If you are on a new MacBook: You are on ARM. No hardware SGX for you.

  • If you are on AMD: Check out SEV (we'll cover that in Part I don't know).

  • If you are on a specialized Cloud Instance (e.g., Azure DC-series): You are golden.

"But Max, I don't have a Xeon server in my bedroom!"

Relax. Intel provides a Simulation Mode. It emulates the Enclave in software. It offers zero security guarantees (because the OS can see the emulated memory), but it lets you write and debug code. We will use Simulation Mode for this tutorial. So, yes, you can follow along on your standard Linux machine.

Step 1: Installing the SDK (The Toolkit)

We need the Intel SGX SDK for Linux. I’m assuming you are on Ubuntu 20.04 or 22.04.

Open your terminal and pretend you are a sysadmin:

# Install the prerequisites (The usual suspects)
sudo apt-get install build-essential python-is-python3

# Download the SGX SDK installer (Check 01.org for the latest version)
wget https://download.01.org/intel-sgx/sgx-linux/2.20/distro/ubuntu22.04-server/sgx_linux_x64_sdk_2.20.100.4.bin

# Make it executable and run it
chmod +x sgx_linux_x64_sdk_*.bin
./sgx_linux_x64_sdk_*.bin
Enter fullscreen mode Exit fullscreen mode

It will ask you where to install. Just say "yes" to /opt/intel. Then, source the environment variables. Do not forget this, or nothing will work and you will cry.

source /opt/intel/sgxsdk/environment
Enter fullscreen mode Exit fullscreen mode

Step 2: The Architecture of a "Hello World"

In a normal program, main() calls printf(). Simple.
In SGX, main() (Untrusted) cannot call printf() inside the Enclave (Trusted) because the Enclave doesn't have a screen, a keyboard, or an OS. It is a black box.

We need three files to make this happen:

  1. App.cpp (The Untrusted Host)
  2. Enclave.cpp (The Secret Logic)
  3. Enclave.edl (The Contract)

transfer

The Contract: Enclave.edl

This is the Enclave Definition Language. It defines what functions can cross the boundary.

  • ECALL (Enclave Call): App calls Enclave (Entering).
  • OCALL (Outside Call): Enclave calls App (Exiting).

Create a file named Enclave.edl:

enclave {
    // Import standard C library types
    from "sgx_tstdc.edl" import *;

    trusted {
        // ECALL: The App will call this function to say Hello
        public void trusted_hello_world();
    };

    untrusted {
        // OCALL: The Enclave will call this to print to the screen
        void untrusted_print([in, string] const char* str);
    };
};
Enter fullscreen mode Exit fullscreen mode

See what we did? We defined a trusted_hello_world function that we can call from the outside. But since the Enclave can't print, we also defined an untrusted_print that the Enclave can call to ask the App to print for it. It's like a prisoner asking a guard to mail a letter.

The Secret: Enclave.cpp

This code runs inside the protected memory.

#include "Enclave_t.h" // Auto-generated header (we'll see this later)
#include "sgx_trts.h"
#include <string.h>

void trusted_hello_world() {
    const char* secret_msg = "Hello from the Secure Enclave!";

    // We cannot use printf here! We must use the OCALL.
    untrusted_print(secret_msg);
}
Enter fullscreen mode Exit fullscreen mode

The Host: App.cpp

This is the normal application that sets everything up.

#include <stdio.h>
#include "sgx_urts.h"
#include "Enclave_u.h" // Auto-generated header for untrusted code

// Global Enclave ID
sgx_enclave_id_t global_eid = 0;

// This is the OCALL implementation
// The Enclave calls this when it wants to print something
void untrusted_print(const char* str) {
    printf("Enclave says: %s\n", str);
}

int main() {
    sgx_status_t ret;

    // 1. Initialize the Enclave
    // "enclave.signed.so" is the signed library we will build
    ret = sgx_create_enclave("enclave.signed.so", SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);

    if (ret != SGX_SUCCESS) {
        printf("Failed to create Enclave. Error: %x\n", ret);
        return -1;
    }

    printf("App: Enclave created. Calling into the void...\n");

    // 2. Make the ECALL
    trusted_hello_world(global_eid);

    // 3. Destroy the Enclave
    sgx_destroy_enclave(global_eid);

    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Step 3: The Build Nightmare (Edger8r)

You can't just gcc App.cpp. Oh no.
You have to use a tool called sgx_edger8r. It parses your .edl file and generates "Edge Routines" (the glue code that handles the context switching between secure and insecure worlds).

  1. sgx_edger8r reads Enclave.edl.
  2. It generates Enclave_t.c (Trusted proxy) and Enclave_u.c (Untrusted proxy).
  3. You compile the Enclave code + Trusted Proxy into a library.
  4. You Sign the library using a private key (OpenSSL).
  5. You compile the App code + Untrusted Proxy.
  6. Link them together.

I won't paste the 50-line Makefile here because it looks like ancient hieroglyphics.

For now, just imagine running:

make SGX_MODE=SIM
Enter fullscreen mode Exit fullscreen mode

Step 4: Run it!

If the gods of compilation smile upon you, you will see an executable app.

$ ./app

App: Enclave created. Calling into the void...
Enclave says: Hello from the Secure Enclave!
Enter fullscreen mode Exit fullscreen mode

Victory.

victory

Why was that so hard?

You might ask: "Max, that was 200 lines of setup for a print statement."

Yes. But think about what actually happened.
That "Hello" string was created in a region of memory that the Operating System could not read.
When untrusted_print was called, the CPU performed a hardware context switch, exited the protected mode, scrubbed the registers, and handed control back to the OS just to print those characters.

We just defied the laws of traditional OS hierarchy.

Up Next

Now that we have the environment, we need to talk about the Memory Wall.
In the next post, I will show you how to crash your Enclave by allocating too much RAM, and why "Paging" in SGX is a performance killer.

Part 3: The Memory Wall & Performance Tuning is coming soon.


Leave a Comment 👇

Did you get the SGX_ERROR_NO_DEVICE error? Or did you actually manage to run it in Simulation Mode?
Drop your error logs in the comments and let's debug this together.

Top comments (1)

Collapse
 
max_jiang profile image
Max Jiang

If you are running this on a real Ice Lake Server, please brag about it so I can be jealous.