├── .gitignore ├── 001-pwd ├── .gitignore ├── Makefile ├── README.md ├── passwd.c └── secret.h ├── 001-sgx-pwd ├── .gitignore ├── Enclave │ ├── .gitignore │ ├── Makefile │ ├── encl.c │ ├── encl.config.xml │ ├── encl.edl │ └── secret.h ├── Makefile ├── README.md └── main.c ├── 002-inc-secret ├── .gitignore ├── Makefile ├── README.md ├── asm.S ├── main.c ├── overview.png ├── victim.c └── victim.h ├── 002-sgx-inc-secret ├── .gitignore ├── Enclave │ ├── .gitignore │ ├── Makefile │ ├── asm.S │ ├── encl.c │ ├── encl.config.xml │ └── encl.edl ├── Makefile ├── README.md ├── main.c └── overview.png ├── 003-flush-and-reload ├── .gitignore ├── Makefile ├── README.md ├── main.c ├── overview.png ├── secret.h ├── victim.c └── victim.h ├── 003-sgx-flush-and-reload ├── .gitignore ├── Enclave │ ├── .gitignore │ ├── Makefile │ ├── encl.c │ ├── encl.config.xml │ ├── encl.edl │ └── secret.h ├── Makefile ├── README.md ├── main.c └── overview.png ├── 004-secstr ├── .gitignore ├── Makefile ├── README.md ├── main.c ├── victim.c └── victim.h ├── 004-sgx-secstr ├── .gitignore ├── Enclave │ ├── .gitignore │ ├── Makefile │ ├── encl.c │ ├── encl.config.xml │ └── encl.edl ├── Makefile ├── README.md └── main.c ├── 005-rsa ├── .gitignore ├── Makefile ├── README.md ├── asm.S ├── main.c ├── sample-out.txt ├── state-machine.png ├── state-machine.xml ├── victim.c └── victim.h ├── 005-sgx-rsa ├── .gitignore ├── Enclave │ ├── .gitignore │ ├── Makefile │ ├── asm.S │ ├── encl.c │ ├── encl.config.xml │ └── encl.edl ├── Makefile ├── README.md ├── main.c ├── sample-out.txt ├── state-machine.png └── state-machine.xml ├── README.md ├── common ├── cacheutils.h ├── debug.c ├── debug.h ├── pf.c └── pf.h ├── part1-slides.pdf ├── part2-slides.pdf └── space18.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.o 3 | *.elf 4 | *.elf.* 5 | *.bin 6 | *.fst 7 | *.fst.* 8 | *.out 9 | *.swo 10 | -------------------------------------------------------------------------------- /001-pwd/.gitignore: -------------------------------------------------------------------------------- 1 | passwd 2 | -------------------------------------------------------------------------------- /001-pwd/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | 3 | INCLUDE = -I../common/ 4 | 5 | passwd: 6 | $(CC) $(INCLUDE) passwd.c -o passwd 7 | 8 | clean: 9 | rm -f passwd 10 | -------------------------------------------------------------------------------- /001-pwd/README.md: -------------------------------------------------------------------------------- 1 | # A hands-on guide to execution timing attacks 2 | 3 | As a warm-up exercise, we will start by explaining the concept of a timing 4 | side-channel by attacking a rudimentary example program. The program compares a 5 | user-provided input against an unknown secret PIN code to decide access. 6 | Your task is to infer the secret PIN code, without modifying any of the code. 7 | For this, you will have to cleverly provide inputs to the program, and 8 | carefully observe the associated execution timings being printed. 9 | 10 | ## Your task 11 | 12 | Try to understand what the passwd program is doing by examining its source code 13 | (`passwd.c`). However, make sure to not yet open the `secret.h` file at this 14 | point, or you'll miss out on all the fun! ;-) 15 | 16 | **Note.** This program does not yet require Intel SGX support, but can only be 17 | executed on a (recent) Intel/AMD x86 processor, which is most likely what's in 18 | your laptop (if you don't get any error messages). 19 | 20 | ### Identifying the timing channel 21 | 22 | After running and/or examining the program, you will have noticed that the only 23 | way to get access is to provide the unknown PIN code. However, besides 24 | printing an "access denied" message, the program also prints a timing 25 | measurement. More specifically, it prints the amount of CPU cycles needed to 26 | execute the `check_pwd` function below (expressed as the median over 100,000 27 | repeated runs): 28 | 29 | ```C 30 | int check_pwd(char *user, int user_len, char *secret, int secret_len) 31 | { 32 | int i; 33 | 34 | /* reject if incorrect length */ 35 | if (user_len != secret_len) 36 | return 0; 37 | 38 | /* reject on first byte mismatch */ 39 | for (i=0; i < user_len; i++) 40 | { 41 | if (user[i] != secret[i]) 42 | return 0; 43 | } 44 | 45 | /* user password passed all the tests */ 46 | return 1; 47 | } 48 | ``` 49 | 50 | **Note.** The above code is somewhat simplified. The real C program includes 51 | additional dummy `delay` function calls to artificially delay the 52 | program, with the purpose of amplifying the timing channel for educational 53 | purposes. 54 | 55 | **Do it yourself.** Explain why the execution timings being printed are not not 56 | always exactly the same when repeatedly providing the exact same input. Why is 57 | it a good idea to print the median instead of the average? 58 | 59 | > Execution time non-determinism in modern processors is caused by a wide range 60 | > of microarchitectural optimizations including (instruction+data) caching, 61 | > pipelining, branch prediction, dynamic frequency scaling, etc. Ultimately, a 62 | > single execution timing measurement may be unreliable, and it's better to 63 | > aggregate over multiple measurements. We compute the the median, since a 64 | > single outlier (e.g., due to an operating system context switch or interrupt) 65 | > may strongly affect the average. 66 | 67 | The `check_pwd` function performs the actual password comparison, and only returns 68 | 1 if the password string pointed to by the `user` argument 69 | exactly matches a `secret` string. Otherwise a return value of zero is returned. 70 | While this is clearly functionally correct behavior, `check_pwd` does not 71 | always execute the same instructions for every input. 72 | 73 | ### Exploiting the timing channel 74 | 75 | Keep in mind that you only control the `user` and `user_len` 76 | arguments (by providing inputs to the program), while `secret` and `secret_len` 77 | remain fixed unknown values. 78 | 79 | **Do it yourself.** Try to come up with a way to iteratively provide inputs and 80 | learn something useful from the associated timings. First infer `secret_len`, 81 | before finally inferring all the `secret` bytes. You can assume the secret PIN 82 | code uses only numeric digits (0-9). 83 | 84 | -------------------------------------------------------------------------------- /001-pwd/passwd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "secret.h" 7 | 8 | #define NUM_SAMPLES 100000 9 | #define DELAY 1 10 | 11 | uint64_t diff[NUM_SAMPLES]; 12 | int user_len, secret_len; 13 | 14 | char *read_from_user(void) 15 | { 16 | char *buffer = NULL; 17 | int len; size_t size; 18 | 19 | printf("Enter super secret password ('q' to exit): "); 20 | if ((len=getline(&buffer, &size, stdin)) != -1) 21 | { 22 | /* get rid of the terminating newline character */ 23 | buffer[len-1]='\0'; 24 | printf("--> You entered: '%s'\n", buffer); 25 | return buffer; 26 | } 27 | else 28 | { 29 | printf("--> failure to read line\n"); 30 | return NULL; 31 | } 32 | } 33 | 34 | void delay(void) 35 | { 36 | volatile int i; 37 | for (i=0; i<100;i++); 38 | } 39 | 40 | int check_pwd(char *user) 41 | { 42 | int i; 43 | 44 | /* reject if incorrect length */ 45 | if (user_len != secret_len) 46 | return 0; 47 | 48 | #if DELAY 49 | delay(); 50 | #endif 51 | 52 | /* reject on first byte mismatch */ 53 | for (i=0; i < user_len; i++) 54 | { 55 | if (user[i] != SECRET_PWD[i]) 56 | return 0; 57 | 58 | #if DELAY 59 | delay(); 60 | #endif 61 | } 62 | 63 | /* user password passed all the tests */ 64 | return 1; 65 | } 66 | 67 | int compare(const void * a, const void * b) { 68 | return ( *(uint64_t*)a - *(uint64_t*)b ); 69 | } 70 | 71 | int main() 72 | { 73 | char *pwd; 74 | int j, allowed = 0; 75 | uint64_t tsc1, tsc2, med; 76 | 77 | while ((pwd = read_from_user()) && strcmp(pwd, "q")) 78 | { 79 | 80 | user_len = strlen(pwd); 81 | secret_len = strlen(SECRET_PWD); 82 | 83 | /* collect execution timing samples */ 84 | for (j=0; j < NUM_SAMPLES; j++) 85 | { 86 | tsc1 = rdtsc_begin(); 87 | allowed = check_pwd(pwd); 88 | tsc2 = rdtsc_end(); 89 | diff[j] = tsc2 - tsc1; 90 | } 91 | 92 | if (allowed) 93 | { 94 | printf(" _______________\n"); 95 | printf("< ACCESS ALLOWED >\n"); 96 | printf(" ---------------\n"); 97 | printf(" \\\n"); 98 | printf(" \\\n"); 99 | printf(" .--. \n"); 100 | printf(" |o_o | \n"); 101 | printf(" |:_/ | \n"); 102 | printf(" // \\ \\ \n"); 103 | printf(" (| | ) \n"); 104 | printf(" /'\\_ _/`\\ \n"); 105 | printf(" \\___)=(___/ \n\n"); 106 | } 107 | else 108 | { 109 | printf(" _______________\n"); 110 | printf("< ACCESS DENIED >\n"); 111 | printf(" ---------------\n"); 112 | printf(" \\\n"); 113 | printf(" \\\n"); 114 | printf(" \\|/ ____ \\|/ \n"); 115 | printf(" \"@'/ .. \\`@\" \n"); 116 | printf(" /_| \\__/ |_\\ \n"); 117 | printf(" \\__U_/ \n\n"); 118 | } 119 | 120 | /* compute median over all samples (avg may be affected by outliers) */ 121 | qsort(diff, NUM_SAMPLES, sizeof(uint64_t), compare); 122 | med = diff[NUM_SAMPLES/2]; 123 | printf("time (med clock cycles): %lu\n", med); 124 | 125 | free(pwd); 126 | 127 | } 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /001-pwd/secret.h: -------------------------------------------------------------------------------- 1 | #ifndef SECRET_H_INC 2 | #define SECRET_H_INC 3 | 4 | #define SECRET_PWD "524" 5 | #define FR_SECRET 5 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /001-sgx-pwd/.gitignore: -------------------------------------------------------------------------------- 1 | sgx-pin 2 | -------------------------------------------------------------------------------- /001-sgx-pwd/Enclave/.gitignore: -------------------------------------------------------------------------------- 1 | encl 2 | *.pem 3 | *.a 4 | *.s 5 | *.so 6 | *_u.* 7 | *_t.* 8 | -------------------------------------------------------------------------------- /001-sgx-pwd/Enclave/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | LD = gcc 4 | EDGER = sgx_edger8r 5 | SIGNER = sgx_sign 6 | INCLUDE = -I$(SGX_SDK)/include/ -I$(SGX_SDK)/include/tlibc 7 | T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os 8 | U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g 9 | AR_FLAGS = rcs 10 | OBJECTS = encl.o 11 | LIB_SGX_TRTS = -lsgx_trts 12 | LIB_SGX_TSERVICE = -lsgx_tservice 13 | 14 | ENCLAVE_LIBS = $(LIB_SGX_TRTS) 15 | ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE) 16 | ENCLAVE = encl 17 | PRIVATE_KEY = private_key.pem 18 | PUBLIC_KEY = public_key.pem 19 | KEY_SIZE = 3072 20 | ENCLAVE_EDL = $(ENCLAVE).edl 21 | ENCLAVE_CONFIG = $(ENCLAVE).config.xml 22 | OUTPUT_T = $(ENCLAVE).so 23 | OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so 24 | OUTPUT_U = lib$(ENCLAVE)_proxy.a 25 | LIB_DIRS = -L $(SGX_SDK)/lib64 26 | LD_FLAGS = -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ 27 | -Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \ 28 | -Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \ 29 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 30 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 31 | -Wl,--defsym,__ImageBase=0 32 | TRUSTED_OBJECTS = $(ENCLAVE)_t.o 33 | UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o 34 | TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c 35 | UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c 36 | 37 | #.SILENT: 38 | all: $(OUTPUT_T) $(OUTPUT_U) 39 | 40 | $(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY) 41 | echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG) 42 | $(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG) 43 | 44 | echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG) 45 | $(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null 46 | 47 | $(OUTPUT_U) : $(UNTRUSTED_OBJECTS) 48 | echo "$(INDENT)[AR] " $(OUTPUT_U) 49 | $(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS) 50 | 51 | %_t.o : $(subst .o,.c,$@) edger 52 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)" 53 | touch $(subst .o,.c,$@) 54 | $(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@) 55 | 56 | %_u.o : $(subst .o,.c,$@) edger 57 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)" 58 | touch $(subst .o,.c,$@) 59 | $(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@) 60 | 61 | %.o : %.c edger 62 | echo "$(INDENT)[CC] " $< "(core)" 63 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< 64 | 65 | %.o : %.S 66 | echo "$(INDENT)[AS] " $< "(core)" 67 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@ 68 | 69 | edger: $(ENCLAVE).edl 70 | echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL) 71 | $(EDGER) $(ENCLAVE_EDL) 72 | 73 | .PHONY: force_check 74 | force_check: 75 | true 76 | 77 | .PHONY: scrub 78 | scrub: clean 79 | echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY) 80 | $(RM) $(PRIVATE_KEY) $(PUBLIC_KEY) 81 | 82 | $(PRIVATE_KEY): 83 | echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)" 84 | 85 | # generate 3072 bit private RSA key 86 | openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE) 87 | 88 | echo "$(INDENT)[EXT] $(PUBLIC_KEY)" 89 | # extract public key 90 | openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY) 91 | 92 | # sign enclave 93 | #sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so 94 | 95 | .PHONY: clean 96 | clean: 97 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 98 | $(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 99 | echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 100 | $(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 101 | -------------------------------------------------------------------------------- /001-sgx-pwd/Enclave/encl.c: -------------------------------------------------------------------------------- 1 | #include "encl_t.h" 2 | #include "secret.h" 3 | #include 4 | 5 | /* 6 | * NOTE: for demonstration purposes, we hard-code secrets at compile time and 7 | * abstract away how they are securely provisioned at runtime. 8 | */ 9 | int super_secret_constant = 0xdeadbeef; 10 | 11 | int ecall_dummy(int i) 12 | { 13 | return super_secret_constant + i; 14 | } 15 | 16 | void delay(void) 17 | { 18 | volatile int i; 19 | for (i=0; i<10000;i++); 20 | } 21 | 22 | int check_pwd(char *user) 23 | { 24 | int i; 25 | int user_len = strlen(user); 26 | 27 | /* reject if incorrect length */ 28 | if (user_len != SECRET_LEN) 29 | return 0; 30 | 31 | #if DELAY 32 | delay(); 33 | #endif 34 | 35 | /* reject on first byte mismatch */ 36 | for (i=0; i < user_len; i++) 37 | { 38 | if (user[i] != SECRET_PIN[i]) 39 | return 0; 40 | 41 | #if DELAY 42 | delay(); 43 | #endif 44 | } 45 | 46 | /* user password passed all the tests */ 47 | return 1; 48 | } 49 | 50 | /* =========================== START SOLUTION =========================== */ 51 | /* ============================ END SOLUTION ============================ */ 52 | -------------------------------------------------------------------------------- /001-sgx-pwd/Enclave/encl.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x100000 7 | 1 8 | 1 9 | 0 10 | 11 | -------------------------------------------------------------------------------- /001-sgx-pwd/Enclave/encl.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | 3 | trusted { 4 | /* define ECALLs here. */ 5 | public int ecall_dummy(int i); 6 | 7 | /* =========================== START SOLUTION =========================== */ 8 | /* ============================ END SOLUTION ============================ */ 9 | }; 10 | 11 | untrusted { 12 | /* define OCALLs here. */ 13 | void ocall_print([in,string] const char *str); 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /001-sgx-pwd/Enclave/secret.h: -------------------------------------------------------------------------------- 1 | #ifndef SECRET_H_INC 2 | #define SECRET_H_INC 3 | 4 | #define SECRET_LEN 4 5 | #define SECRET_PIN "1234" 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /001-sgx-pwd/Makefile: -------------------------------------------------------------------------------- 1 | ENCLAVE = Enclave 2 | SUBDIRS = $(ENCLAVE) 3 | 4 | CC = gcc 5 | AS = gcc 6 | LD = gcc 7 | 8 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 9 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 10 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 11 | LDFLAGS += -lencl_proxy -lsgx_urts \ 12 | -lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib64/ 13 | 14 | SOURCES = $(shell ls *.c ../common/*.c) 15 | OBJECTS = $(SOURCES:.c=.o) 16 | OUTPUT = sgx-pin 17 | 18 | BUILDDIRS = $(SUBDIRS:%=build-%) 19 | CLEANDIRS = $(SUBDIRS:%=clean-%) 20 | 21 | 22 | .SILENT: 23 | all: $(OUTPUT) 24 | 25 | run: clean all 26 | ./$(OUTPUT) 27 | 28 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 29 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 30 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 31 | 32 | %.o : %.c 33 | echo "$(INDENT)[CC] " $< 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 35 | 36 | %.o : %.S 37 | echo "$(INDENT)[AS] " $< 38 | $(AS) $(INCLUDE) -c $< -o $@ 39 | 40 | clean: $(CLEANDIRS) 41 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 42 | rm -f $(OBJECTS) $(OUTPUT) 43 | 44 | $(BUILDDIRS): 45 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 46 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 47 | 48 | $(CLEANDIRS): 49 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 50 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 51 | -------------------------------------------------------------------------------- /001-sgx-pwd/README.md: -------------------------------------------------------------------------------- 1 | # PIN code verifier: your first enclave program 2 | 3 | ## Application overview 4 | 5 | The purpose of this application is to develop a first elementary SGX enclave 6 | program that verifies untrusted user input. Particularly, we assume that the 7 | enclave has previously already been securely provisioned with a 4-digit PIN 8 | code and an application-level secret. The enclave's sole job is to enforce 9 | access control on the application secret by querying the untrusted world for 10 | the PIN code, destroying the secret after three successive failed comparison 11 | attempts, or returning it on success. 12 | 13 | **Note.** This application only serves demonstration purposes and does not aim 14 | to be a fully tamper-proof security solution. Notable enclave concepts that are 15 | missing include _secure I/O_, _secret provisioning_, _sealing_ for persistent 16 | storage, and _state continuity_ to protect against roll-back attacks. 17 | 18 | ## Your task 19 | 20 | Developing an SGX enclave application roughly falls down in three phases, 21 | outlined below. 22 | 23 | ### Extending enclave public interface (`Enclave/encl.edl`) 24 | 25 | In the enclaved execution paradigm, the programmer splits off a small trusted 26 | application part (the "enclave") that is shielded by the CPU from the remainder 27 | of the application. Since enclaves are designed to operate in an untrusted, 28 | potentially hostile, environment, they should enforce a strict public software 29 | interface. Generally, enclaves can interact with their untrusted environment in 30 | two distinct ways: 31 | 32 | - **ECALL:** Function call performed by the untrusted world to enter an 33 | enclave, passing some arguments and/or expecting a return value. 34 | - **OCALL:** Function call performed by the enclave to call back to the 35 | untrusted world, passing some arguments and/or expecting a return value. 36 | 37 | The Intel SGX SDK features a small domain-specific [Enclave Definition Language 38 | (EDL)](https://software.intel.com/en-us/sgx-sdk-dev-reference-enclave-definition-language-file-syntax) 39 | to unambiguously define the enclave's ECALL/OCALL interaction with the 40 | untrusted world. Pointer arguments should be explicitly marked with `[in]` and 41 | `[out]` attributes to indicate whether they represent input and/or output for 42 | the enclave (in case of an ECALL), or untrusted world (in case of an OCALL). 43 | Based on this description, the SDK automatically generates trusted and 44 | untrusted bridge code that securely transfers control to/from the untrusted 45 | environment. 46 | 47 | **Do it yourself.** The PIN code verifier application will feature an ECALL 48 | entry point to try and request the application secret by verifying an untrusted 49 | PIN code from the end user. You will thus have to: 50 | 51 | - Extend `Enclave/encl.edl` with a trusted `ecall_get_secret` ECALL entry point 52 | that takes an `int*` and a `char*` pointer arguments and returns an `int`, 53 | indicating whether or not PIN code verification succeeded and the application 54 | secret was written to the pointer argument. 55 | 56 | ### Extending enclave implementation (`Enclave/encl.c`) 57 | 58 | After defining the enclave's interface, you will have to implement the required 59 | ECALL functionality. Implement the `int ecall_get_secret(int *secret_pt, char* pin)` untrusted helper function. Take care to ensure that: 60 | 61 | - The enclave only writes `super_secret_constant` to `secret_pt` when the 62 | untrusted user-provided PIN code exactly matches `SECRET_PIN` of length 63 | `SECRET_LEN`. 64 | 65 | ### Extending untrusted runtime (`main.c`) 66 | 67 | Finally, after finishing the trusted enclave's implementation, you have to 68 | extend the untrusted runtime support system. We already provided the enclave 69 | creation code and an example `ecall_dummy()` enclave 70 | function call. Now, add the `ecall_get_secret()` enclave function call, and 71 | print out the return value and secret returned by the trusted enclave. 72 | 73 | ## Building and running 74 | 75 | Simply execute: 76 | 77 | ```bash 78 | $ make run 79 | ``` 80 | 81 | **Explain.** Do you succeed in reproducing the timing side-channel attack of 82 | the untrusted program in an enclave setting. Explain why (not)? What doest this 83 | tell you about the _signal-to-noise_ ratio for timing enclave programs? 84 | -------------------------------------------------------------------------------- /001-sgx-pwd/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include 4 | 5 | /* SGX untrusted runtime */ 6 | #include 7 | #include "Enclave/encl_u.h" 8 | 9 | #define NUM_SAMPLES 1000 10 | #define DELAY 1 11 | 12 | uint64_t diff[NUM_SAMPLES]; 13 | 14 | /* define untrusted OCALL functions here */ 15 | 16 | void ocall_print(const char *str) 17 | { 18 | info("ocall_print: enclave says: '%s'", str); 19 | } 20 | 21 | char *read_from_user(void) 22 | { 23 | char *buffer = NULL; 24 | int len; size_t size; 25 | 26 | printf("Enter super secret password ('q' to exit): "); 27 | if ((len=getline(&buffer, &size, stdin)) != -1) 28 | { 29 | /* get rid of the terminating newline character */ 30 | buffer[len-1]='\0'; 31 | printf("--> You entered: '%s'\n", buffer); 32 | return buffer; 33 | } 34 | else 35 | { 36 | printf("--> failure to read line\n"); 37 | return NULL; 38 | } 39 | } 40 | 41 | sgx_enclave_id_t create_enclave(void) 42 | { 43 | sgx_launch_token_t token = {0}; 44 | int updated = 0; 45 | sgx_enclave_id_t eid = -1; 46 | 47 | info_event("Creating enclave..."); 48 | SGX_ASSERT( sgx_create_enclave( "./Enclave/encl.so", /*debug=*/1, 49 | &token, &updated, &eid, NULL ) ); 50 | 51 | return eid; 52 | } 53 | 54 | int compare(const void * a, const void * b) { 55 | return ( *(uint64_t*)a - *(uint64_t*)b ); 56 | } 57 | 58 | int main( int argc, char **argv ) 59 | { 60 | sgx_enclave_id_t eid = create_enclave(); 61 | int rv = 1, secret = 0; 62 | char *pwd; 63 | int j, tsc1, tsc2, med, allowed = 0; 64 | 65 | /* Example SGX enclave ecall invocation */ 66 | SGX_ASSERT( ecall_dummy(eid, &rv, 1) ); 67 | 68 | /* ---------------------------------------------------------------------- */ 69 | while ((pwd = read_from_user()) && strcmp(pwd, "q")) 70 | { 71 | 72 | /* collect execution timing samples */ 73 | for (j=0; j < NUM_SAMPLES; j++) 74 | { 75 | tsc1 = rdtsc_begin(); 76 | /* =========================== START SOLUTION =========================== */ 77 | /* ============================ END SOLUTION ============================ */ 78 | tsc2 = rdtsc_end(); 79 | 80 | diff[j] = tsc2 - tsc1; 81 | } 82 | 83 | if (allowed) 84 | { 85 | printf(" _______________\n"); 86 | printf("< ACCESS ALLOWED >\n"); 87 | printf(" ---------------\n"); 88 | printf(" \\\n"); 89 | printf(" \\\n"); 90 | printf(" .--. \n"); 91 | printf(" |o_o | \n"); 92 | printf(" |:_/ | \n"); 93 | printf(" // \\ \\ \n"); 94 | printf(" (| | ) \n"); 95 | printf(" /'\\_ _/`\\ \n"); 96 | printf(" \\___)=(___/ \n\n"); 97 | } 98 | else 99 | { 100 | printf(" _______________\n"); 101 | printf("< ACCESS DENIED >\n"); 102 | printf(" ---------------\n"); 103 | printf(" \\\n"); 104 | printf(" \\\n"); 105 | printf(" \\|/ ____ \\|/ \n"); 106 | printf(" \"@'/ .. \\`@\" \n"); 107 | printf(" /_| \\__/ |_\\ \n"); 108 | printf(" \\__U_/ \n\n"); 109 | } 110 | 111 | /* compute median over all samples (avg may be affected by outliers) */ 112 | qsort(diff, NUM_SAMPLES, sizeof(uint64_t), compare); 113 | med = diff[NUM_SAMPLES/2]; 114 | printf("time (med clock cycles): %lu\n", med); 115 | 116 | free(pwd); 117 | 118 | } 119 | 120 | /* ---------------------------------------------------------------------- */ 121 | info_event("destroying SGX enclave"); 122 | SGX_ASSERT( sgx_destroy_enclave( eid ) ); 123 | 124 | info("all is well; exiting.."); 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /002-inc-secret/.gitignore: -------------------------------------------------------------------------------- 1 | inc 2 | -------------------------------------------------------------------------------- /002-inc-secret/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AS = gcc 3 | LD = gcc 4 | 5 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 6 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 7 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 8 | 9 | SOURCES = $(shell ls *.c ../common/*.c) 10 | OBJECTS = $(SOURCES:.c=.o) asm.o 11 | OUTPUT = inc 12 | 13 | BUILDDIRS = $(SUBDIRS:%=build-%) 14 | CLEANDIRS = $(SUBDIRS:%=clean-%) 15 | 16 | 17 | .SILENT: 18 | all: $(OUTPUT) 19 | 20 | run: clean all 21 | ./$(OUTPUT) 22 | 23 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 24 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 25 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 26 | 27 | %.o : %.c 28 | echo "$(INDENT)[CC] " $< 29 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 30 | 31 | %.o : %.S 32 | echo "$(INDENT)[AS] " $< 33 | $(AS) $(INCLUDE) -c $< -o $@ 34 | 35 | clean: $(CLEANDIRS) 36 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 37 | rm -f $(OBJECTS) $(OUTPUT) 38 | 39 | $(BUILDDIRS): 40 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 41 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 42 | 43 | $(CLEANDIRS): 44 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 45 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 46 | -------------------------------------------------------------------------------- /002-inc-secret/README.md: -------------------------------------------------------------------------------- 1 | # Increment secret: An elementary page fault attack 2 | 3 | Even before the official launch of Intel SGX, researchers showed the existence 4 | of a [dangerous 5 | side-channel](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/ctrlchannels-oakland-2015.pdf) 6 | within the processor's virtual-to-physical address translation logic. By 7 | revoking access rights on selected enclave memory pages, and observing the 8 | associated page fault patterns, adversaries controlling the operating system 9 | can deterministically establish enclaved code and data accesses at a 4 KiB 10 | granularity. This attack technique has been proven highly practical and 11 | effective, extracting full enclave secrets in a single run and without noise. 12 | 13 | ![overview](overview.png) 14 | 15 | ## Your task 16 | 17 | Consider the following enclave function that increments a global variable `a`, 18 | depending on some secret. 19 | 20 | ```C 21 | void ecall_inc_secret(int s) 22 | { 23 | if (s) 24 | a += 1; 25 | } 26 | ``` 27 | 28 | **Do it yourself.** Edit the untrusted main function to reconstruct the secret 29 | enclave input `s` based on the page fault pattern for the global variable `a`. 30 | Some guidance notes: 31 | 32 | * You can make use of the 33 | [mprotect](http://man7.org/linux/man-pages/man2/mprotect.2.html) library 34 | function to alter page-granular access rights. 35 | * The provided skeleton program already takes care to redirect any page faults 36 | to the `fault_handler` function. 37 | * Make sure to test both with an input `s=1` and `s=0` to make sure your attack 38 | proplerly handles both cases. 39 | 40 | **Note.** For testing purposes, we pass the secret input `s` as plain text from 41 | the main function, but in a real-world scenario the secret input would be 42 | end-to-end encrypted so that only the enclave can see it. 43 | 44 | ### Defeating naive page fault access pattern defenses 45 | 46 | Consider the following "hardened" version of the vulnerable increment function. 47 | The idea is to hide the secret-dependent enclave page access, by always performing 48 | a dummy access on the global variable `a` immediately after the secret branch. 49 | 50 | ```C 51 | void ecall_inc_secret_maccess(int s) 52 | { 53 | if (s) 54 | a += 1; 55 | 56 | /* DEFENSE IDEA: let's always access 'a', independent of the secret */ 57 | volatile int b = a; 58 | } 59 | ``` 60 | 61 | **Do it yourself.** Verify that your attack against `ecall_inc_secret` indeed 62 | does _not_ anymore work against the hardened version above. Now, come up with a 63 | way to refine your attack and distinguish the secret-dependent access from the 64 | dummy access. 65 | 66 | ### Launching the attack on real SGX hardware 67 | 68 | Now you have the proof-of-concept attack working in an _unprotected_ 69 | application on your own laptop, proceed to the `../002-sgx-inc-secret` program 70 | to try and port your attack to a real Intel x86 SGX processor. 71 | -------------------------------------------------------------------------------- /002-inc-secret/asm.S: -------------------------------------------------------------------------------- 1 | .data 2 | .global a 3 | .align 0x1000 /* 4KiB */ 4 | a: 5 | .word 0x0 6 | .space 0x1000 /* 4KiB */ 7 | -------------------------------------------------------------------------------- /002-inc-secret/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "pf.h" 4 | #include "cacheutils.h" 5 | #include 6 | #include "victim.h" 7 | 8 | int fault_fired = 0; 9 | 10 | void fault_handler(void *base_adrs) 11 | { 12 | /* =========================== START SOLUTION =========================== */ 13 | /* =========================== END SOLUTION =========================== */ 14 | 15 | fault_fired++; 16 | } 17 | 18 | int main( int argc, char **argv ) 19 | { 20 | int rv = 1, secret = 0; 21 | 22 | /* ---------------------------------------------------------------------- */ 23 | info("registering fault handler.."); 24 | register_fault_handler(fault_handler); 25 | info("a at %p\n", &a); 26 | 27 | /* ---------------------------------------------------------------------- */ 28 | info_event("inc_secret attack"); 29 | 30 | /* =========================== START SOLUTION =========================== */ 31 | /* =========================== END SOLUTION =========================== */ 32 | 33 | /* ---------------------------------------------------------------------- */ 34 | info_event("inc_secret_maccess attack"); 35 | 36 | /* =========================== START SOLUTION =========================== */ 37 | /* =========================== END SOLUTION =========================== */ 38 | 39 | /* ---------------------------------------------------------------------- */ 40 | 41 | info("all is well; exiting.."); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /002-inc-secret/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/002-inc-secret/overview.png -------------------------------------------------------------------------------- /002-inc-secret/victim.c: -------------------------------------------------------------------------------- 1 | #include "victim.h" 2 | 3 | void ecall_inc_secret(int s) 4 | { 5 | if (s) 6 | a += 1; 7 | } 8 | 9 | void ecall_inc_secret_maccess(int s) 10 | { 11 | if (s) 12 | a += 1; 13 | 14 | /* DEFENSE IDEA: let's always access 'a', independent of the secret */ 15 | volatile int b = a; 16 | } 17 | -------------------------------------------------------------------------------- /002-inc-secret/victim.h: -------------------------------------------------------------------------------- 1 | #ifndef VICTIM_H_INC 2 | #define VICTIM_H_INC 3 | 4 | /* see asm.S */ 5 | extern int a; 6 | 7 | void ecall_inc_secret(int s); 8 | 9 | void ecall_inc_secret_maccess(int s); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/.gitignore: -------------------------------------------------------------------------------- 1 | inc 2 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Enclave/.gitignore: -------------------------------------------------------------------------------- 1 | encl 2 | *.pem 3 | *.a 4 | *.s 5 | *.so 6 | *_u.* 7 | *_t.* 8 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Enclave/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | LD = gcc 4 | EDGER = sgx_edger8r 5 | SIGNER = sgx_sign 6 | INCLUDE = -I$(SGX_SDK)/include/ -I$(SGX_SDK)/include/tlibc 7 | T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os 8 | U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g 9 | AR_FLAGS = rcs 10 | OBJECTS = encl.o asm.o 11 | LIB_SGX_TRTS = -lsgx_trts 12 | LIB_SGX_TSERVICE = -lsgx_tservice 13 | 14 | ENCLAVE_LIBS = $(LIB_SGX_TRTS) 15 | ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE) 16 | ENCLAVE = encl 17 | PRIVATE_KEY = private_key.pem 18 | PUBLIC_KEY = public_key.pem 19 | KEY_SIZE = 3072 20 | ENCLAVE_EDL = $(ENCLAVE).edl 21 | ENCLAVE_CONFIG = $(ENCLAVE).config.xml 22 | OUTPUT_T = $(ENCLAVE).so 23 | OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so 24 | OUTPUT_U = lib$(ENCLAVE)_proxy.a 25 | LIB_DIRS = -L $(SGX_SDK)/lib64 26 | LD_FLAGS = -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ 27 | -Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \ 28 | -Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \ 29 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 30 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 31 | -Wl,--defsym,__ImageBase=0 32 | TRUSTED_OBJECTS = $(ENCLAVE)_t.o 33 | UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o 34 | TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c 35 | UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c 36 | 37 | #.SILENT: 38 | all: $(OUTPUT_T) $(OUTPUT_U) 39 | 40 | $(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY) 41 | echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG) 42 | $(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG) 43 | 44 | echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG) 45 | $(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null 46 | 47 | $(OUTPUT_U) : $(UNTRUSTED_OBJECTS) 48 | echo "$(INDENT)[AR] " $(OUTPUT_U) 49 | $(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS) 50 | 51 | %_t.o : $(subst .o,.c,$@) edger 52 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)" 53 | touch $(subst .o,.c,$@) 54 | $(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@) 55 | 56 | %_u.o : $(subst .o,.c,$@) edger 57 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)" 58 | touch $(subst .o,.c,$@) 59 | $(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@) 60 | 61 | %.o : %.c edger 62 | echo "$(INDENT)[CC] " $< "(core)" 63 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< 64 | 65 | %.o : %.S 66 | echo "$(INDENT)[AS] " $< "(core)" 67 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@ 68 | 69 | edger: $(ENCLAVE).edl 70 | echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL) 71 | $(EDGER) $(ENCLAVE_EDL) 72 | 73 | .PHONY: force_check 74 | force_check: 75 | true 76 | 77 | .PHONY: scrub 78 | scrub: clean 79 | echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY) 80 | $(RM) $(PRIVATE_KEY) $(PUBLIC_KEY) 81 | 82 | $(PRIVATE_KEY): 83 | echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)" 84 | 85 | # generate 3072 bit private RSA key 86 | openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE) 87 | 88 | echo "$(INDENT)[EXT] $(PUBLIC_KEY)" 89 | # extract public key 90 | openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY) 91 | 92 | # sign enclave 93 | #sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so 94 | 95 | .PHONY: clean 96 | clean: 97 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 98 | $(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 99 | echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 100 | $(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 101 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Enclave/asm.S: -------------------------------------------------------------------------------- 1 | .data 2 | .global a 3 | .align 0x1000 /* 4KiB */ 4 | a: 5 | .word 0x0 6 | .space 0x1000 /* 4KiB */ 7 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Enclave/encl.c: -------------------------------------------------------------------------------- 1 | #include "encl_t.h" 2 | #include 3 | 4 | /* see asm.S */ 5 | extern int a; 6 | 7 | void ecall_inc_secret(int s) 8 | { 9 | if (s) 10 | a += 1; 11 | } 12 | 13 | void ecall_inc_secret_maccess(int s) 14 | { 15 | if (s) 16 | a += 1; 17 | 18 | /* DEFENSE IDEA: let's always access 'a', independent of the secret */ 19 | volatile int b = a; 20 | } 21 | 22 | void *ecall_get_a_adrs(void) 23 | { 24 | return (void*) &a; 25 | } 26 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Enclave/encl.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x100000 7 | 1 8 | 1 9 | 0 10 | 11 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Enclave/encl.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | trusted { 3 | public void ecall_inc_secret(int s); 4 | public void ecall_inc_secret_maccess(int s); 5 | 6 | public void *ecall_get_a_adrs( void ); 7 | }; 8 | 9 | untrusted { 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/Makefile: -------------------------------------------------------------------------------- 1 | ENCLAVE = Enclave 2 | SUBDIRS = $(ENCLAVE) 3 | 4 | CC = gcc 5 | AS = gcc 6 | LD = gcc 7 | 8 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 9 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 10 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 11 | LDFLAGS += -lencl_proxy -lsgx_urts \ 12 | -lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib64/ 13 | 14 | SOURCES = $(shell ls *.c ../common/*.c) 15 | OBJECTS = $(SOURCES:.c=.o) 16 | OUTPUT = inc 17 | 18 | BUILDDIRS = $(SUBDIRS:%=build-%) 19 | CLEANDIRS = $(SUBDIRS:%=clean-%) 20 | 21 | 22 | .SILENT: 23 | all: $(OUTPUT) 24 | 25 | run: clean all 26 | ./$(OUTPUT) 27 | 28 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 29 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 30 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 31 | 32 | %.o : %.c 33 | echo "$(INDENT)[CC] " $< 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 35 | 36 | %.o : %.S 37 | echo "$(INDENT)[AS] " $< 38 | $(AS) $(INCLUDE) -c $< -o $@ 39 | 40 | clean: $(CLEANDIRS) 41 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 42 | rm -f $(OBJECTS) $(OUTPUT) 43 | 44 | $(BUILDDIRS): 45 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 46 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 47 | 48 | $(CLEANDIRS): 49 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 50 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 51 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/README.md: -------------------------------------------------------------------------------- 1 | # Increment secret: An elementary page fault attack 2 | 3 | Even before the official launch of Intel SGX, researchers showed the existence 4 | of a [dangerous 5 | side-channel](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/ctrlchannels-oakland-2015.pdf) 6 | within the processor's virtual-to-physical address translation logic. By 7 | revoking access rights on selected enclave memory pages, and observing the 8 | associated page fault patterns, adversaries controlling the operating system 9 | can deterministically establish enclaved code and data accesses at a 4 KiB 10 | granularity. This attack technique has been proven highly practical and 11 | effective, extracting full enclave secrets in a single run and without noise. 12 | 13 | ![overview](overview.png) 14 | 15 | ## Your task 16 | 17 | Consider the following enclave function that increments a global variable `a`, 18 | depending on some secret. 19 | 20 | ```C 21 | void ecall_inc_secret(int s) 22 | { 23 | if (s) 24 | a += 1; 25 | } 26 | ``` 27 | 28 | **Do it yourself.** Edit the untrusted main function to reconstruct the secret 29 | enclave input `s` based on the page fault pattern for the global variable `a`. 30 | Some guidance notes: 31 | 32 | * You can make use of the 33 | [mprotect](http://man7.org/linux/man-pages/man2/mprotect.2.html) library 34 | function to alter page-granular access rights. 35 | * SGX enclaves are loaded at runtime as a shared library object. This means 36 | that all addresses you obtain from an `objdump` need to be incremented with the 37 | base load address of the enclave. Enclave load addresses are 38 | attacker-controlled, and can hence be obtained by modifying the untrusted 39 | runtime, but we already provide you with an `ecall_get_a_adrs` function to more 40 | easily get started. 41 | * The provided skeleton program already takes care to redirect any page faults 42 | to the `fault_handler` function. 43 | * Make sure to test both with an input `s=1` and `s=0` to make sure your attack 44 | proplerly handles both cases. 45 | 46 | **Note.** For testing purposes, we pass the secret input `s` as plain text from 47 | the main function, but in a real-world scenario the secret input would be 48 | end-to-end encrypted so that only the enclave can see it. 49 | 50 | ### Defeating naive page fault access pattern defenses 51 | 52 | Consider the following "hardened" version of the vulnerable increment function. 53 | The idea is to hide the secret-dependent enclave page access, by always performing 54 | a dummy access on the global variable `a` immediately after the secret branch. 55 | 56 | ```C 57 | void ecall_inc_secret_maccess(int s) 58 | { 59 | if (s) 60 | a += 1; 61 | 62 | /* DEFENSE IDEA: let's always access 'a', independent of the secret */ 63 | volatile int b = a; 64 | } 65 | ``` 66 | 67 | **Do it yourself.** Verify that your attack against `ecall_inc_secret` indeed 68 | does _not_ anymore work against the hardened version above. Now, come up with a 69 | way to refine your attack and distinguish the secret-dependent access from the 70 | dummy access. 71 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "pf.h" 4 | #include "cacheutils.h" 5 | #include 6 | 7 | /* SGX untrusted runtime */ 8 | #include 9 | #include "Enclave/encl_u.h" 10 | 11 | sgx_enclave_id_t create_enclave(void) 12 | { 13 | sgx_launch_token_t token = {0}; 14 | int updated = 0; 15 | sgx_enclave_id_t eid = -1; 16 | 17 | info_event("Creating enclave..."); 18 | SGX_ASSERT( sgx_create_enclave( "./Enclave/encl.so", /*debug=*/1, 19 | &token, &updated, &eid, NULL ) ); 20 | 21 | return eid; 22 | } 23 | 24 | int fault_fired = 0; 25 | void *a_pt = NULL; 26 | 27 | void fault_handler(void *base_adrs) 28 | { 29 | /* =========================== START SOLUTION =========================== */ 30 | /* =========================== END SOLUTION =========================== */ 31 | 32 | fault_fired++; 33 | } 34 | 35 | int main( int argc, char **argv ) 36 | { 37 | sgx_enclave_id_t eid = create_enclave(); 38 | int rv = 1, secret = 0; 39 | 40 | /* ---------------------------------------------------------------------- */ 41 | info("registering fault handler.."); 42 | register_fault_handler(fault_handler); 43 | 44 | SGX_ASSERT( ecall_get_a_adrs(eid, &a_pt) ); 45 | info("a at %p\n", a_pt); 46 | 47 | /* ---------------------------------------------------------------------- */ 48 | info_event("inc_secret attack"); 49 | 50 | /* =========================== START SOLUTION =========================== */ 51 | /* =========================== END SOLUTION =========================== */ 52 | 53 | /* ---------------------------------------------------------------------- */ 54 | info_event("inc_secret_maccess attack"); 55 | 56 | /* =========================== START SOLUTION =========================== */ 57 | /* =========================== END SOLUTION =========================== */ 58 | 59 | /* ---------------------------------------------------------------------- */ 60 | info_event("destroying SGX enclave"); 61 | SGX_ASSERT( sgx_destroy_enclave( eid ) ); 62 | 63 | info("all is well; exiting.."); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /002-sgx-inc-secret/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/002-sgx-inc-secret/overview.png -------------------------------------------------------------------------------- /003-flush-and-reload/.gitignore: -------------------------------------------------------------------------------- 1 | fnr 2 | -------------------------------------------------------------------------------- /003-flush-and-reload/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AS = gcc 3 | LD = gcc 4 | 5 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 6 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 7 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 8 | 9 | SOURCES = $(shell ls *.c ../common/*.c) 10 | OBJECTS = $(SOURCES:.c=.o) 11 | OUTPUT = fnr 12 | 13 | BUILDDIRS = $(SUBDIRS:%=build-%) 14 | CLEANDIRS = $(SUBDIRS:%=clean-%) 15 | 16 | 17 | .SILENT: 18 | all: $(OUTPUT) 19 | 20 | run: clean all 21 | ./$(OUTPUT) 22 | 23 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 24 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 25 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 26 | 27 | %.o : %.c 28 | echo "$(INDENT)[CC] " $< 29 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 30 | 31 | %.o : %.S 32 | echo "$(INDENT)[AS] " $< 33 | $(AS) $(INCLUDE) -c $< -o $@ 34 | 35 | clean: $(CLEANDIRS) 36 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 37 | rm -f $(OBJECTS) $(OUTPUT) 38 | 39 | $(BUILDDIRS): 40 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 41 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 42 | 43 | $(CLEANDIRS): 44 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 45 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 46 | -------------------------------------------------------------------------------- /003-flush-and-reload/README.md: -------------------------------------------------------------------------------- 1 | # Flush+Reload: Spying on _unprotected_ memory accesses 2 | 3 | The previous execution timing attack example measured an obvious timing 4 | difference caused by early-outing a function (i.e., executing more vs. less 5 | instructions before returning). Most real-world programs do not exhibit such 6 | explicit input-dependent timing dependencies, however, and we need another way 7 | to extract information. We will therefore abuse subtle timing differences 8 | caused by the underlying CPU cache to infer memory accesses by the victim. 9 | 10 | If the attacker and the victim share some memory locations (e.g., as is often 11 | the case for shared library code), we can rely on the seminal Flush+Reload 12 | attack technique. This technique is conceptually very simple, but has been 13 | proven to be extremely powerful (e.g., Flush+Reload has recently been applied 14 | for instance as an important building block for the high-impact Meltdown, 15 | Spectre, and Foreshadow attacks). Flush+Reload proceeds in 3 distinct phases 16 | to determine whether a victim program accessed some shared data _A_: 17 | 18 | 1. **Flush.** The attacker first initializes the shared CPU cache in a known 19 | state by explicitly flushing the address _A_ from the cache. This ensures that 20 | any subsequent access to _A_ will suffer a cache miss, and will hence be 21 | brought back into the cache from memory. 22 | 23 | 2. **Victim execution.** Now the attacker simply waits for the victim to 24 | execute. If a certain secret is true, the victim will load some data _A_ into 25 | the cache. If the secret is false, however, the victim loads some other data 26 | _B_ into the cache. 27 | 28 | 3. **Reload.** After completing the victim execution, the attacker measures the 29 | amount of time (CPU clock cycles) it takes to reload the shared data _A_. A 30 | fast access reveals that the victim execution in step 2 above brought _A_ into 31 | the cache (i.e., cache hit, secret = true), whereas a slow access indicates 32 | that _A_ was not accessed during the victim's execution (i.e., cache miss, 33 | secret = false). 34 | 35 | ![overview](overview.png) 36 | 37 | ## Your task 38 | 39 | Consider the example victim enclave program. Describe a way to mount a 40 | successful Flush+Reload attack to reconstruct the `secet_idx` lookup index, solely 41 | through timing differences induced by the CPU cache? 42 | 43 | ```C 44 | void ecall_secret_lookup(char *array, int len) 45 | { 46 | c = array[(4096*secret_idx) % len]; 47 | } 48 | 49 | ``` 50 | 51 | **Do it yourself.** Edit the main function to implement the missing "flush" 52 | and "reload" attacker phases. You can use respectively the provided `void 53 | flush(void *adrs)` and `int reload(void *adrs)` functions. The latter returns 54 | the CPU cycle timing difference needed for the reload. If necessary, 55 | compensate for timing noise from modern processor optimizations by repeating 56 | the Flush+Reload experiment (steps 1-3 above) a sufficient amount of times and 57 | taking the median or average. 58 | 59 | > Sample output (secret=4, NUM_SAMPLES=5): 60 | 61 | ``` 62 | Time slot 0 (CPU cycles): 254 63 | Time slot 1 (CPU cycles): 256 64 | Time slot 2 (CPU cycles): 254 65 | Time slot 3 (CPU cycles): 258 66 | Time slot 4 (CPU cycles): 80 67 | Time slot 5 (CPU cycles): 262 68 | Time slot 6 (CPU cycles): 266 69 | Time slot 7 (CPU cycles): 254 70 | Time slot 8 (CPU cycles): 252 71 | Time slot 9 (CPU cycles): 254 72 | ``` 73 | 74 | ### Launching the attack on real SGX hardware 75 | 76 | Now you have the proof-of-concept attack working in an _unprotected_ 77 | application on your own laptop, proceed to the `../003-sgx-flush-and-reload` program 78 | to try and port your attack to a real Intel x86 SGX processor. 79 | -------------------------------------------------------------------------------- /003-flush-and-reload/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "cacheutils.h" 4 | #include "victim.h" 5 | 6 | #define NUM_SAMPLES 5 7 | #define NUM_SLOTS 10 8 | #define SLOT_SIZE 0x1000 9 | #define ARRAY_LEN (NUM_SLOTS*SLOT_SIZE) 10 | #define GET_SLOT(k) (array[k*SLOT_SIZE]) 11 | char __attribute__((aligned(0x1000))) array[ARRAY_LEN]; 12 | 13 | int compare(const void * a, const void * b) { 14 | return ( *(uint64_t*)a - *(uint64_t*)b ); 15 | } 16 | int tsc[NUM_SLOTS][NUM_SAMPLES]; 17 | 18 | int main( int argc, char **argv ) 19 | { 20 | int rv = 1, secret = 0; 21 | int i, j, med; 22 | 23 | /* Ensure array pages are mapped in */ 24 | for (i=0; i < ARRAY_LEN; i++) 25 | array[i] = 0x00; 26 | 27 | for (j=0; j < NUM_SLOTS; j++) 28 | for (i=0; i < NUM_SAMPLES; i++) 29 | tsc[j][i] = 0; 30 | 31 | /* ---------------------------------------------------------------------- */ 32 | info_event("calling victim..."); 33 | 34 | /* Example victim invocation */ 35 | ecall_secret_lookup(array, ARRAY_LEN); 36 | 37 | /* =========================== START SOLUTION =========================== */ 38 | /* =========================== END SOLUTION =========================== */ 39 | 40 | for (j=0; j < NUM_SLOTS; j++) 41 | { 42 | /* compute median over all samples (avg may be affected by outliers) */ 43 | qsort(tsc[j], NUM_SAMPLES, sizeof(int), compare); 44 | med = tsc[j][NUM_SAMPLES/2]; 45 | printf("Time slot %3d (CPU cycles): %d\n", j, med); 46 | } 47 | 48 | /* ---------------------------------------------------------------------- */ 49 | 50 | info("all is well; exiting.."); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /003-flush-and-reload/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/003-flush-and-reload/overview.png -------------------------------------------------------------------------------- /003-flush-and-reload/secret.h: -------------------------------------------------------------------------------- 1 | int secret_idx = 4; 2 | -------------------------------------------------------------------------------- /003-flush-and-reload/victim.c: -------------------------------------------------------------------------------- 1 | #include "secret.h" 2 | 3 | volatile char c; 4 | 5 | void ecall_secret_lookup(char *array, int len) 6 | { 7 | /* Do the secret lookup */ 8 | c = array[(4096*secret_idx) % len]; 9 | } 10 | -------------------------------------------------------------------------------- /003-flush-and-reload/victim.h: -------------------------------------------------------------------------------- 1 | #ifndef VICTIM_H_INC 2 | #define VICTIM_H_INC 3 | 4 | void ecall_secret_lookup(char *array, int len); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/.gitignore: -------------------------------------------------------------------------------- 1 | fnr 2 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Enclave/.gitignore: -------------------------------------------------------------------------------- 1 | encl 2 | *.pem 3 | *.a 4 | *.s 5 | *.so 6 | *_u.* 7 | *_t.* 8 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Enclave/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | LD = gcc 4 | EDGER = sgx_edger8r 5 | SIGNER = sgx_sign 6 | INCLUDE = -I$(SGX_SDK)/include/ -I$(SGX_SDK)/include/tlibc 7 | T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os 8 | U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g 9 | AR_FLAGS = rcs 10 | OBJECTS = encl.o 11 | LIB_SGX_TRTS = -lsgx_trts 12 | LIB_SGX_TSERVICE = -lsgx_tservice 13 | 14 | ENCLAVE_LIBS = $(LIB_SGX_TRTS) 15 | ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE) 16 | ENCLAVE = encl 17 | PRIVATE_KEY = private_key.pem 18 | PUBLIC_KEY = public_key.pem 19 | KEY_SIZE = 3072 20 | ENCLAVE_EDL = $(ENCLAVE).edl 21 | ENCLAVE_CONFIG = $(ENCLAVE).config.xml 22 | OUTPUT_T = $(ENCLAVE).so 23 | OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so 24 | OUTPUT_U = lib$(ENCLAVE)_proxy.a 25 | LIB_DIRS = -L $(SGX_SDK)/lib64 26 | LD_FLAGS = -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ 27 | -Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \ 28 | -Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \ 29 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 30 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 31 | -Wl,--defsym,__ImageBase=0 32 | TRUSTED_OBJECTS = $(ENCLAVE)_t.o 33 | UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o 34 | TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c 35 | UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c 36 | 37 | #.SILENT: 38 | all: $(OUTPUT_T) $(OUTPUT_U) 39 | 40 | $(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY) 41 | echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG) 42 | $(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG) 43 | 44 | echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG) 45 | $(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null 46 | 47 | $(OUTPUT_U) : $(UNTRUSTED_OBJECTS) 48 | echo "$(INDENT)[AR] " $(OUTPUT_U) 49 | $(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS) 50 | 51 | %_t.o : $(subst .o,.c,$@) edger 52 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)" 53 | touch $(subst .o,.c,$@) 54 | $(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@) 55 | 56 | %_u.o : $(subst .o,.c,$@) edger 57 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)" 58 | touch $(subst .o,.c,$@) 59 | $(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@) 60 | 61 | %.o : %.c edger 62 | echo "$(INDENT)[CC] " $< "(core)" 63 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< 64 | 65 | %.o : %.S 66 | echo "$(INDENT)[AS] " $< "(core)" 67 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@ 68 | 69 | edger: $(ENCLAVE).edl 70 | echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL) 71 | $(EDGER) $(ENCLAVE_EDL) 72 | 73 | .PHONY: force_check 74 | force_check: 75 | true 76 | 77 | .PHONY: scrub 78 | scrub: clean 79 | echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY) 80 | $(RM) $(PRIVATE_KEY) $(PUBLIC_KEY) 81 | 82 | $(PRIVATE_KEY): 83 | echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)" 84 | 85 | # generate 3072 bit private RSA key 86 | openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE) 87 | 88 | echo "$(INDENT)[EXT] $(PUBLIC_KEY)" 89 | # extract public key 90 | openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY) 91 | 92 | # sign enclave 93 | #sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so 94 | 95 | .PHONY: clean 96 | clean: 97 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 98 | $(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 99 | echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 100 | $(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 101 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Enclave/encl.c: -------------------------------------------------------------------------------- 1 | #include "encl_t.h" 2 | #include 3 | #include "secret.h" 4 | 5 | volatile char c; 6 | 7 | void ecall_secret_lookup(char *array, int len) 8 | { 9 | /* First ensure the _untrusted_ pointer points outside the enclave */ 10 | if (!sgx_is_outside_enclave(array, len)) 11 | return; 12 | 13 | /* Now do the secret lookup */ 14 | c = array[(4096*secret_idx) % len]; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Enclave/encl.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x100000 7 | 1 8 | 1 9 | 0 10 | 11 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Enclave/encl.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | trusted { 3 | public void ecall_secret_lookup([user_check] char *array, int len); 4 | }; 5 | 6 | untrusted { 7 | }; 8 | }; 9 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Enclave/secret.h: -------------------------------------------------------------------------------- 1 | int secret_idx = 4; 2 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/Makefile: -------------------------------------------------------------------------------- 1 | ENCLAVE = Enclave 2 | SUBDIRS = $(ENCLAVE) 3 | 4 | CC = gcc 5 | AS = gcc 6 | LD = gcc 7 | 8 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 9 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 10 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 11 | LDFLAGS += -lencl_proxy -lsgx_urts \ 12 | -lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib64/ 13 | 14 | SOURCES = $(shell ls *.c ../common/*.c) 15 | OBJECTS = $(SOURCES:.c=.o) 16 | OUTPUT = fnr 17 | 18 | BUILDDIRS = $(SUBDIRS:%=build-%) 19 | CLEANDIRS = $(SUBDIRS:%=clean-%) 20 | 21 | 22 | .SILENT: 23 | all: $(OUTPUT) 24 | 25 | run: clean all 26 | ./$(OUTPUT) 27 | 28 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 29 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 30 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 31 | 32 | %.o : %.c 33 | echo "$(INDENT)[CC] " $< 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 35 | 36 | %.o : %.S 37 | echo "$(INDENT)[AS] " $< 38 | $(AS) $(INCLUDE) -c $< -o $@ 39 | 40 | clean: $(CLEANDIRS) 41 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 42 | rm -f $(OBJECTS) $(OUTPUT) 43 | 44 | $(BUILDDIRS): 45 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 46 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 47 | 48 | $(CLEANDIRS): 49 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 50 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 51 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/README.md: -------------------------------------------------------------------------------- 1 | # Flush+Reload: Spying on _unprotected_ memory accesses 2 | 3 | The previous execution timing attack example measured an obvious timing 4 | difference caused by early-outing a function (i.e., executing more vs. less 5 | instructions before returning). Most real-world programs do not exhibit such 6 | explicit input-dependent timing dependencies, however, and we need another way 7 | to extract information. We will therefore abuse subtle timing differences 8 | caused by the underlying CPU cache to infer memory accesses by the victim. 9 | 10 | If the attacker and the victim share some memory locations (e.g., as is often 11 | the case for shared library code), we can rely on the seminal Flush+Reload 12 | attack technique. This technique is conceptually very simple, but has been 13 | proven to be extremely powerful (e.g., Flush+Reload has recently been applied 14 | for instance as an important building block for the high-impact Meltdown, 15 | Spectre, and Foreshadow attacks). Flush+Reload proceeds in 3 distinct phases 16 | to determine whether a victim program accessed some shared data _A_: 17 | 18 | 1. **Flush.** The attacker first initializes the shared CPU cache in a known 19 | state by explicitly flushing the address _A_ from the cache. This ensures that 20 | any subsequent access to _A_ will suffer a cache miss, and will hence be 21 | brought back into the cache from memory. 22 | 23 | 2. **Victim execution.** Now the attacker simply waits for the victim to 24 | execute. If a certain secret is true, the victim will load some data _A_ into 25 | the cache. If the secret is false, however, the victim loads some other data 26 | _B_ into the cache. 27 | 28 | 3. **Reload.** After completing the victim execution, the attacker measures the 29 | amount of time (CPU clock cycles) it takes to reload the shared data _A_. A 30 | fast access reveals that the victim execution in step 2 above brought _A_ into 31 | the cache (i.e., cache hit, secret = true), whereas a slow access indicates 32 | that _A_ was not accessed during the victim's execution (i.e., cache miss, 33 | secret = false). 34 | 35 | ![overview](overview.png) 36 | 37 | ## Your task 38 | 39 | Consider the example victim enclave program. Describe a way to mount a 40 | successful Flush+Reload attack to reconstruct the `secet_idx` lookup index, solely 41 | through timing differences induced by the CPU cache? 42 | 43 | ```C 44 | void ecall_secret_lookup(char *array, int len) 45 | { 46 | if (!sgx_is_outside_enclave(array, len)) 47 | return; 48 | 49 | c = array[(4096*secret_idx) % len]; 50 | } 51 | 52 | ``` 53 | 54 | **Do it yourself.** Edit the main function to implement the missing "flush" 55 | and "reload" attacker phases. You can use respectively the provided `void 56 | flush(void *adrs)` and `int reload(void *adrs)` functions. The latter returns 57 | the CPU cycle timing difference needed for the reload. If necessary, 58 | compensate for timing noise from modern processor optimizations by repeating 59 | the Flush+Reload experiment (steps 1-3 above) a sufficient amount of times and 60 | taking the median or average. 61 | 62 | > Sample output (secret=4, NUM_SAMPLES=5): 63 | 64 | ``` 65 | Time slot 0 (CPU cycles): 254 66 | Time slot 1 (CPU cycles): 256 67 | Time slot 2 (CPU cycles): 254 68 | Time slot 3 (CPU cycles): 258 69 | Time slot 4 (CPU cycles): 80 70 | Time slot 5 (CPU cycles): 262 71 | Time slot 6 (CPU cycles): 266 72 | Time slot 7 (CPU cycles): 254 73 | Time slot 8 (CPU cycles): 252 74 | Time slot 9 (CPU cycles): 254 75 | ``` 76 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "cacheutils.h" 4 | 5 | /* SGX untrusted runtime */ 6 | #include 7 | #include "Enclave/encl_u.h" 8 | 9 | #define NUM_SAMPLES 5 10 | #define NUM_SLOTS 10 11 | #define SLOT_SIZE 0x1000 12 | #define ARRAY_LEN (NUM_SLOTS*SLOT_SIZE) 13 | #define GET_SLOT(k) (array[k*SLOT_SIZE]) 14 | char __attribute__((aligned(0x1000))) array[ARRAY_LEN]; 15 | 16 | sgx_enclave_id_t create_enclave(void) 17 | { 18 | sgx_launch_token_t token = {0}; 19 | int updated = 0; 20 | sgx_enclave_id_t eid = -1; 21 | 22 | info_event("Creating enclave..."); 23 | SGX_ASSERT( sgx_create_enclave( "./Enclave/encl.so", /*debug=*/1, 24 | &token, &updated, &eid, NULL ) ); 25 | 26 | return eid; 27 | } 28 | 29 | int compare(const void * a, const void * b) { 30 | return ( *(uint64_t*)a - *(uint64_t*)b ); 31 | } 32 | int tsc[NUM_SLOTS][NUM_SAMPLES]; 33 | 34 | int main( int argc, char **argv ) 35 | { 36 | sgx_enclave_id_t eid = create_enclave(); 37 | int rv = 1, secret = 0; 38 | int i, j, med; 39 | 40 | /* Ensure array pages are mapped in */ 41 | for (i=0; i < ARRAY_LEN; i++) 42 | array[i] = 0x00; 43 | 44 | for (j=0; j < NUM_SLOTS; j++) 45 | for (i=0; i < NUM_SAMPLES; i++) 46 | tsc[j][i] = 0; 47 | 48 | /* ---------------------------------------------------------------------- */ 49 | info_event("calling enclave..."); 50 | 51 | /* Example victim invocation */ 52 | SGX_ASSERT( ecall_secret_lookup(eid, array, ARRAY_LEN) ); 53 | 54 | /* =========================== START SOLUTION =========================== */ 55 | /* =========================== END SOLUTION =========================== */ 56 | 57 | for (j=0; j < NUM_SLOTS; j++) 58 | { 59 | /* compute median over all samples (avg may be affected by outliers) */ 60 | qsort(tsc[j], NUM_SAMPLES, sizeof(int), compare); 61 | med = tsc[j][NUM_SAMPLES/2]; 62 | printf("Time slot %3d (CPU cycles): %d\n", j, med); 63 | } 64 | 65 | /* ---------------------------------------------------------------------- */ 66 | info_event("destroying SGX enclave"); 67 | SGX_ASSERT( sgx_destroy_enclave( eid ) ); 68 | 69 | info("all is well; exiting.."); 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /003-sgx-flush-and-reload/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/003-sgx-flush-and-reload/overview.png -------------------------------------------------------------------------------- /004-secstr/.gitignore: -------------------------------------------------------------------------------- 1 | str 2 | -------------------------------------------------------------------------------- /004-secstr/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AS = gcc 3 | LD = gcc 4 | 5 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 6 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 7 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 8 | 9 | SOURCES = $(shell ls *.c ../common/*.c) 10 | OBJECTS = $(SOURCES:.c=.o) 11 | OUTPUT = str 12 | 13 | BUILDDIRS = $(SUBDIRS:%=build-%) 14 | CLEANDIRS = $(SUBDIRS:%=clean-%) 15 | 16 | 17 | .SILENT: 18 | all: $(OUTPUT) 19 | 20 | run: clean all 21 | ./$(OUTPUT) 22 | 23 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 24 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 25 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 26 | 27 | %.o : %.c 28 | echo "$(INDENT)[CC] " $< 29 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 30 | 31 | %.o : %.S 32 | echo "$(INDENT)[AS] " $< 33 | $(AS) $(INCLUDE) -c $< -o $@ 34 | 35 | clean: $(CLEANDIRS) 36 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 37 | rm -f $(OBJECTS) $(OUTPUT) 38 | 39 | $(BUILDDIRS): 40 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 41 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 42 | 43 | $(CLEANDIRS): 44 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 45 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 46 | -------------------------------------------------------------------------------- /004-secstr/README.md: -------------------------------------------------------------------------------- 1 | # To lower case: A secure string processing facility 2 | 3 | Subtle side-channel vulnerabilities may arise in unexpected places. In this 4 | exercise we will explore how a seemingly harmless side-channel in one part of 5 | the program, may compromise an unrelated secret in entirely another part of the 6 | program. 7 | 8 | ## Your task 9 | 10 | Consider the following enclave function that securely transforms a provided 11 | input string to lower case characters. 12 | 13 | ```C 14 | void ecall_to_lowercase(char *s) 15 | { 16 | int i; char c; 17 | 18 | /* First ensure the _untrusted_ string lies outside the enclave */ 19 | if (!sgx_is_outside_enclave(s, strlen(s))) 20 | return; 21 | 22 | /* Now transform the string character per character */ 23 | for (i=0; i < strlen(s); i++) 24 | s[i] = to_lower(s[i]); 25 | } 26 | ``` 27 | 28 | The above program is functionally correct. Go over the program line per line, 29 | can you spot the subtle side-channel vulnerability? 30 | 31 | The test enclave provides an `ecall_set_secret` entry point that places a 32 | supposedly secret input value at a specific location `secret_pt` inside the 33 | "enclave" (`victim.c`). However, since the secret is _never_ explicitly used 34 | inside the enclave, it should not be possible for the attacker to obtain its 35 | value. 36 | 37 | **Do it yourself.** Modify the untrusted main function to obtain the secret 38 | value by observing side-effects of the `ecall_to_lowercase` enclave function. 39 | 40 | Some guidance notes: 41 | 42 | * Modern Intel processors feature a memory page size of 4096 (0x1000) bytes. 43 | * You can make use of the 44 | [mprotect](http://man7.org/linux/man-pages/man2/mprotect.2.html) library 45 | function to alter page-granular access rights. 46 | * The provided skeleton program already takes care to redirect any page faults 47 | to the `fault_handler` function. 48 | * Make sure to test both with an input `s=1` and `s=0` to make sure your attack 49 | proplerly handles both cases. 50 | 51 | ### Launching the attack on real SGX hardware 52 | 53 | Now you have the proof-of-concept attack working in an _unprotected_ 54 | application on your own laptop, proceed to the `../004-sgx-secstr` program 55 | to try and port your attack to a real Intel x86 SGX processor. 56 | -------------------------------------------------------------------------------- /004-secstr/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "pf.h" 4 | #include "cacheutils.h" 5 | #include 6 | #include 7 | #include "victim.h" 8 | 9 | #define TEST_STRING "DeaDBEeF" 10 | 11 | int fault_fired = 0; 12 | void *page_pt = NULL; 13 | 14 | void fault_handler(void *base_adrs) 15 | { 16 | /* =========================== START SOLUTION =========================== */ 17 | /* =========================== END SOLUTION =========================== */ 18 | 19 | fault_fired++; 20 | } 21 | 22 | int main( int argc, char **argv ) 23 | { 24 | int rv = 1, secret = 0; 25 | char *string; 26 | 27 | /* ---------------------------------------------------------------------- */ 28 | info("registering fault handler.."); 29 | register_fault_handler(fault_handler); 30 | 31 | info("secret at %p\n", secret_pt); 32 | 33 | /* ---------------------------------------------------------------------- */ 34 | info_event("Calling enclave.."); 35 | string = malloc(strlen(TEST_STRING)+1); 36 | strcpy(string, TEST_STRING); 37 | ecall_to_lowercase(string); 38 | info("secure enclave converted '%s' to '%s'", TEST_STRING, string); 39 | 40 | /* =========================== START SOLUTION =========================== */ 41 | /* =========================== END SOLUTION =========================== */ 42 | 43 | info("all is well; exiting.."); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /004-secstr/victim.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define ARRAY_LEN 0x2000 4 | char __attribute__((aligned(0x1000))) array[ARRAY_LEN]; 5 | char *secret_pt = &array[(ARRAY_LEN/2)-1]; 6 | 7 | void ecall_set_secret(char b) 8 | { 9 | int i; 10 | 11 | for (i=0; i < ARRAY_LEN; i++) 12 | array[i] = 0x00; 13 | 14 | *secret_pt = b; 15 | } 16 | 17 | char to_lower(char c) 18 | { 19 | if ((c >= 'A') && (c <= 'Z')) 20 | return 'a' + (c - 'A'); 21 | 22 | return c; 23 | } 24 | 25 | int sgx_is_outside_enclave(void *p, size_t len) 26 | { 27 | /* dummy implementation to be able to test w/o SGX support */ 28 | return 1; 29 | } 30 | 31 | void ecall_to_lowercase(char *s) 32 | { 33 | int i; char c; 34 | 35 | /* First ensure the _untrusted_ string lies outside the enclave */ 36 | if (!sgx_is_outside_enclave(s, strlen(s))) 37 | return; 38 | 39 | /* Now transform the string character per character */ 40 | for (i=0; i < strlen(s); i++) 41 | s[i] = to_lower(s[i]); 42 | } 43 | -------------------------------------------------------------------------------- /004-secstr/victim.h: -------------------------------------------------------------------------------- 1 | #ifndef VICTIM_H_INC 2 | #define VICTIM_H_INC 3 | 4 | extern char *secret_pt; 5 | 6 | void ecall_set_secret(char b); 7 | 8 | void ecall_to_lowercase(char *s); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /004-sgx-secstr/.gitignore: -------------------------------------------------------------------------------- 1 | str 2 | -------------------------------------------------------------------------------- /004-sgx-secstr/Enclave/.gitignore: -------------------------------------------------------------------------------- 1 | encl 2 | *.pem 3 | *.a 4 | *.s 5 | *.so 6 | *_u.* 7 | *_t.* 8 | -------------------------------------------------------------------------------- /004-sgx-secstr/Enclave/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | LD = gcc 4 | EDGER = sgx_edger8r 5 | SIGNER = sgx_sign 6 | INCLUDE = -I$(SGX_SDK)/include/ -I$(SGX_SDK)/include/tlibc 7 | T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os 8 | U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g 9 | AR_FLAGS = rcs 10 | OBJECTS = encl.o 11 | LIB_SGX_TRTS = -lsgx_trts 12 | LIB_SGX_TSERVICE = -lsgx_tservice 13 | 14 | ENCLAVE_LIBS = $(LIB_SGX_TRTS) 15 | ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE) 16 | ENCLAVE = encl 17 | PRIVATE_KEY = private_key.pem 18 | PUBLIC_KEY = public_key.pem 19 | KEY_SIZE = 3072 20 | ENCLAVE_EDL = $(ENCLAVE).edl 21 | ENCLAVE_CONFIG = $(ENCLAVE).config.xml 22 | OUTPUT_T = $(ENCLAVE).so 23 | OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so 24 | OUTPUT_U = lib$(ENCLAVE)_proxy.a 25 | LIB_DIRS = -L $(SGX_SDK)/lib64 26 | LD_FLAGS = -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ 27 | -Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \ 28 | -Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \ 29 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 30 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 31 | -Wl,--defsym,__ImageBase=0 32 | TRUSTED_OBJECTS = $(ENCLAVE)_t.o 33 | UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o 34 | TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c 35 | UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c 36 | 37 | #.SILENT: 38 | all: $(OUTPUT_T) $(OUTPUT_U) 39 | 40 | $(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY) 41 | echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG) 42 | $(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG) 43 | 44 | echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG) 45 | $(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null 46 | 47 | $(OUTPUT_U) : $(UNTRUSTED_OBJECTS) 48 | echo "$(INDENT)[AR] " $(OUTPUT_U) 49 | $(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS) 50 | 51 | %_t.o : $(subst .o,.c,$@) edger 52 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)" 53 | touch $(subst .o,.c,$@) 54 | $(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@) 55 | 56 | %_u.o : $(subst .o,.c,$@) edger 57 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)" 58 | touch $(subst .o,.c,$@) 59 | $(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@) 60 | 61 | %.o : %.c edger 62 | echo "$(INDENT)[CC] " $< "(core)" 63 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< 64 | 65 | %.o : %.S 66 | echo "$(INDENT)[AS] " $< "(core)" 67 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@ 68 | 69 | edger: $(ENCLAVE).edl 70 | echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL) 71 | $(EDGER) $(ENCLAVE_EDL) 72 | 73 | .PHONY: force_check 74 | force_check: 75 | true 76 | 77 | .PHONY: scrub 78 | scrub: clean 79 | echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY) 80 | $(RM) $(PRIVATE_KEY) $(PUBLIC_KEY) 81 | 82 | $(PRIVATE_KEY): 83 | echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)" 84 | 85 | # generate 3072 bit private RSA key 86 | openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE) 87 | 88 | echo "$(INDENT)[EXT] $(PUBLIC_KEY)" 89 | # extract public key 90 | openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY) 91 | 92 | # sign enclave 93 | #sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so 94 | 95 | .PHONY: clean 96 | clean: 97 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 98 | $(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 99 | echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 100 | $(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 101 | -------------------------------------------------------------------------------- /004-sgx-secstr/Enclave/encl.c: -------------------------------------------------------------------------------- 1 | #include "encl_t.h" 2 | #include 3 | #include 4 | 5 | #define ARRAY_LEN 0x2000 6 | char __attribute__((aligned(0x1000))) array[ARRAY_LEN]; 7 | char *secret_pt = &array[(ARRAY_LEN/2)-1]; 8 | 9 | void ecall_set_secret(char b) 10 | { 11 | int i; 12 | 13 | for (i=0; i < ARRAY_LEN; i++) 14 | array[i] = 0x00; 15 | 16 | *secret_pt = b; 17 | } 18 | 19 | void *ecall_get_secret_adrs(void) 20 | { 21 | return secret_pt; 22 | } 23 | 24 | char to_lower(char c) 25 | { 26 | if ((c >= 'A') && (c <= 'Z')) 27 | return 'a' + (c - 'A'); 28 | 29 | return c; 30 | } 31 | 32 | void ecall_to_lowercase(char *s) 33 | { 34 | int i; char c; 35 | 36 | /* First ensure the _untrusted_ string lies outside the enclave */ 37 | if (!sgx_is_outside_enclave(s, strlen(s))) 38 | return; 39 | 40 | /* Now transform the string character per character */ 41 | for (i=0; i < strlen(s); i++) 42 | s[i] = to_lower(s[i]); 43 | } 44 | -------------------------------------------------------------------------------- /004-sgx-secstr/Enclave/encl.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x100000 7 | 1 8 | 1 9 | 0 10 | 11 | -------------------------------------------------------------------------------- /004-sgx-secstr/Enclave/encl.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | trusted { 3 | public void ecall_to_lowercase([user_check] char *s); 4 | 5 | public void ecall_set_secret(char b); 6 | public void* ecall_get_secret_adrs(void); 7 | }; 8 | 9 | untrusted { 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /004-sgx-secstr/Makefile: -------------------------------------------------------------------------------- 1 | ENCLAVE = Enclave 2 | SUBDIRS = $(ENCLAVE) 3 | 4 | CC = gcc 5 | AS = gcc 6 | LD = gcc 7 | 8 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 9 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 10 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 11 | LDFLAGS += -lencl_proxy -lsgx_urts \ 12 | -lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib64/ 13 | 14 | SOURCES = $(shell ls *.c ../common/*.c) 15 | OBJECTS = $(SOURCES:.c=.o) 16 | OUTPUT = str 17 | 18 | BUILDDIRS = $(SUBDIRS:%=build-%) 19 | CLEANDIRS = $(SUBDIRS:%=clean-%) 20 | 21 | 22 | .SILENT: 23 | all: $(OUTPUT) 24 | 25 | run: clean all 26 | ./$(OUTPUT) 27 | 28 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 29 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 30 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 31 | 32 | %.o : %.c 33 | echo "$(INDENT)[CC] " $< 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 35 | 36 | %.o : %.S 37 | echo "$(INDENT)[AS] " $< 38 | $(AS) $(INCLUDE) -c $< -o $@ 39 | 40 | clean: $(CLEANDIRS) 41 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 42 | rm -f $(OBJECTS) $(OUTPUT) 43 | 44 | $(BUILDDIRS): 45 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 46 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 47 | 48 | $(CLEANDIRS): 49 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 50 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 51 | -------------------------------------------------------------------------------- /004-sgx-secstr/README.md: -------------------------------------------------------------------------------- 1 | # To lower case: A secure string processing facility 2 | 3 | Subtle side-channel vulnerabilities may arise in unexpected places. In this 4 | exercise we will explore how a seemingly harmless side-channel in one part of 5 | the program, may compromise an unrelated secret in entirely another part of the 6 | program. 7 | 8 | ## Your task 9 | 10 | Consider the following enclave function that securely transforms a provided 11 | input string to lower case characters. 12 | 13 | ```C 14 | void ecall_to_lowercase(char *s) 15 | { 16 | int i; char c; 17 | 18 | /* First ensure the _untrusted_ string lies outside the enclave */ 19 | if (!sgx_is_outside_enclave(s, strlen(s))) 20 | return; 21 | 22 | /* Now transform the string character per character */ 23 | for (i=0; i < strlen(s); i++) 24 | s[i] = to_lower(s[i]); 25 | } 26 | ``` 27 | 28 | The above program is functionally correct. Go over the program line per line, 29 | can you spot the subtle side-channel vulnerability? 30 | 31 | The test enclave provides an `ecall_set_secret` entry point that places a 32 | supposedly secret input value at a specific location inside the enclave (as 33 | with the previous exercise, we provide an explicit `ecall_get_secret_adrs` 34 | entry point to more easily obtain the address of the secret). However, since 35 | the secret is _never_ explicitly used inside the enclave, it should not be 36 | possible for the attacker to obtain its value. 37 | 38 | **Do it yourself.** Modify the untrusted main function to obtain the secret 39 | value by observing side-effects of the `ecall_to_lowercase` enclave function. 40 | 41 | Some guidance notes: 42 | 43 | * Modern Intel processors feature a memory page size of 4096 (0x1000) bytes. 44 | * You can make use of the 45 | [mprotect](http://man7.org/linux/man-pages/man2/mprotect.2.html) library 46 | function to alter page-granular access rights. 47 | * SGX enclaves are loaded at runtime as a shared library object. This means 48 | that all addresses you obtain from an `objdump` need to be incremented with the 49 | base load address of the enclave. Enclave load addresses are 50 | attacker-controlled, and can hence be obtained by modifying the untrusted 51 | runtime, but we already provide you with an `ecall_get_secret_adrs` 52 | function to more easily get started. 53 | * The provided skeleton program already takes care to redirect any page faults 54 | to the `fault_handler` function. 55 | * Make sure to test both with an input `s=1` and `s=0` to make sure your attack 56 | proplerly handles both cases. 57 | 58 | -------------------------------------------------------------------------------- /004-sgx-secstr/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "pf.h" 4 | #include "cacheutils.h" 5 | #include 6 | 7 | /* SGX untrusted runtime */ 8 | #include 9 | #include "Enclave/encl_u.h" 10 | 11 | #define TEST_STRING "DeaDBEeF" 12 | 13 | sgx_enclave_id_t create_enclave(void) 14 | { 15 | sgx_launch_token_t token = {0}; 16 | int updated = 0; 17 | sgx_enclave_id_t eid = -1; 18 | 19 | info_event("Creating enclave..."); 20 | SGX_ASSERT( sgx_create_enclave( "./Enclave/encl.so", /*debug=*/1, 21 | &token, &updated, &eid, NULL ) ); 22 | 23 | return eid; 24 | } 25 | 26 | int fault_fired = 0; 27 | void *s_pt = NULL; 28 | void *page_pt = NULL; 29 | 30 | void fault_handler(void *base_adrs) 31 | { 32 | /* =========================== START SOLUTION =========================== */ 33 | /* =========================== END SOLUTION =========================== */ 34 | 35 | fault_fired++; 36 | } 37 | 38 | int main( int argc, char **argv ) 39 | { 40 | sgx_enclave_id_t eid = create_enclave(); 41 | int rv = 1, secret = 0; 42 | char *string; 43 | 44 | /* ---------------------------------------------------------------------- */ 45 | info("registering fault handler.."); 46 | register_fault_handler(fault_handler); 47 | 48 | SGX_ASSERT( ecall_get_secret_adrs(eid, &s_pt) ); 49 | info("secret at %p\n", s_pt); 50 | 51 | /* ---------------------------------------------------------------------- */ 52 | info_event("Calling enclave.."); 53 | string = malloc(strlen(TEST_STRING)+1); 54 | strcpy(string, TEST_STRING); 55 | SGX_ASSERT( ecall_to_lowercase(eid, string) ); 56 | info("secure enclave converted '%s' to '%s'", TEST_STRING, string); 57 | 58 | /* =========================== START SOLUTION =========================== */ 59 | /* =========================== END SOLUTION =========================== */ 60 | 61 | info_event("destroying SGX enclave"); 62 | SGX_ASSERT( sgx_destroy_enclave( eid ) ); 63 | 64 | info("all is well; exiting.."); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /005-rsa/.gitignore: -------------------------------------------------------------------------------- 1 | rsa 2 | -------------------------------------------------------------------------------- /005-rsa/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AS = gcc 3 | LD = gcc 4 | 5 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 6 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 7 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 8 | 9 | SOURCES = $(shell ls *.c ../common/*.c) 10 | OBJECTS = $(SOURCES:.c=.o) asm.o 11 | OUTPUT = rsa 12 | 13 | BUILDDIRS = $(SUBDIRS:%=build-%) 14 | CLEANDIRS = $(SUBDIRS:%=clean-%) 15 | 16 | 17 | .SILENT: 18 | all: $(OUTPUT) 19 | 20 | run: clean all 21 | ./$(OUTPUT) 22 | 23 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 24 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 25 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 26 | 27 | %.o : %.c 28 | echo "$(INDENT)[CC] " $< 29 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 30 | 31 | %.o : %.S 32 | echo "$(INDENT)[AS] " $< 33 | $(AS) $(INCLUDE) -c $< -o $@ 34 | 35 | clean: $(CLEANDIRS) 36 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 37 | rm -f $(OBJECTS) $(OUTPUT) 38 | 39 | $(BUILDDIRS): 40 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 41 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 42 | 43 | $(CLEANDIRS): 44 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 45 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 46 | -------------------------------------------------------------------------------- /005-rsa/README.md: -------------------------------------------------------------------------------- 1 | # RSA: An elementary 16-bit crypto attack scenario 2 | 3 | Cryptographic software is widely studied in side-channel attack research. This 4 | exercise considers a toy enclave that implements a basic 16-bit version of the 5 | RSA cryptosystem using the square-and-multiply algorithm with message blinding 6 | protection. The implementation is definitely not meant to be cryptographically 7 | secure, but serves as an elementary case study application to analyze 8 | side-channel leakage in enclave programs. 9 | 10 | ## Background: Square and multiply 11 | 12 | Modular exponentiation is the main ingredient of public key 13 | algorithms such as RSA, and is commonly implemented using the 14 | _square-and-multiply_ algorithm. To compute _m = c^d_, square-and-multiply 15 | iterates over the binary representation of _d_, repeatedly squaring _m_ each 16 | iteration, and performing an extra multiplication of _m_ with _c_ in case the 17 | bit in _d_ was set. Square-and-multiply thus branches on a secret each loop 18 | iteration, making it a widely studied algorithm in side-channel analysis 19 | research. Furthermore, naive implementations are known to be vulnerable to a 20 | classical start-to-end execution timing attack that supplies carefully crafted 21 | input messages to yield a measurable difference for individual key bits in the 22 | total runtime of the program. The recommended countermeasure for this type of 23 | timing attacks involves _message blinding_, where the input is masked with a 24 | random factor before modular exponentiation takes place, and afterwards 25 | canceled out. 26 | 27 | ## Your task 28 | 29 | Your job is to extract the 16-bit private RSA key by observing side-effects 30 | of the `ecall_rsa_decode` enclave entry point, which internally executes 31 | square-and-multiply by iterating over the private key bits: 32 | 33 | ```C 34 | int modpow(long long a, long long b, long long n) 35 | { 36 | long long res = 1; 37 | uint16_t mask = 0x8000; 38 | 39 | for (int i=15; i >= 0; i--) 40 | { 41 | res = square(res, n); 42 | if (b & mask) 43 | res = multiply(res, a, n); 44 | mask = mask >> 1; 45 | } 46 | return res; 47 | } 48 | ``` 49 | 50 | **Note.** Real-world crypto libraries typically offer specialized helper 51 | functions to multiply big numbers. This is abstracted in our rudimentary 16-bit 52 | implementation by the dedicated `square` and `multiply` functions. 53 | 54 | Some further guidance: 55 | 56 | * Page-aligned assembly versions of the functions `square`, `multiply`, and 57 | `modpow` are declared in `asm.S`, and are for this exercise explicitly 58 | allocated on separate code pages. (Again, note that this is often the case 59 | in real-world crypto libraries due to the complexity of the big number 60 | computation functions.) 61 | * Simply monitoring the accesses on either `square` or `multiply` won't get you 62 | far, as this only reveals the _total_ number of one bits in the private key 63 | (which is supposed to be randomly distributed anyway). 64 | * To reveal _individual_ private key bits, you will have to monitor the **page 65 | fault sequences** of the `square`, `multiply`, and `modpow` code pages with a 66 | simple state machine as follows: 67 | 68 | ![state-machine](state-machine.png) 69 | 70 | * Be aware that `ecall_rsa_decode` first performs blinding on the input 71 | parameter through a `modpow` call with a _known_ exponent (rsa_e). As such, 72 | your attacker code will have to ignore the first call to `modpow` and only 73 | focus on page fault side-effects of the second `modpow` invocation with 74 | the secret argument (rsa_d). You can start with commenting out the first 75 | `modpow` call if that helps. 76 | 77 | ### Launching the attack on real SGX hardware 78 | 79 | Now you have the proof-of-concept attack working in an _unprotected_ 80 | application on your own laptop, proceed to the `../005-sgx-rsa` program 81 | to try and port your attack to a real Intel x86 SGX processor. 82 | -------------------------------------------------------------------------------- /005-rsa/asm.S: -------------------------------------------------------------------------------- 1 | .text 2 | .global square 3 | .align 0x1000 /* 4KiB */ 4 | square: 5 | mov %rdi,%rax 6 | xor %edx,%edx 7 | imul %rdi,%rax 8 | div %rsi 9 | mov %rdx,%rax 10 | retq 11 | .space 0x1000 /* 4KiB */ 12 | 13 | .text 14 | .global multiply 15 | .align 0x1000 /* 4KiB */ 16 | multiply: 17 | mov %rdi,%rax 18 | mov %rdx,%rcx 19 | xor %edx,%edx 20 | imul %rsi,%rax 21 | div %rcx 22 | mov %rdx,%rax 23 | retq 24 | .space 0x1000 /* 4KiB */ 25 | 26 | .text 27 | .global modpow 28 | .align 0x1000 /* 4KiB */ 29 | modpow: 30 | push %rbp 31 | mov %rsp,%rbp 32 | sub $0x30,%rsp 33 | mov %rdi,-0x18(%rbp) 34 | mov %rsi,-0x20(%rbp) 35 | mov %rdx,-0x28(%rbp) 36 | movq $0x1,-0x8(%rbp) 37 | movw $0x8000,-0xa(%rbp) 38 | movl $0xf,-0x10(%rbp) 39 | jmp 3f 40 | 1: 41 | mov -0x28(%rbp),%rdx 42 | mov -0x8(%rbp),%rax 43 | mov %rdx,%rsi 44 | mov %rax,%rdi 45 | callq square 46 | mov %rax,-0x8(%rbp) 47 | movzwl -0xa(%rbp),%eax 48 | and -0x20(%rbp),%rax 49 | test %rax,%rax 50 | je 2f 51 | mov -0x28(%rbp),%rdx 52 | mov -0x18(%rbp),%rcx 53 | mov -0x8(%rbp),%rax 54 | mov %rcx,%rsi 55 | mov %rax,%rdi 56 | callq multiply 57 | mov %rax,-0x8(%rbp) 58 | 2: 59 | shrw -0xa(%rbp) 60 | subl $0x1,-0x10(%rbp) 61 | 3: 62 | cmpl $0x0,-0x10(%rbp) 63 | jns 1b 64 | mov -0x8(%rbp),%rax 65 | leaveq 66 | retq 67 | 68 | .space 0x1000 /* 4KiB */ 69 | -------------------------------------------------------------------------------- /005-rsa/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "pf.h" 4 | #include "cacheutils.h" 5 | #include 6 | #include "victim.h" 7 | 8 | #define RSA_TEST_VAL 1234 9 | 10 | int fault_fired = 0; 11 | void *sq_pt = NULL, *mul_pt = NULL, *modpow_pt = NULL; 12 | 13 | /* =========================== START SOLUTION =========================== */ 14 | /* =========================== END SOLUTION =========================== */ 15 | 16 | void fault_handler(void *base_adrs) 17 | { 18 | /* =========================== START SOLUTION =========================== */ 19 | /* =========================== END SOLUTION =========================== */ 20 | 21 | fault_fired++; 22 | } 23 | 24 | int main( int argc, char **argv ) 25 | { 26 | int rv = 1, secret = 0; 27 | int cipher, plain; 28 | 29 | /* ---------------------------------------------------------------------- */ 30 | info("registering fault handler.."); 31 | register_fault_handler(fault_handler); 32 | 33 | /* ---------------------------------------------------------------------- */ 34 | info_event("Calling enclave.."); 35 | sq_pt = square; 36 | mul_pt = multiply; 37 | modpow_pt = GET_PFN(modpow); 38 | info("square at %p; muliply at %p; modpow at %p", sq_pt, mul_pt, modpow_pt); 39 | 40 | cipher = ecall_rsa_encode(RSA_TEST_VAL); 41 | plain = ecall_rsa_decode(cipher); 42 | info("secure enclave encrypted '%d' to '%d'; decrypted '%d'", RSA_TEST_VAL, cipher, plain); 43 | 44 | /* =========================== START SOLUTION =========================== */ 45 | /* =========================== END SOLUTION =========================== */ 46 | 47 | info("all is well; exiting.."); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /005-rsa/sample-out.txt: -------------------------------------------------------------------------------- 1 | [RM] ../common/debug.o ../common/pf.o main.o victim.o asm.o rsa 2 | [CC] ../common/debug.c 3 | [CC] ../common/pf.c 4 | [CC] main.c 5 | [CC] victim.c 6 | [AS] asm.S 7 | [LD] ../common/debug.o ../common/pf.o main.o victim.o asm.o -o rsa 8 | [main.c] registering fault handler.. 9 | 10 | -------------------------------------------------------------------------------- 11 | [main.c] Calling enclave.. 12 | -------------------------------------------------------------------------------- 13 | 14 | [main.c] square at 0x402000; muliply at 0x404000; modpow at 0x406000 15 | [../common/pf.c] Caught page fault (base address=0x402000) 16 | 17 | -------------------------------------------------------------------------------- 18 | [main.c] MODPOW INVOCATION 19 | -------------------------------------------------------------------------------- 20 | 21 | [../common/pf.c] Caught page fault (base address=0x40603e) 22 | [../common/pf.c] Caught page fault (base address=0x402000) 23 | [../common/pf.c] Caught page fault (base address=0x40603e) 24 | [../common/pf.c] Caught page fault (base address=0x402000) 25 | [../common/pf.c] Caught page fault (base address=0x40603e) 26 | [../common/pf.c] Caught page fault (base address=0x402000) 27 | [../common/pf.c] Caught page fault (base address=0x40603e) 28 | [../common/pf.c] Caught page fault (base address=0x402000) 29 | [../common/pf.c] Caught page fault (base address=0x40603e) 30 | [../common/pf.c] Caught page fault (base address=0x402000) 31 | [../common/pf.c] Caught page fault (base address=0x40603e) 32 | [../common/pf.c] Caught page fault (base address=0x402000) 33 | [../common/pf.c] Caught page fault (base address=0x40603e) 34 | [../common/pf.c] Caught page fault (base address=0x402000) 35 | [../common/pf.c] Caught page fault (base address=0x40603e) 36 | [../common/pf.c] Caught page fault (base address=0x402000) 37 | [../common/pf.c] Caught page fault (base address=0x40603e) 38 | [../common/pf.c] Caught page fault (base address=0x402000) 39 | [../common/pf.c] Caught page fault (base address=0x40603e) 40 | [../common/pf.c] Caught page fault (base address=0x402000) 41 | [../common/pf.c] Caught page fault (base address=0x40603e) 42 | [../common/pf.c] Caught page fault (base address=0x402000) 43 | [../common/pf.c] Caught page fault (base address=0x40603e) 44 | [../common/pf.c] Caught page fault (base address=0x402000) 45 | [../common/pf.c] Caught page fault (base address=0x40603e) 46 | [../common/pf.c] Caught page fault (base address=0x404000) 47 | [../common/pf.c] Caught page fault (base address=0x406066) 48 | [../common/pf.c] Caught page fault (base address=0x402000) 49 | [../common/pf.c] Caught page fault (base address=0x40603e) 50 | [../common/pf.c] Caught page fault (base address=0x402000) 51 | [../common/pf.c] Caught page fault (base address=0x40603e) 52 | [../common/pf.c] Caught page fault (base address=0x404000) 53 | [../common/pf.c] Caught page fault (base address=0x406066) 54 | [../common/pf.c] Caught page fault (base address=0x402000) 55 | [../common/pf.c] Caught page fault (base address=0x40603e) 56 | [../common/pf.c] Caught page fault (base address=0x404000) 57 | [../common/pf.c] Caught page fault (base address=0x406066) 58 | [../common/pf.c] Caught page fault (base address=0x402000) 59 | 60 | -------------------------------------------------------------------------------- 61 | [main.c] MODPOW INVOCATION 62 | -------------------------------------------------------------------------------- 63 | 64 | [../common/pf.c] Caught page fault (base address=0x40603e) 65 | [../common/pf.c] Caught page fault (base address=0x402000) 66 | [../common/pf.c] Caught page fault (base address=0x40603e) 67 | [../common/pf.c] Caught page fault (base address=0x404000) 68 | [../common/pf.c] Caught page fault (base address=0x406066) 69 | [../common/pf.c] Caught page fault (base address=0x402000) 70 | [../common/pf.c] Caught page fault (base address=0x40603e) 71 | [../common/pf.c] Caught page fault (base address=0x402000) 72 | [../common/pf.c] Caught page fault (base address=0x40603e) 73 | [../common/pf.c] Caught page fault (base address=0x404000) 74 | [../common/pf.c] Caught page fault (base address=0x406066) 75 | [../common/pf.c] Caught page fault (base address=0x402000) 76 | [../common/pf.c] Caught page fault (base address=0x40603e) 77 | [../common/pf.c] Caught page fault (base address=0x402000) 78 | [../common/pf.c] Caught page fault (base address=0x40603e) 79 | [../common/pf.c] Caught page fault (base address=0x402000) 80 | [../common/pf.c] Caught page fault (base address=0x40603e) 81 | [../common/pf.c] Caught page fault (base address=0x402000) 82 | [../common/pf.c] Caught page fault (base address=0x40603e) 83 | [../common/pf.c] Caught page fault (base address=0x404000) 84 | [../common/pf.c] Caught page fault (base address=0x406066) 85 | [../common/pf.c] Caught page fault (base address=0x402000) 86 | [../common/pf.c] Caught page fault (base address=0x40603e) 87 | [../common/pf.c] Caught page fault (base address=0x402000) 88 | [../common/pf.c] Caught page fault (base address=0x40603e) 89 | [../common/pf.c] Caught page fault (base address=0x402000) 90 | [../common/pf.c] Caught page fault (base address=0x40603e) 91 | [../common/pf.c] Caught page fault (base address=0x404000) 92 | [../common/pf.c] Caught page fault (base address=0x406066) 93 | [../common/pf.c] Caught page fault (base address=0x402000) 94 | [../common/pf.c] Caught page fault (base address=0x40603e) 95 | [../common/pf.c] Caught page fault (base address=0x402000) 96 | [../common/pf.c] Caught page fault (base address=0x40603e) 97 | [../common/pf.c] Caught page fault (base address=0x402000) 98 | [../common/pf.c] Caught page fault (base address=0x40603e) 99 | [../common/pf.c] Caught page fault (base address=0x402000) 100 | [../common/pf.c] Caught page fault (base address=0x40603e) 101 | [../common/pf.c] Caught page fault (base address=0x404000) 102 | [../common/pf.c] Caught page fault (base address=0x406066) 103 | [../common/pf.c] Caught page fault (base address=0x402000) 104 | [../common/pf.c] Caught page fault (base address=0x40603e) 105 | [../common/pf.c] Caught page fault (base address=0x404000) 106 | [../common/pf.c] Caught page fault (base address=0x406066) 107 | [main.c] secure enclave encrypted '1234' to '21921'; decrypted '1234' 108 | [main.c] --> RECONSTRUCTED KEY '20771' (0x5123) 109 | [main.c] all is well; exiting.. 110 | -------------------------------------------------------------------------------- /005-rsa/state-machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/005-rsa/state-machine.png -------------------------------------------------------------------------------- /005-rsa/state-machine.xml: -------------------------------------------------------------------------------- 1 | 7Vltc+I2EP41fISxJdnYH0NyuXbmrk2Htrm7b8IWoImxqCwCuV9fCUvGkp2EF0PJTPOBWKv16mVXz7Na9+DtYvOZ4+X8K0tJ1gNeuunBux4AkR/IXyV4KQXICGacpqXI3wnG9CfRQk9LVzQlhaUoGMsEXdrChOU5SYQlw5yzta02ZZk96hLPSEMwTnDWlD7SVMz1skC4k/9C6GxuRvbDuOxZYKOsV1LMccrWNRH81IO3nDFRPi02tyRTe2f2pXzv/pXeamKc5GKfF/roz+EjWL7g+/jvX8d3P377+eVHX1t5xtlKL7gHwkzaG02ZNCtnLV70VoT/rJjp6BdbR91IBT9abnad8mmm/2+tTIxg/IcRyRlOXDUpK8czYmANDeRKpMNlY7SeU0HGS5yonrUMOSmbi0UmW758xMWyjIIp3ZBUzZZm2S3LGN8agmlAohRJeSE4eyK1nghMYBhWg9f31WwS4YJsaiK9z58JWxDBX6SK7oVQ+1wHPTDtdS2EtGheix4jwzpoZ5XlnV/lg3btAW4Gl3Lz17++XIWfp1FCkqTNz5MoQIHXjZ+D4ZX5OWzxs7vFeXqjcFG2cpYTe1uTFX9W27ltFAJzYXSTDBcFTYz4nmbmHWlQt9Sukg0V30yPfP6u5INgqydX+M1uftear/qiYCuekLcATK9QTmpGxPtHgKQW3jddW3Nd0OI6I+Mkw4I+2yzR5k89wgOj24NmIsdBCDh0QqJcuH6rjuqOIRg5htzYKjemYUj6Fb/U1JZKoXhjwnH7OLtoLS3uYrfa0+PD2e+AntBbuEWNgBOx4nkNpqir2g1QNsxOeAtGNrQauLkfnEoYE/YB50TOFE+2Cuq4ardL7WDUC+4UsmZ0lqsDL48ikZg5UnBIZUJ0ozsWNE3V+6MMT0g2wsnTjLNVntbRd/vXeq7fhC0XeKu0Ts/YypzaANkbABRAK1ANQJx4YPvKeGBZ7kMjMGbYdFoQ4ZyLTk6CSSKv4ST8H3WNqENDz7diI+gk6BohF18q3qITE4ka2asrYI3uvYE8kU6mYZIGb+B5gZU4hBAenYmoER8Ip3IvVEhV6YkrOz752Df3MBh0JckH8h0u949MPoIYDSIvDlQ2oH6HtlkvGoAoGPpI/54nMXEWA+ILJCbx6Wh8WJpwGsg/EbWjE6pM+O/kFEcmJB+UAwzOncwBfYlrYRTboTjshgUChwUulnUY3LpA3eD3u4fHq6gcpJhE09bKQZhEZNIeWwdXDhByIBj9x5UDHx7E+DsSbiP9qlG7/VcUbxG8mwkcz8V7FwL8q+Liyo6pjx9dCPAcQ+A8hQDkFBzARQoBw1eBKKXPZ2bPjLGlmqAkJelplr9DoK/QpTXPD8qWFUh0QZfIsy/qcSfnyWbgPnIMnJErUYcAKi9CPrJBFA4rDfcC0xWC7gug13WbAQ6VIpcj90VQ4JQ4ETwPgjZKtvqT4XkR9LBPA++EZ8+p3+8XgR8tsqAbEC6l7s3NzneiKvvrmptBewQfGVmyufs8XarvvvHDT/8C -------------------------------------------------------------------------------- /005-rsa/victim.c: -------------------------------------------------------------------------------- 1 | #include "victim.h" 2 | 3 | /* 4 | * Compute n^-1 mod m by extended euclidian method. 5 | * (from https://github.com/pantaloons/RSA/blob/master/single.c) 6 | */ 7 | int inverse(int n, int modulus) 8 | { 9 | int a = n, b = modulus; 10 | int x = 0, y = 1, x0 = 1, y0 = 0, q, temp; 11 | while (b != 0) 12 | { 13 | q = a / b; 14 | temp = a % b; 15 | a = b; 16 | b = temp; 17 | temp = x; x = x0 - q * x; x0 = temp; 18 | temp = y; y = y0 - q * y; y0 = temp; 19 | } 20 | if (x0 < 0) x0 += modulus; 21 | return x0; 22 | } 23 | 24 | /* 25 | * NOTE: we provide a page-aligned assembly version of this function in asm.S 26 | * to ease the attack. 27 | */ 28 | long long c_square(long long a, long long n) 29 | { 30 | return (a * a) % n; 31 | } 32 | 33 | /* 34 | * NOTE: we provide a page-aligned assembly version of this function in asm.S 35 | * to ease the attack. 36 | */ 37 | long long c_multiply(long long a, long long b, long long n) 38 | { 39 | return (a * b) % n; 40 | } 41 | 42 | /* 43 | * Computes a^b mod n. 44 | * (long long multiplication prevents overflow) 45 | * 46 | * NOTE: we provide a page-aligned assembly version of this function in asm.S 47 | * to ease the attack. 48 | */ 49 | int c_modpow(long long a, long long b, long long n) 50 | { 51 | long long res = 1; 52 | uint16_t mask = 0x8000; 53 | 54 | for (int i=15; i >= 0; i--) 55 | { 56 | res = square(res, n); 57 | if (b & mask) 58 | res = multiply(res, a, n); 59 | mask = mask >> 1; 60 | } 61 | return res; 62 | } 63 | 64 | /* 65 | * Example RSA key with p = 137 and q = 421. 66 | */ 67 | int rsa_n = 57677; 68 | int rsa_e = 11; 69 | int rsa_d = 20771; //16'b0101000100100011 70 | 71 | #define SGX_SUCCESS 0 72 | int sgx_read_rand(unsigned char *rand, int len) 73 | { 74 | /* Dummy implementation to be able to test w/o SGX support. */ 75 | for (int i= 0; i < len; i++) 76 | rand[i] = 0xab; 77 | return SGX_SUCCESS; 78 | } 79 | 80 | int ecall_rsa_decode(int cipher) 81 | { 82 | int i, mask, r = 0; 83 | long long res; 84 | 85 | /* Blinding with 16-bit random factor. */ 86 | if (sgx_read_rand((unsigned char*) &r, 2) 87 | != SGX_SUCCESS) return 0; 88 | cipher = cipher * modpow(r, rsa_e, rsa_n); 89 | 90 | /* Decrypt blinded message with square and multiply algorithm. */ 91 | res = modpow(cipher, rsa_d, rsa_n); 92 | 93 | /* Unblind result. */ 94 | return (res * inverse(r, rsa_n)) % rsa_n; 95 | } 96 | 97 | int ecall_rsa_encode(int plain) 98 | { 99 | return modpow(plain, rsa_e, rsa_n); 100 | } 101 | -------------------------------------------------------------------------------- /005-rsa/victim.h: -------------------------------------------------------------------------------- 1 | #ifndef VICTIM_H_INC 2 | #define VICTIM_H_INC 3 | 4 | #include 5 | 6 | /* See asm.S */ 7 | uint64_t square(uint64_t a, uint64_t n); 8 | uint64_t multiply(uint64_t a, uint64_t b, uint64_t n); 9 | int modpow(long long a, long long b, long long n); 10 | 11 | int ecall_rsa_encode(int plain); 12 | int ecall_rsa_decode(int cipher); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /005-sgx-rsa/.gitignore: -------------------------------------------------------------------------------- 1 | rsa 2 | -------------------------------------------------------------------------------- /005-sgx-rsa/Enclave/.gitignore: -------------------------------------------------------------------------------- 1 | encl 2 | *.pem 3 | *.a 4 | *.s 5 | *.so 6 | *_u.* 7 | *_t.* 8 | -------------------------------------------------------------------------------- /005-sgx-rsa/Enclave/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | LD = gcc 4 | EDGER = sgx_edger8r 5 | SIGNER = sgx_sign 6 | INCLUDE = -I$(SGX_SDK)/include/ -I$(SGX_SDK)/include/tlibc 7 | T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os 8 | U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g 9 | AR_FLAGS = rcs 10 | OBJECTS = encl.o asm.o 11 | LIB_SGX_TRTS = -lsgx_trts 12 | LIB_SGX_TSERVICE = -lsgx_tservice 13 | 14 | ENCLAVE_LIBS = $(LIB_SGX_TRTS) 15 | ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE) 16 | ENCLAVE = encl 17 | PRIVATE_KEY = private_key.pem 18 | PUBLIC_KEY = public_key.pem 19 | KEY_SIZE = 3072 20 | ENCLAVE_EDL = $(ENCLAVE).edl 21 | ENCLAVE_CONFIG = $(ENCLAVE).config.xml 22 | OUTPUT_T = $(ENCLAVE).so 23 | OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so 24 | OUTPUT_U = lib$(ENCLAVE)_proxy.a 25 | LIB_DIRS = -L $(SGX_SDK)/lib64 26 | LD_FLAGS = -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ 27 | -Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \ 28 | -Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \ 29 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 30 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 31 | -Wl,--defsym,__ImageBase=0 32 | TRUSTED_OBJECTS = $(ENCLAVE)_t.o 33 | UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o 34 | TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c 35 | UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c 36 | 37 | #.SILENT: 38 | all: $(OUTPUT_T) $(OUTPUT_U) 39 | 40 | $(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY) 41 | echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG) 42 | $(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG) 43 | 44 | echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG) 45 | $(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null 46 | 47 | $(OUTPUT_U) : $(UNTRUSTED_OBJECTS) 48 | echo "$(INDENT)[AR] " $(OUTPUT_U) 49 | $(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS) 50 | 51 | %_t.o : $(subst .o,.c,$@) edger 52 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)" 53 | touch $(subst .o,.c,$@) 54 | $(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@) 55 | 56 | %_u.o : $(subst .o,.c,$@) edger 57 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)" 58 | touch $(subst .o,.c,$@) 59 | $(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@) 60 | 61 | %.o : %.c edger 62 | echo "$(INDENT)[CC] " $< "(core)" 63 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< 64 | 65 | %.o : %.S 66 | echo "$(INDENT)[AS] " $< "(core)" 67 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@ 68 | 69 | edger: $(ENCLAVE).edl 70 | echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL) 71 | $(EDGER) $(ENCLAVE_EDL) 72 | 73 | .PHONY: force_check 74 | force_check: 75 | true 76 | 77 | .PHONY: scrub 78 | scrub: clean 79 | echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY) 80 | $(RM) $(PRIVATE_KEY) $(PUBLIC_KEY) 81 | 82 | $(PRIVATE_KEY): 83 | echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)" 84 | 85 | # generate 3072 bit private RSA key 86 | openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE) 87 | 88 | echo "$(INDENT)[EXT] $(PUBLIC_KEY)" 89 | # extract public key 90 | openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY) 91 | 92 | # sign enclave 93 | #sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so 94 | 95 | .PHONY: clean 96 | clean: 97 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 98 | $(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 99 | echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 100 | $(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 101 | -------------------------------------------------------------------------------- /005-sgx-rsa/Enclave/asm.S: -------------------------------------------------------------------------------- 1 | .text 2 | .global square 3 | .align 0x1000 /* 4KiB */ 4 | square: 5 | mov %rdi,%rax 6 | xor %edx,%edx 7 | imul %rdi,%rax 8 | div %rsi 9 | mov %rdx,%rax 10 | retq 11 | .space 0x1000 /* 4KiB */ 12 | 13 | .text 14 | .global multiply 15 | .align 0x1000 /* 4KiB */ 16 | multiply: 17 | mov %rdi,%rax 18 | mov %rdx,%rcx 19 | xor %edx,%edx 20 | imul %rsi,%rax 21 | div %rcx 22 | mov %rdx,%rax 23 | retq 24 | .space 0x1000 /* 4KiB */ 25 | -------------------------------------------------------------------------------- /005-sgx-rsa/Enclave/encl.c: -------------------------------------------------------------------------------- 1 | #include "encl_t.h" 2 | #include 3 | 4 | /* 5 | * Compute n^-1 mod m by extended euclidian method. 6 | * (from https://github.com/pantaloons/RSA/blob/master/single.c) 7 | */ 8 | int inverse(int n, int modulus) 9 | { 10 | int a = n, b = modulus; 11 | int x = 0, y = 1, x0 = 1, y0 = 0, q, temp; 12 | while (b != 0) 13 | { 14 | q = a / b; 15 | temp = a % b; 16 | a = b; 17 | b = temp; 18 | temp = x; x = x0 - q * x; x0 = temp; 19 | temp = y; y = y0 - q * y; y0 = temp; 20 | } 21 | if (x0 < 0) x0 += modulus; 22 | return x0; 23 | } 24 | 25 | /* 26 | * NOTE: we provide a page-aligned assembly version of this function in asm.S 27 | * to ease the attack. 28 | */ 29 | long long c_square(long long a, long long n) 30 | { 31 | return (a * a) % n; 32 | } 33 | 34 | /* 35 | * NOTE: we provide a page-aligned assembly version of this function in asm.S 36 | * to ease the attack. 37 | */ 38 | long long c_multiply(long long a, long long b, long long n) 39 | { 40 | return (a * b) % n; 41 | } 42 | 43 | /* See asm.S */ 44 | uint64_t square(uint64_t a, uint64_t n); 45 | uint64_t multiply(uint64_t a, uint64_t b, uint64_t n); 46 | 47 | /* 48 | * Computes a^b mod n. 49 | * (long long multiplication prevents overflow) 50 | */ 51 | int modpow(long long a, long long b, long long n) 52 | { 53 | long long res = 1; 54 | uint16_t mask = 0x8000; 55 | 56 | for (int i=15; i >= 0; i--) 57 | { 58 | res = square(res, n); 59 | if (b & mask) 60 | res = multiply(res, a, n); 61 | mask = mask >> 1; 62 | } 63 | return res; 64 | } 65 | 66 | /* 67 | * Example RSA key with p = 137 and q = 421. 68 | */ 69 | int rsa_n = 57677; 70 | int rsa_e = 11; 71 | int rsa_d = 20771; //16'b0101000100100011 72 | 73 | int ecall_rsa_decode(int cipher) 74 | { 75 | int i, mask, r = 0; 76 | long long res; 77 | 78 | /* Blinding with 16-bit random factor. */ 79 | if (sgx_read_rand((unsigned char*) &r, 2) 80 | != SGX_SUCCESS) return 0; 81 | cipher = cipher * modpow(r, rsa_e, rsa_n); 82 | 83 | /* Decrypt blinded message with square and multiply algorithm. */ 84 | res = modpow(cipher, rsa_d, rsa_n); 85 | 86 | /* Unblind result. */ 87 | return (res * inverse(r, rsa_n)) % rsa_n; 88 | } 89 | 90 | int ecall_rsa_encode(int plain) 91 | { 92 | return modpow(plain, rsa_e, rsa_n); 93 | } 94 | 95 | void *ecall_get_square_adrs(void) 96 | { 97 | return square; 98 | } 99 | 100 | void *ecall_get_multiply_adrs(void) 101 | { 102 | return multiply; 103 | } 104 | 105 | void *ecall_get_modpow_adrs(void) 106 | { 107 | return modpow; 108 | } 109 | -------------------------------------------------------------------------------- /005-sgx-rsa/Enclave/encl.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x100000 7 | 1 8 | 1 9 | 0 10 | 11 | -------------------------------------------------------------------------------- /005-sgx-rsa/Enclave/encl.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | trusted { 3 | public int ecall_rsa_encode(int plain); 4 | public int ecall_rsa_decode(int cipher); 5 | 6 | public void *ecall_get_square_adrs(void); 7 | public void *ecall_get_multiply_adrs(void); 8 | public void *ecall_get_modpow_adrs(void); 9 | }; 10 | 11 | untrusted { 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /005-sgx-rsa/Makefile: -------------------------------------------------------------------------------- 1 | ENCLAVE = Enclave 2 | SUBDIRS = $(ENCLAVE) 3 | 4 | CC = gcc 5 | AS = gcc 6 | LD = gcc 7 | 8 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 9 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 10 | INCLUDE = -I$(SGX_SDK)/include/ -I../common/ 11 | LDFLAGS += -lencl_proxy -lsgx_urts \ 12 | -lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib64/ 13 | 14 | SOURCES = $(shell ls *.c ../common/*.c) 15 | OBJECTS = $(SOURCES:.c=.o) 16 | OUTPUT = rsa 17 | 18 | BUILDDIRS = $(SUBDIRS:%=build-%) 19 | CLEANDIRS = $(SUBDIRS:%=clean-%) 20 | 21 | 22 | .SILENT: 23 | all: $(OUTPUT) 24 | 25 | run: clean all 26 | ./$(OUTPUT) 27 | 28 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 29 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 30 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 31 | 32 | %.o : %.c 33 | echo "$(INDENT)[CC] " $< 34 | $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 35 | 36 | %.o : %.S 37 | echo "$(INDENT)[AS] " $< 38 | $(AS) $(INCLUDE) -c $< -o $@ 39 | 40 | clean: $(CLEANDIRS) 41 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 42 | rm -f $(OBJECTS) $(OUTPUT) 43 | 44 | $(BUILDDIRS): 45 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 46 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 47 | 48 | $(CLEANDIRS): 49 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 50 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 51 | -------------------------------------------------------------------------------- /005-sgx-rsa/README.md: -------------------------------------------------------------------------------- 1 | # RSA: An elementary 16-bit crypto attack scenario 2 | 3 | Cryptographic software is widely studied in side-channel attack research. This 4 | exercise considers a toy enclave that implements a basic 16-bit version of the 5 | RSA cryptosystem using the square-and-multiply algorithm with message blinding 6 | protection. The implementation is definitely not meant to be cryptographically 7 | secure, but serves as an elementary case study application to analyze 8 | side-channel leakage in enclave programs. 9 | 10 | ## Background: Square and multiply 11 | 12 | Modular exponentiation is the main ingredient of public key 13 | algorithms such as RSA, and is commonly implemented using the 14 | _square-and-multiply_ algorithm. To compute _m = c^d_, square-and-multiply 15 | iterates over the binary representation of _d_, repeatedly squaring _m_ each 16 | iteration, and performing an extra multiplication of _m_ with _c_ in case the 17 | bit in _d_ was set. Square-and-multiply thus branches on a secret each loop 18 | iteration, making it a widely studied algorithm in side-channel analysis 19 | research. Furthermore, naive implementations are known to be vulnerable to a 20 | classical start-to-end execution timing attack that supplies carefully crafted 21 | input messages to yield a measurable difference for individual key bits in the 22 | total runtime of the program. The recommended countermeasure for this type of 23 | timing attacks involves _message blinding_, where the input is masked with a 24 | random factor before modular exponentiation takes place, and afterwards 25 | canceled out. 26 | 27 | ## Your task 28 | 29 | Your job is to extract the 16-bit private RSA key by observing side-effects 30 | of the `ecall_rsa_decode` enclave entry point, which internally executes 31 | square-and-multiply by iterating over the private key bits: 32 | 33 | ```C 34 | int modpow(long long a, long long b, long long n) 35 | { 36 | long long res = 1; 37 | uint16_t mask = 0x8000; 38 | 39 | for (int i=15; i >= 0; i--) 40 | { 41 | res = square(res, n); 42 | if (b & mask) 43 | res = multiply(res, a, n); 44 | mask = mask >> 1; 45 | } 46 | return res; 47 | } 48 | ``` 49 | 50 | **Note.** Real-world crypto libraries typically offer specialized helper 51 | functions to multiply big numbers. This is abstracted in our rudimentary 16-bit 52 | implementation by the dedicated `square` and `multiply` functions. 53 | 54 | Some further guidance: 55 | 56 | * The helper functions `square` and `multiply` are declared in `asm.S`, and are for 57 | this exercise explicitly allocated on separate code pages. (Again, note that 58 | this is often the case in real-world crypto libraries due to the complexity of 59 | the big number computation functions.) 60 | * **For the enclave version, `modpow` is not expliticly aligned to a dedicated 61 | code page.** As such, the code for `modpow` may share a memory page with 62 | other enclave code, but your attack should still work if it correctly 63 | recognized page fault sequences. 64 | * Simply monitoring the accesses on either `square` or `multiply` won't get you 65 | far, as this only reveals the _total_ number of one bits in the private key 66 | (which is supposed to be randomly distributed anyway). 67 | * To reveal _individual_ private key bits, you will have to monitor the **page 68 | fault sequences** of the `square`, `multiply`, and `modpow` code pages with a 69 | simple state machine as follows: 70 | 71 | ![state-machine](state-machine.png) 72 | 73 | * Be aware that `ecall_rsa_decode` first performs blinding on the input 74 | parameter through a `modpow` call with a _known_ exponent (rsa_e). As such, 75 | your attacker code will have to ignore the first call to `modpow` and only 76 | focus on page fault side-effects of the second `modpow` invocation with 77 | the secret argument (rsa_d). You can start with commenting out the first 78 | `modpow` call if that helps. 79 | -------------------------------------------------------------------------------- /005-sgx-rsa/main.c: -------------------------------------------------------------------------------- 1 | /* utility headers */ 2 | #include "debug.h" 3 | #include "pf.h" 4 | #include "cacheutils.h" 5 | #include 6 | 7 | /* SGX untrusted runtime */ 8 | #include 9 | #include "Enclave/encl_u.h" 10 | 11 | #define RSA_TEST_VAL 1234 12 | 13 | sgx_enclave_id_t create_enclave(void) 14 | { 15 | sgx_launch_token_t token = {0}; 16 | int updated = 0; 17 | sgx_enclave_id_t eid = -1; 18 | 19 | info_event("Creating enclave..."); 20 | SGX_ASSERT( sgx_create_enclave( "./Enclave/encl.so", /*debug=*/1, 21 | &token, &updated, &eid, NULL ) ); 22 | 23 | return eid; 24 | } 25 | 26 | int fault_fired = 0; 27 | void *sq_pt = NULL, *mul_pt = NULL, *modpow_pt = NULL; 28 | 29 | /* =========================== START SOLUTION =========================== */ 30 | /* =========================== END SOLUTION =========================== */ 31 | 32 | void fault_handler(void *base_adrs) 33 | { 34 | /* =========================== START SOLUTION =========================== */ 35 | /* =========================== END SOLUTION =========================== */ 36 | 37 | fault_fired++; 38 | } 39 | 40 | int main( int argc, char **argv ) 41 | { 42 | sgx_enclave_id_t eid = create_enclave(); 43 | int rv = 1, secret = 0; 44 | int cipher, plain; 45 | 46 | /* ---------------------------------------------------------------------- */ 47 | info("registering fault handler.."); 48 | register_fault_handler(fault_handler); 49 | 50 | /* ---------------------------------------------------------------------- */ 51 | info_event("Calling enclave.."); 52 | SGX_ASSERT( ecall_get_square_adrs(eid, &sq_pt) ); 53 | SGX_ASSERT( ecall_get_multiply_adrs(eid, &mul_pt) ); 54 | SGX_ASSERT( ecall_get_modpow_adrs(eid, &modpow_pt) ); 55 | modpow_pt = (void*) (((uint64_t) modpow_pt) & ~0xfff); 56 | info("square at %p; muliply at %p; modpow at %p", sq_pt, mul_pt, modpow_pt); 57 | 58 | SGX_ASSERT( ecall_rsa_encode(eid, &cipher, RSA_TEST_VAL) ); 59 | SGX_ASSERT( ecall_rsa_decode(eid, &plain, cipher) ); 60 | info("secure enclave encrypted '%d' to '%d'; decrypted '%d'", RSA_TEST_VAL, cipher, plain); 61 | 62 | /* =========================== START SOLUTION =========================== */ 63 | /* =========================== END SOLUTION =========================== */ 64 | 65 | info_event("destroying SGX enclave"); 66 | SGX_ASSERT( sgx_destroy_enclave( eid ) ); 67 | 68 | info("all is well; exiting.."); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /005-sgx-rsa/sample-out.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- 3 | [main.c] Creating enclave... 4 | -------------------------------------------------------------------------------- 5 | 6 | [main.c] registering fault handler.. 7 | 8 | -------------------------------------------------------------------------------- 9 | [main.c] Calling enclave.. 10 | -------------------------------------------------------------------------------- 11 | 12 | [main.c] square at 0x7f51e2403000; muliply at 0x7f51e2405000; modpow at 0x7f51e2402000 13 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 14 | 15 | -------------------------------------------------------------------------------- 16 | [main.c] MODPOW INVOCATION 17 | -------------------------------------------------------------------------------- 18 | 19 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 20 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 21 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 22 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 23 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 24 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 25 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 26 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 27 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 28 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 29 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 30 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 31 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 32 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 33 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 34 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 35 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 36 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 37 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 38 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 39 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 40 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 41 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 42 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 43 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 44 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 45 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 46 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 47 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 48 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 49 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 50 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 51 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 52 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 53 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 54 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 55 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 56 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 57 | 58 | -------------------------------------------------------------------------------- 59 | [main.c] MODPOW INVOCATION 60 | -------------------------------------------------------------------------------- 61 | 62 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 63 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 64 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 65 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 66 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 67 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 68 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 69 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 70 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 71 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 72 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 73 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 74 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 75 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 76 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 77 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 78 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 79 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 80 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 81 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 82 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 83 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 84 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 85 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 86 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 87 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 88 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 89 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 90 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 91 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 92 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 93 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 94 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 95 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 96 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 97 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 98 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 99 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 100 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 101 | [../common/pf.c] Caught page fault (base address=0x7f51e2403000) 102 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 103 | [../common/pf.c] Caught page fault (base address=0x7f51e2405000) 104 | [../common/pf.c] Caught page fault (base address=0x7f51e2402000) 105 | [main.c] secure enclave encrypted '1234' to '21921'; decrypted '1234' 106 | [main.c] --> RECONSTRUCTED KEY '20771' (0x5123) 107 | 108 | -------------------------------------------------------------------------------- 109 | [main.c] destroying SGX enclave 110 | -------------------------------------------------------------------------------- 111 | 112 | [main.c] all is well; exiting.. 113 | -------------------------------------------------------------------------------- /005-sgx-rsa/state-machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/005-sgx-rsa/state-machine.png -------------------------------------------------------------------------------- /005-sgx-rsa/state-machine.xml: -------------------------------------------------------------------------------- 1 | 7Vltc+I2EP41fISxJdnYH0NyuXbmrk2Htrm7b8IWoImxqCwCuV9fCUvGkp2EF0PJTPOBWKv16mVXz7Na9+DtYvOZ4+X8K0tJ1gNeuunBux4AkR/IXyV4KQXICGacpqXI3wnG9CfRQk9LVzQlhaUoGMsEXdrChOU5SYQlw5yzta02ZZk96hLPSEMwTnDWlD7SVMz1skC4k/9C6GxuRvbDuOxZYKOsV1LMccrWNRH81IO3nDFRPi02tyRTe2f2pXzv/pXeamKc5GKfF/roz+EjWL7g+/jvX8d3P377+eVHX1t5xtlKL7gHwkzaG02ZNCtnLV70VoT/rJjp6BdbR91IBT9abnad8mmm/2+tTIxg/IcRyRlOXDUpK8czYmANDeRKpMNlY7SeU0HGS5yonrUMOSmbi0UmW758xMWyjIIp3ZBUzZZm2S3LGN8agmlAohRJeSE4eyK1nghMYBhWg9f31WwS4YJsaiK9z58JWxDBX6SK7oVQ+1wHPTDtdS2EtGheix4jwzpoZ5XlnV/lg3btAW4Gl3Lz17++XIWfp1FCkqTNz5MoQIHXjZ+D4ZX5OWzxs7vFeXqjcFG2cpYTe1uTFX9W27ltFAJzYXSTDBcFTYz4nmbmHWlQt9Sukg0V30yPfP6u5INgqydX+M1uftear/qiYCuekLcATK9QTmpGxPtHgKQW3jddW3Nd0OI6I+Mkw4I+2yzR5k89wgOj24NmIsdBCDh0QqJcuH6rjuqOIRg5htzYKjemYUj6Fb/U1JZKoXhjwnH7OLtoLS3uYrfa0+PD2e+AntBbuEWNgBOx4nkNpqir2g1QNsxOeAtGNrQauLkfnEoYE/YB50TOFE+2Cuq4ardL7WDUC+4UsmZ0lqsDL48ikZg5UnBIZUJ0ozsWNE3V+6MMT0g2wsnTjLNVntbRd/vXeq7fhC0XeKu0Ts/YypzaANkbABRAK1ANQJx4YPvKeGBZ7kMjMGbYdFoQ4ZyLTk6CSSKv4ST8H3WNqENDz7diI+gk6BohF18q3qITE4ka2asrYI3uvYE8kU6mYZIGb+B5gZU4hBAenYmoER8Ip3IvVEhV6YkrOz752Df3MBh0JckH8h0u949MPoIYDSIvDlQ2oH6HtlkvGoAoGPpI/54nMXEWA+ILJCbx6Wh8WJpwGsg/EbWjE6pM+O/kFEcmJB+UAwzOncwBfYlrYRTboTjshgUChwUulnUY3LpA3eD3u4fHq6gcpJhE09bKQZhEZNIeWwdXDhByIBj9x5UDHx7E+DsSbiP9qlG7/VcUbxG8mwkcz8V7FwL8q+Liyo6pjx9dCPAcQ+A8hQDkFBzARQoBw1eBKKXPZ2bPjLGlmqAkJelplr9DoK/QpTXPD8qWFUh0QZfIsy/qcSfnyWbgPnIMnJErUYcAKi9CPrJBFA4rDfcC0xWC7gug13WbAQ6VIpcj90VQ4JQ4ETwPgjZKtvqT4XkR9LBPA++EZ8+p3+8XgR8tsqAbEC6l7s3NzneiKvvrmptBewQfGVmyufs8XarvvvHDT/8C -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tutorial overview and objectives 2 | 3 | This repository collects presentation material and source code for hands-on 4 | exercises part of a 3h tutorial taught at the 8th International Conference on 5 | Security, Privacy, and Applied Cryptography Engineering 6 | ([SPACE18](https://space2018.cse.iitk.ac.in/)), held 2018 December 15, Kanpur, 7 | India. 8 | 9 | ## Abstract 10 | 11 | The inclusion of the Software Guard eXtensions (SGX) in recent Intel processors 12 | has been broadly acclaimed for bringing strong hardware-enforced trusted 13 | computing guarantees to mass consumer devices, and for protecting end user data 14 | in an untrusted cloud environment. While SGX assumes a very strong attacker 15 | model and indeed even safeguards enclave secrets against a compromised 16 | operating system, recent research has demonstrated that considerable private 17 | data (e.g., full text and images, complete cryptographic keys) may still be 18 | reconstructed by monitoring subtle side-effects of the enclaved execution. 19 | 20 | We argue that a systematic understanding of such side-channel leakage sources 21 | is essential for writing intrinsically secure enclave applications, and will be 22 | instrumental to the success of this new trusted execution technology. This 23 | tutorial and write-up therefore aims to bring a better understanding of current 24 | state-of-the-art side-channel attacks and defenses on Intel SGX platforms. 25 | Participants will learn how to extract data from elementary example 26 | applications, thereby recognizing how to avoid common pitfalls and information 27 | leakage sources in enclave development. 28 | 29 | > Jo Van Bulck, Frank Piessens "Tutorial: Uncovering and mitigating side-channel 30 | > leakage in Intel SGX enclaves", 8th International Conference on Security, 31 | > Privacy, and Applied Cryptography Engineering (SPACE'18). December 2018. 32 | 33 | ## Tutorial organization 34 | 35 | This tutorial is aimed at a target audience of C programmers with an interest 36 | in security. The tutorial takes about three hours, with an equal split between 37 | lectures and practical exercises. 38 | 39 | **Note (SGX support).** Since we do not assume that all participants have 40 | access to an [SGX-capable](https://github.com/ayeks/SGX-hardware) Intel 41 | processor, plus [linux-sgx](https://github.com/01org/linux-sgx) toolchain, we 42 | made sure that all exercises have both an _unprotected_ and _enclaved_ version. 43 | For the SPACE2018 tutorial setting, we will provide SSH access to an SGX 44 | machine over the local network in order to test the enclaved version. 45 | 46 | However, to keep pressure on the remote SSH SGX machine low, *we strongly 47 | advise to first develop the unprotected attack scenario on your local x86 48 | machine, before testing the enclaved version on the remote SGX machine via 49 | SSH.* Once the unprotected version is working, it should be relatively 50 | straightforward to port the attack to an SGX setting. 51 | 52 | **Note (solutions).** This git repository includes a 53 | [`solutions`](https://github.com/jovanbulck/sgx-tutorial-space18/tree/solutions) 54 | branch with working attack code for all of the exercises. If you want to solve 55 | the exercise challenges on your own, you should of course only verify your 56 | solutions after having implemented the attack yourself using the skeleton code 57 | provided in the default `master` branch. 58 | 59 | 60 | | Program | SGX enclave version | Description | 61 | |---------------------------|--------------------------|----------------------------------------------------| 62 | | **001-pwd** | 001-sgx-pwd | Basic _timing_ side-channel attack. | 63 | | **002-inc-secret** | 002-sgx-inc-secret | Basic _page fault_ side-channel attack. | 64 | | **003-flush-and-reload** | 003-sgx-flush-and-reload | Flush+Reload _cache_ attack on unprotected memory. | 65 | | **004-str** | 004-sgx-str | More subtle _page fault_ side-channel attack. | 66 | | **005-rsa** | 005-sgx-rsa | Page _fault sequence_ side-channel attack. | 67 | 68 | ## License 69 | 70 | You are welcome to re-use all of the material in this repository for your own 71 | teaching (given appropriate credit). All exercise code is free software, 72 | licensed under [GPLv3](https://www.gnu.org/licenses/gpl-3.0). 73 | Presentation material (slides) are released on a 74 | [CC-BY](https://creativecommons.org/licenses/by/4.0/) basis. 75 | 76 | -------------------------------------------------------------------------------- /common/cacheutils.h: -------------------------------------------------------------------------------- 1 | #ifndef CACHE_UTILS_H_INC 2 | #define CACHE_UTILS_H_INC 3 | 4 | /* 5 | * Code adapted from 6 | * https://github.com/IAIK/flush_flush/blob/master/sc/cacheutils.h 7 | */ 8 | uint64_t rdtsc_begin( void ) 9 | { 10 | uint64_t begin; 11 | uint32_t a, d; 12 | 13 | asm volatile ( 14 | "mfence\n\t" 15 | "CPUID\n\t" 16 | "RDTSCP\n\t" 17 | "mov %%edx, %0\n\t" 18 | "mov %%eax, %1\n\t" 19 | "mfence\n\t" 20 | : "=r" (d), "=r" (a) 21 | : 22 | : "%eax", "%ebx", "%ecx", "%edx"); 23 | 24 | begin = ((uint64_t)d << 32) | a; 25 | return begin; 26 | } 27 | 28 | uint64_t rdtsc_end( void ) 29 | { 30 | uint64_t end; 31 | uint32_t a, d; 32 | 33 | asm volatile( 34 | "mfence\n\t" 35 | "RDTSCP\n\t" 36 | "mov %%edx, %0\n\t" 37 | "mov %%eax, %1\n\t" 38 | "CPUID\n\t" 39 | "mfence\n\t" 40 | : "=r" (d), "=r" (a) 41 | : 42 | : "%eax", "%ebx", "%ecx", "%edx"); 43 | 44 | end = ((uint64_t)d << 32) | a; 45 | return end; 46 | } 47 | 48 | /* 49 | * Code adapted from: Yarom, Yuval, and Katrina Falkner. "Flush+ reload: a high 50 | * resolution, low noise, L3 cache side-channel attack." 23rd USENIX Security 51 | * Symposium (USENIX Security 14). 2014. 52 | */ 53 | int reload( void * adrs) 54 | { 55 | volatile unsigned long time; 56 | 57 | asm volatile ( 58 | "mfence\n\t" 59 | "lfence\n\t" 60 | "rdtsc\n\t" 61 | "lfence\n\t" 62 | "movl %%eax, %%esi\n\t" 63 | "movl (%1), %%eax\n\t" 64 | "lfence\n\t" 65 | "rdtsc\n\t" 66 | "subl %%esi, %%eax \n\t" 67 | : "=a" (time) 68 | : "c" (adrs) 69 | : "%rsi", "%rdx"); 70 | 71 | return (int) time; 72 | } 73 | 74 | void flush(void* p) 75 | { 76 | asm volatile ( "mfence\n" 77 | "clflush 0(%0)\n" 78 | "mfence\n" 79 | : 80 | : "D" (p) 81 | : "rax"); 82 | } 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /common/debug.c: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | 3 | int enclave_rv = 0; 4 | 5 | void dump_hex(char *str, uint8_t *buf, int len) 6 | { 7 | printf("%s = ", str); 8 | for (int i=0; i < len; i++) 9 | printf("%02x ", *(buf + i)); 10 | printf("\n"); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /common/debug.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUG_H_INC 2 | #define DEBUG_H_INC 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define ASSERT(cond) \ 9 | do { \ 10 | if (!(cond)) \ 11 | { \ 12 | perror("[" __FILE__ "] assertion '" #cond "' failed"); \ 13 | abort(); \ 14 | } \ 15 | } while(0) 16 | 17 | #define SGX_ASSERT(f) { if ( SGX_SUCCESS != (enclave_rv = (f)) ) \ 18 | { \ 19 | printf( "Error calling enclave at %s:%d (rv=0x%x)\n", __FILE__, \ 20 | __LINE__, enclave_rv); \ 21 | abort(); \ 22 | } } 23 | 24 | #define info(msg, ...) \ 25 | do { \ 26 | printf("[" __FILE__ "] " msg "\n", ##__VA_ARGS__); \ 27 | fflush(stdout); \ 28 | } while(0) 29 | 30 | #define info_event(msg, ...) \ 31 | do { \ 32 | printf("\n--------------------------------------------------------------------------------\n"); \ 33 | info(msg,##__VA_ARGS__); \ 34 | printf("--------------------------------------------------------------------------------\n\n"); \ 35 | } while(0) 36 | 37 | extern int enclave_rv; 38 | 39 | void dump_hex(char *str, uint8_t *buf, int len); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /common/pf.c: -------------------------------------------------------------------------------- 1 | #include "debug.h" 2 | #include "pf.h" 3 | #include 4 | #include 5 | 6 | fault_handler_t __fault_handler_cb = NULL; 7 | 8 | void fault_handler_wrapper (int signo, siginfo_t * si, void *ctx) 9 | { 10 | void *base_adrs; 11 | ucontext_t *uc = (ucontext_t *) ctx; 12 | 13 | switch ( signo ) 14 | { 15 | case SIGSEGV: 16 | base_adrs = si->si_addr; 17 | info("Caught page fault (base address=%p)", base_adrs); 18 | break; 19 | 20 | default: 21 | info("Caught unknown signal '%d'", signo); 22 | abort(); 23 | } 24 | 25 | /* Mask lower PFN bits to simulate clearing by SGX hardware when executing 26 | the unprotected programs */ 27 | base_adrs = GET_PFN(base_adrs); 28 | 29 | if (__fault_handler_cb) 30 | __fault_handler_cb(base_adrs); 31 | } 32 | 33 | void register_fault_handler(fault_handler_t cb) 34 | { 35 | struct sigaction act, old_act; 36 | memset(&act, sizeof(sigaction), 0); 37 | 38 | /* Specify handler with signinfo arguments */ 39 | act.sa_sigaction = fault_handler_wrapper; 40 | act.sa_flags = SA_RESTART | SA_SIGINFO; 41 | 42 | /* Block all signals while the signal is being handled */ 43 | sigfillset(&act.sa_mask); 44 | 45 | ASSERT (!sigaction( SIGSEGV, &act, &old_act )); 46 | 47 | __fault_handler_cb = cb; 48 | } 49 | -------------------------------------------------------------------------------- /common/pf.h: -------------------------------------------------------------------------------- 1 | #ifndef PF_H_INC 2 | #define PF_H_INC 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define PFN_MASK 0xfff 9 | 10 | #define GET_PFN(adrs) ((void*) (((uint64_t) adrs) & ~PFN_MASK)) 11 | 12 | typedef void (*fault_handler_t)(void *page_base_adrs); 13 | void register_fault_handler(fault_handler_t cb); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /part1-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/part1-slides.pdf -------------------------------------------------------------------------------- /part2-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/part2-slides.pdf -------------------------------------------------------------------------------- /space18.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/sgx-tutorial-space18/27e6dec9c5c151f7d5b9620ce995bb205fbc5e38/space18.pdf --------------------------------------------------------------------------------