From 10614a43928987676a2098851f7047954d5a3501 Mon Sep 17 00:00:00 2001 From: Paul Zinselmeyer Date: Sat, 6 Jul 2024 14:54:54 +0200 Subject: [PATCH] [Assignment-7] working implementation of untrusted --- 7-SGX_Hands-on/src/Makefile | 2 +- 7-SGX_Hands-on/src/app/intermediary.c | 96 +++-- 7-SGX_Hands-on/src/app/main.c | 3 + 7-SGX_Hands-on/src/app/proxy.c | 596 ++++++++++++++++++-------- 7-SGX_Hands-on/src/app/proxysetup.c | 445 +++++++++++++++++++ 7-SGX_Hands-on/src/app/proxysetup.h | 23 + 7-SGX_Hands-on/src/app/util.c | 160 ++++++- 7-SGX_Hands-on/src/app/util.h | 9 + 8 files changed, 1126 insertions(+), 208 deletions(-) create mode 100644 7-SGX_Hands-on/src/app/proxysetup.c create mode 100644 7-SGX_Hands-on/src/app/proxysetup.h diff --git a/7-SGX_Hands-on/src/Makefile b/7-SGX_Hands-on/src/Makefile index 7aea36b..df2209d 100644 --- a/7-SGX_Hands-on/src/Makefile +++ b/7-SGX_Hands-on/src/Makefile @@ -74,7 +74,7 @@ else Urts_Library_Name := sgx_urts endif -App_C_Files := app/main.c app/proxy.c app/intermediary.c app/util.c +App_C_Files := app/main.c app/proxy.c app/proxysetup.c app/intermediary.c app/util.c App_Include_Paths := -IInclude -Iapp -I$(SGX_SDK)/include App_C_Flags := $(SGX_COMMON_CFLAGS) -fPIC -Wno-attributes $(App_Include_Paths) diff --git a/7-SGX_Hands-on/src/app/intermediary.c b/7-SGX_Hands-on/src/app/intermediary.c index e299c40..03bd6de 100644 --- a/7-SGX_Hands-on/src/app/intermediary.c +++ b/7-SGX_Hands-on/src/app/intermediary.c @@ -19,9 +19,11 @@ struct IntermediaryArgs { char* key_path; + char* firmware_path; }; +/* static int generate_key(EVP_PKEY** key) { OSSL_PARAM key_params[2]; EVP_PKEY_CTX* gctx; @@ -45,28 +47,31 @@ static int generate_key(EVP_PKEY** key) { EVP_PKEY_CTX_free(gctx); return (0); } +*/ char* intermediary_syntax(void) { return - "intermediary mock up implementation of the employee binary\n" - " expects firmware on stdin\n" - " outputs signature on stdout\n" - " -k key file path\n"; + "intermediary mock up implementation of the employee binary\n" + " outputs signature on stdout\n" + " WARNING: output is in binary format, may mess up terminal\n" + " -ekey file path of the PEM encoded private key of the employee\n" + " -firm path of the firmware\n"; } int handle_intermediary(int argc, char** argv) { struct IntermediaryArgs args = { + NULL, NULL }; - FILE* key_file; + FILE* key_file = NULL; + FILE* firmware_file = NULL; uint8_t firmware_chunk[HASH_CHUNK_BYTES]; - EVP_PKEY* key; - OSSL_PARAM key_params[2]; - EVP_PKEY_CTX* gctx; - EVP_MD_CTX *mdctx; + EVP_PKEY* key = NULL; + EVP_MD_CTX *mdctx = NULL; size_t sig_len; - unsigned char* sig; + unsigned char* sig = NULL; + int status = EXIT_FAILURE; /* * Parse Input @@ -74,9 +79,12 @@ int handle_intermediary(int argc, char** argv) { int i = 0; while(i < argc) { - if(strcmp(argv[i], "-k")==0 && argc-i >=2){ + if(strcmp(argv[i], "-ekey")==0 && argc-i >=2){ args.key_path = argv[i+1]; i += 2; + }else if(strcmp(argv[i], "-firm")==0 && argc-i >=2){ + args.firmware_path = argv[i+1]; + i += 2; }else syntax_exit(); } @@ -84,6 +92,7 @@ int handle_intermediary(int argc, char** argv) { if(args.key_path == NULL) syntax_exit(); + /* * Load Signing Key */ @@ -91,69 +100,96 @@ int handle_intermediary(int argc, char** argv) { key_file = fopen(args.key_path, "rb"); if(key_file == NULL){ perror("Error opening key file"); - exit(1); + status = EXIT_FAILURE; + goto cleanup; } key = PEM_read_PrivateKey(key_file, &key, NULL, NULL); if(key == NULL) { fprintf(stderr, "failed to read key"); - exit(1); + fclose(key_file); + status = EXIT_FAILURE; + goto cleanup; } + fclose(key_file); + /* * Sign Firmware */ + firmware_file = fopen(args.firmware_path, "rb"); + if(firmware_file == NULL){ + perror("Error opening firmware file"); + status = EXIT_FAILURE; + goto cleanup; + } mdctx = EVP_MD_CTX_new(); if (EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, key) != 1) { fprintf(stderr, "Message digest initialization failed.\n"); - EVP_MD_CTX_free(mdctx); - exit(1); + fclose(firmware_file); + status = EXIT_FAILURE; + goto cleanup; } + size_t chunk_len = HASH_CHUNK_BYTES; while(chunk_len==HASH_CHUNK_BYTES) { - chunk_len = fread(&firmware_chunk, HASH_CHUNK_BYTES, 1, stdin); - if(chunk_len!=HASH_CHUNK_BYTES&&ferror(stdin)!=0){ + chunk_len = fread(&firmware_chunk, 1, HASH_CHUNK_BYTES, firmware_file); + if(chunk_len!=HASH_CHUNK_BYTES&&ferror(firmware_file)!=0){ perror("Failed to read firmware file"); - exit(1); + exit(EXIT_FAILURE); } if (EVP_DigestSignUpdate(mdctx, firmware_chunk, chunk_len) != 1) { printf("Message digest update failed.\n"); - EVP_MD_CTX_free(mdctx); - exit(1); + exit(EXIT_FAILURE); } } + fclose(firmware_file); + // call with empty sig to get length if (EVP_DigestSignFinal(mdctx, NULL, &sig_len) != 1) { printf("Message digest finalization failed.\n"); - EVP_MD_CTX_free(mdctx); - exit(1); + status = EXIT_FAILURE; + goto cleanup; } // allocate signature buffer sig = malloc(sizeof(unsigned char) * sig_len); if(sig == NULL){ perror("could not initialize digest buffer"); - exit(1); + status = EXIT_FAILURE; + goto cleanup; } // load signature into buffer if (EVP_DigestSignFinal(mdctx, sig, &sig_len) != 1) { printf("Message digest finalization failed.\n"); EVP_MD_CTX_free(mdctx); - exit(1); + status = EXIT_FAILURE; + goto cleanup; } - EVP_MD_CTX_free(mdctx); + fwrite(sig, sig_len, 1, stdout); + if (ferror(stdout) != 0) { + fprintf(stdout, "failed to write signature to stdout\n"); + status = EXIT_FAILURE; + goto cleanup; + } - for (unsigned int i = 0; i < sig_len; i++) - printf("%02x", sig[i]); - printf("\n"); + fflush(stdout); + status = EXIT_SUCCESS; - EVP_PKEY_free(key); - exit(0); + // free all allocated resources +cleanup: + if(sig != NULL) + free(sig); + if (mdctx != NULL) + EVP_MD_CTX_free(mdctx); + if (key != NULL) + EVP_PKEY_free(key); + exit(status); } diff --git a/7-SGX_Hands-on/src/app/main.c b/7-SGX_Hands-on/src/app/main.c index abeb52d..a02e06c 100644 --- a/7-SGX_Hands-on/src/app/main.c +++ b/7-SGX_Hands-on/src/app/main.c @@ -3,6 +3,7 @@ #include "intermediary.h" #include "proxy.h" +#include "proxysetup.h" #include "util.h" @@ -19,6 +20,8 @@ int main(int argc, char** argv) { handle_intermediary(argc-2, argv+2); else if (strcmp(command, "proxy")==0) handle_proxy(argc-2, argv+2); + else if (strcmp(command, "proxysetup")==0) + handle_proxysetup(argc-2, argv+2); else syntax_exit(); } diff --git a/7-SGX_Hands-on/src/app/proxy.c b/7-SGX_Hands-on/src/app/proxy.c index 4c12e37..4533622 100644 --- a/7-SGX_Hands-on/src/app/proxy.c +++ b/7-SGX_Hands-on/src/app/proxy.c @@ -4,183 +4,298 @@ #include #include -#include "../enclave/enclave.h" +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include "enclave_u.h" #include "proxy.h" #include "util.h" -sgx_enclave_id_t global_eid = 0; struct ProxyArgs { char* sealed_key_file_path; char* sgx_token_path; + char* employee_public_key_path; + char* firmware_path; }; -typedef struct _sgx_errlist_t { - sgx_status_t err; - const char *msg; - const char *sug; /* Suggestion */ -} sgx_errlist_t; - -/* Error code returned by sgx_create_enclave */ -static sgx_errlist_t sgx_errlist[] = { - { - SGX_ERROR_UNEXPECTED, - "Unexpected error occurred.", - NULL - }, - { - SGX_ERROR_INVALID_PARAMETER, - "Invalid parameter.", - NULL - }, - { - SGX_ERROR_OUT_OF_MEMORY, - "Out of memory.", - NULL - }, - { - SGX_ERROR_ENCLAVE_LOST, - "Power transition occurred.", - "Please refer to the sample \"PowerTransition\" for details." - }, - { - SGX_ERROR_INVALID_ENCLAVE, - "Invalid enclave image.", - NULL - }, - { - SGX_ERROR_INVALID_ENCLAVE_ID, - "Invalid enclave identification.", - NULL - }, - { - SGX_ERROR_INVALID_SIGNATURE, - "Invalid enclave signature.", - NULL - }, - { - SGX_ERROR_OUT_OF_EPC, - "Out of EPC memory.", - NULL - }, - { - SGX_ERROR_NO_DEVICE, - "Invalid SGX device.", - "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." - }, - { - SGX_ERROR_MEMORY_MAP_CONFLICT, - "Memory map conflicted.", - NULL - }, - { - SGX_ERROR_INVALID_METADATA, - "Invalid enclave metadata.", - NULL - }, - { - SGX_ERROR_DEVICE_BUSY, - "SGX device was busy.", - NULL - }, - { - SGX_ERROR_INVALID_VERSION, - "Enclave version was invalid.", - NULL - }, - { - SGX_ERROR_INVALID_ATTRIBUTE, - "Enclave was not authorized.", - NULL - }, - { - SGX_ERROR_ENCLAVE_FILE_ACCESS, - "Can't open enclave file.", - NULL - }, -}; - -/* Check error conditions for loading enclave */ -static void print_error_message(sgx_status_t ret) -{ - size_t idx = 0; - size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0]; - - for (idx = 0; idx < ttl; idx++) { - if(ret == sgx_errlist[idx].err) { - if(NULL != sgx_errlist[idx].sug) - printf("Info: %s\n", sgx_errlist[idx].sug); - printf("Error: %s\n", sgx_errlist[idx].msg); - break; - } - } - - if (idx == ttl) - printf("Error code is 0x%X. Please refer to the \"Intel SGX SDK Developer Reference\" for more details.\n", ret); -} - -static int initialize_enclave(char* token_path) { - FILE* sgx_token_file; - sgx_launch_token_t token = {0}; - sgx_status_t ret; - int updated = 0; - - sgx_token_file = fopen(token_path, "rb"); - if(sgx_token_file == NULL){ - perror("Error opening sgx token file"); - exit(1); - } - - //TODO create new on error / ignore missing token file - - size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), sgx_token_file); - if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) { - fprintf(stderr, "sgx token file is corrupted"); - return (1); - } - - ret = sgx_create_enclave("enclave.signed.so", SGX_DEBUG_FLAG, &token, &updated, &global_eid, NULL); - if (ret != SGX_SUCCESS) { - print_error_message(ret); - return (1); - } - - if (updated) { - sgx_token_file = freopen(token_path, "wb", sgx_token_file); - if(sgx_token_file == NULL){ - perror("Error opening sgx token file"); - return (1); - } - size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), sgx_token_file); - if (write_num != sizeof(sgx_launch_token_t)){ - fprintf(stderr,"Warning: Failed to save launch token to \"%s\".\n", token_path); - return (1); - } - } - return (0); -} - char* proxy_syntax(void) { return - "proxy implementation of the enclave-powered SignatureProxy\n" - " expects intermediary signature on stdin\n" - " outputs proxied signature on stdout\n" - " -s file path of the sealed proxy key\n" - " -t file path of the sgx token\n"; + "proxy implementation of the enclave-powered SignatureProxy\n" + " expects intermediary signature on stdin\n" + " outputs proxied signature on stdout\n" + " WARNING: output is binary format, may mess up terminal\n" + " -s file path of the sealed proxy key\n" + " -t file path of the sgx token\n" + " -epub path of the PEM encoded employee public key\n" + " -firm path of the firmware\n"; +} + +static EVP_PKEY *sgx_public_to_EVP_PKEY(const sgx_ec256_public_t *p_public) +{ + EVP_PKEY *evp_key = NULL; + EVP_PKEY_CTX *pkey_ctx = NULL; + BIGNUM *bn_pub_x = NULL; + BIGNUM *bn_pub_y = NULL; + EC_POINT *point = NULL; + EC_GROUP* group = NULL; + OSSL_PARAM_BLD *params_build = NULL; + OSSL_PARAM *params = NULL; + const char *curvename = NULL; + int nid = 0; + size_t key_len; + unsigned char pub_key[SGX_ECP256_KEY_SIZE+4]; + + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (group == NULL) + return NULL; + + do { + // converts the x value of public key, represented as positive integer in little-endian into a BIGNUM + bn_pub_x = BN_lebin2bn((unsigned char*)p_public->gx, sizeof(p_public->gx), bn_pub_x); + if (NULL == bn_pub_x) { + break; + } + // converts the y value of public key, represented as positive integer in little-endian into a BIGNUM + bn_pub_y = BN_lebin2bn((unsigned char*)p_public->gy, sizeof(p_public->gy), bn_pub_y); + if (NULL == bn_pub_y) { + break; + } + // creates new point and assigned the group object that the point relates to + point = EC_POINT_new(group); + if (NULL == point) { + break; + } + + // sets point based on public key's x,y coordinates + if (1 != EC_POINT_set_affine_coordinates(group, point, bn_pub_x, bn_pub_y, NULL)) { + break; + } + + // check point if the point is on curve + if (1 != EC_POINT_is_on_curve(group, point, NULL)) { + break; + } + + // convert point to octet string + key_len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pub_key, sizeof(pub_key), NULL); + if (key_len == 0) { + break; + } + + // build OSSL_PARAM + params_build = OSSL_PARAM_BLD_new(); + if (NULL == params_build) { + break; + } + nid = EC_GROUP_get_curve_name(group); + if (nid == NID_undef) { + break; + } + curvename = OBJ_nid2sn(nid); + if (curvename == NULL) { + break; + } + if (1 != OSSL_PARAM_BLD_push_utf8_string(params_build, "group", curvename, 0)) { + break; + } + if (1 != OSSL_PARAM_BLD_push_octet_string(params_build, OSSL_PKEY_PARAM_PUB_KEY, pub_key, key_len)) { + break; + } + params = OSSL_PARAM_BLD_to_param(params_build); + if (NULL == params) { + break; + } + + // get pkey from params + pkey_ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (NULL == pkey_ctx) { + break; + } + if (1 != EVP_PKEY_fromdata_init(pkey_ctx)) { + break; + } + if (1 != EVP_PKEY_fromdata(pkey_ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params)) { + EVP_PKEY_free(evp_key); + evp_key = NULL; + } + } while(0); + + BN_clear_free(bn_pub_x); + BN_clear_free(bn_pub_y); + EC_POINT_clear_free(point); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(params_build); + EVP_PKEY_CTX_free(pkey_ctx); + EC_GROUP_free(group); + + return evp_key; +} + +static int EVP_PKEY_to_sgx_public(EVP_PKEY* ecdsa_key, sgx_ec256_public_t* sgx_public) { + EC_GROUP* group = NULL; + EC_POINT *point = NULL; + BIGNUM* pub_x = NULL; + BIGNUM* pub_y = NULL; + size_t ec_key_buf_len = 0; + unsigned char ec_key_buf[1024]; + int ret; + int retval; + + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (group == NULL) + return 1; + + point = EC_POINT_new(group); + if (point == NULL) + return 2; + + ret = EVP_PKEY_get_octet_string_param(ecdsa_key, OSSL_PKEY_PARAM_PUB_KEY, ec_key_buf, 1024, &ec_key_buf_len); + if (ret != 1) + return 3; + + ret = EC_POINT_oct2point(group, point, ec_key_buf, ec_key_buf_len, NULL); + if (ret != 1){ + retval = 4; + goto cleanup; + } + + pub_x = BN_new(); + pub_y = BN_new(); + + ret = EC_POINT_get_affine_coordinates(group, point, pub_x, pub_y, NULL); + if (ret != 1){ + retval = 5; + goto cleanup; + } + + ret = BN_bn2lebinpad(pub_x, sgx_public->gx, SGX_ECP256_KEY_SIZE); + if (ret == -1){ + retval = 6; + goto cleanup; + } + + ret = BN_bn2lebinpad(pub_y, sgx_public->gy, SGX_ECP256_KEY_SIZE); + if (ret == -1){ + retval = 7; + goto cleanup; + } + + retval = 0; + +cleanup: + if (pub_x != NULL) + BN_clear_free(pub_x); + if (pub_y != NULL) + BN_clear_free(pub_y); + if (point != NULL) + EC_POINT_clear_free(point); + if (group != NULL) + EC_GROUP_free(group); + + return (retval); +} + +static int ECDSA_SIG_to_sgx_signature(ECDSA_SIG* ecdsa_sig, sgx_ec256_signature_t* sgx_signature) { + BIGNUM* r = NULL; + BIGNUM* s = NULL; + int ret; + + r = ECDSA_SIG_get0_r(ecdsa_sig); + s = ECDSA_SIG_get0_s(ecdsa_sig); + + ret = BN_bn2lebinpad(r, sgx_signature->x, SGX_ECP256_KEY_SIZE); + if (ret == -1) + return (1); + + ret = BN_bn2lebinpad(s, sgx_signature->y, SGX_ECP256_KEY_SIZE); + if (ret == -1) + return (2); + + return (0); +} + +static int sgx_signature_to_ECDSA_SIG(sgx_ec256_signature_t* sgx_signature, ECDSA_SIG** ecdsa_signature) { + BIGNUM *bn_r = NULL; + BIGNUM *bn_s = NULL; + + // converts the x value of the signature, represented as positive integer in little-endian into a BIGNUM + // + bn_r = BN_lebin2bn((unsigned char*)sgx_signature->x, sizeof(sgx_signature->x), 0); + if (bn_r == NULL) + return (1); + + + // converts the y value of the signature, represented as positive integer in little-endian into a BIGNUM + // + bn_s = BN_lebin2bn((unsigned char*)sgx_signature->y, sizeof(sgx_signature->y), 0); + if (NULL == bn_s) { + if (bn_r != NULL) + BN_clear_free(bn_r); + + return (2); + } + + + // allocates a new ECDSA_SIG structure (note: this function also allocates the BIGNUMs) and initialize it + // + *ecdsa_signature = ECDSA_SIG_new(); + if (NULL == *ecdsa_signature) { + if (bn_r != NULL) + BN_clear_free(bn_r); + if (bn_s != NULL) + BN_clear_free(bn_s); + + return (3); + } + + // setes the r and s values of ecdsa_sig + // calling this function transfers the memory management of the values to the ECDSA_SIG object, + // and therefore the values that have been passed in should not be freed directly after this function has been called + // + if (1 != ECDSA_SIG_set0(*ecdsa_signature, bn_r, bn_s)) { + ECDSA_SIG_free(*ecdsa_signature); + *ecdsa_signature = NULL; + + if (bn_r != NULL) + BN_clear_free(bn_r); + + if (bn_s != NULL) + BN_clear_free(bn_s); + + return (4); + } + + return (0); } int handle_proxy(int argc, char** argv) { struct ProxyArgs args = { + NULL, NULL, NULL }; - FILE* input_file = stdin; - FILE* output_file = stdout; - FILE* sealed_key_file; + FILE* sealed_file; + FILE* firmware_file; uint8_t *sealed; - uint32_t sealed_size; - char line[141]; + int sealed_size; + unsigned char* ecdsa_signature_data; + size_t ecdsa_signature_size = 0; uint8_t signature[70]; + sgx_status_t ret; + ECDSA_SIG* ecdsa_signature; + sgx_ec256_signature_t sgx_signature; /* * Parse Input @@ -194,54 +309,183 @@ int handle_proxy(int argc, char** argv) { }else if(strcmp(argv[i], "-t")==0 && argc-i >=2){ args.sgx_token_path = argv[i+1]; i += 2; + }else if(strcmp(argv[i], "-epub")==0 && argc-i >=2){ + args.employee_public_key_path = argv[i+1]; + i += 2; + }else if(strcmp(argv[i], "-firm")==0 && argc-i >=2){ + args.firmware_path = argv[i+1]; + i += 2; }else syntax_exit(); } - if(args.sealed_key_file_path == NULL || args.sgx_token_path == NULL) + if(args.sealed_key_file_path == NULL || args.employee_public_key_path == NULL || args.firmware_path == NULL) syntax_exit(); - if(fgets(line, 141, stdin) == NULL) { - fprintf(stderr, "failed to read signature from stdin"); + + /* + * Read Signature Input + */ + + ecdsa_signature_data = malloc(1024); + if (ecdsa_signature_data == NULL) { + perror("failed to allocate signature"); exit(1); } - if(line[140] != '\0') { - fprintf(stderr, "invalid input"); + ecdsa_signature_size = fread(ecdsa_signature_data, 1, 1024, stdin); + + if (ferror(stdin) != 0) { + fprintf(stderr, "failed to read signature from stdin\n"); exit(1); } - for (i = 0; i < 70; i++) { - sscanf(line+2*i, "%02x", &signature[i]); + ecdsa_signature = ECDSA_SIG_new(); + ecdsa_signature = d2i_ECDSA_SIG(&ecdsa_signature, &ecdsa_signature_data, ecdsa_signature_size); + ecdsa_signature_data = NULL; + if (ecdsa_signature == NULL) { + fprintf(stderr, "failed to read signature"); + exit(1); + } + + if (ECDSA_SIG_to_sgx_signature(ecdsa_signature, &sgx_signature) != 0) { + fprintf(stderr, "failed to transform signature\n"); + exit(1); + } + ECDSA_SIG_free(ecdsa_signature); + ecdsa_signature = NULL; + + + // Initialize SGX Enclave + if (initialize_enclave(args.sgx_token_path) != 0) + exit(1); + + /* + * Read Employee Public Key + */ + + EVP_PKEY* key = NULL; + FILE* key_file = fopen(args.employee_public_key_path, "rb"); + if(key_file == NULL){ + perror("Error opening employee public key file"); + exit(1); + } + key = PEM_read_PUBKEY(key_file, &key, NULL, NULL); + if(key == NULL) { + fprintf(stderr, "failed to read employee public key"); + exit(1); + } + fclose(key_file); + + sgx_ec256_public_t sgx_public; + if (EVP_PKEY_to_sgx_public(key, &sgx_public) != 0) { + fprintf(stderr, "failed transform employee public key"); + exit(1); } /* - * Initialize SGX Enclave + * Read Sealed Proxy Keypair */ - sealed_key_file = fopen(args.sealed_key_file_path, "rb"); - if(sealed_key_file == NULL){ + sealed_file = fopen(args.sealed_key_file_path, "rb"); + if(sealed_file == NULL){ perror("Error opening sealed_key_file file"); exit(1); } - if (initialize_enclave(args.sgx_token_path) != 0) - exit(1); - - sealed_size = get_sealed_size(); + ret = get_sealed_size(get_global_eid(), &sealed_size); + if (ret != SGX_SUCCESS) { + print_error_message(ret); + exit (1); + } sealed = malloc(sizeof(uint8_t)*sealed_size); if (sealed == NULL) { fprintf(stderr, "failed to allocate for sealed key"); exit(1); } - //TODO load sealed (what to do when missing?) + size_t sealed_read = fread(sealed, sealed_size, 1, sealed_file); + if (sealed_read != 1) { + fprintf(stderr, "failed to read sealed private key"); + exit (EXIT_FAILURE); + } - //TODO call enclave + fclose(sealed_file); - //TODO store sealed key if changed - //TODO write output - //TODO enclave teardown + /* + * Read Firmware + */ + int firmware_file_des = open(args.firmware_path, O_RDWR); + if(firmware_file_des == 0){ + perror("Error opening firmware file"); + exit(EXIT_FAILURE); + } + struct stat stat; + if (fstat(firmware_file_des, &stat) != 0) { + perror("failed to get firmware size"); + exit (EXIT_FAILURE); + } + + firmware_file = fopen(args.firmware_path, "rb"); + if(firmware_file == NULL){ + perror("Error opening firmware file"); + exit(EXIT_FAILURE); + } + + size_t firmware_size = stat.st_size; + uint8_t* firmware_buf = malloc(firmware_size); + if (firmware_buf == NULL) { + perror("failed to allocate firmware buffer"); + exit (EXIT_FAILURE); + } + + if (fread(firmware_buf, firmware_size, 1, firmware_file) != 1 || ferror(firmware_file) != 0) { + fprintf(stderr, "failed to read firmware\n"); + exit (EXIT_FAILURE); + } + fclose(firmware_file); + + /* + * Use Enclave To Resign the Firmware + */ + + sign_firmware(get_global_eid(), &ret, firmware_buf, firmware_size, sealed, sealed_size, (uint8_t*)&sgx_public, (uint8_t*)&sgx_signature); + if (ret != SGX_SUCCESS) { + print_error_message(ret); + exit (1); + } + + /* + * Output Signature + */ + if (sgx_signature_to_ECDSA_SIG(&sgx_signature, &ecdsa_signature) != 0) { + fprintf(stderr, "could not convert signature\n"); + exit (EXIT_FAILURE); + } + + ecdsa_signature_data = NULL; + ecdsa_signature_size = i2d_ECDSA_SIG(ecdsa_signature, &ecdsa_signature_data); + if (ecdsa_signature_size <= 0) { + fprintf(stderr, "could not convert signature\n"); + exit (EXIT_FAILURE); + } + + fwrite(ecdsa_signature_data, ecdsa_signature_size, 1, stdout); + + if (ferror(stdout) != 0) { + fprintf(stderr, "could not write signature to stdout\n"); + exit (EXIT_FAILURE); + } + + fflush(stdout); + + free(ecdsa_signature_data); + ECDSA_SIG_free(ecdsa_signature); + + free(sealed); exit(0); } + + + diff --git a/7-SGX_Hands-on/src/app/proxysetup.c b/7-SGX_Hands-on/src/app/proxysetup.c new file mode 100644 index 0000000..e0e94dc --- /dev/null +++ b/7-SGX_Hands-on/src/app/proxysetup.c @@ -0,0 +1,445 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "enclave_u.h" +#include "proxy.h" +#include "util.h" + +struct ProxysetupArgs { + char* sealed_key_file_path; + char* sgx_token_path; +}; + +char* proxysetup_syntax(void) { + return + "proxysetup implementation of the enclave-powered SignatureProxy\n" + " outputs public key on stdout\n" + " -s file path of the sealed proxy key\n" + " -t file path of the sgx token\n"; +} + + + +static EVP_PKEY *sgx_public_to_EVP_PKEY(const sgx_ec256_public_t *p_public) +{ + EVP_PKEY *evp_key = NULL; + EVP_PKEY_CTX *pkey_ctx = NULL; + BIGNUM *bn_pub_x = NULL; + BIGNUM *bn_pub_y = NULL; + EC_POINT *point = NULL; + EC_GROUP* group = NULL; + OSSL_PARAM_BLD *params_build = NULL; + OSSL_PARAM *params = NULL; + const char *curvename = NULL; + int nid = 0; + size_t key_len; + unsigned char pub_key[SGX_ECP256_KEY_SIZE+4]; + + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (group == NULL) + return NULL; + + do { + // converts the x value of public key, represented as positive integer in little-endian into a BIGNUM + bn_pub_x = BN_lebin2bn((unsigned char*)p_public->gx, sizeof(p_public->gx), bn_pub_x); + if (NULL == bn_pub_x) { + break; + } + // converts the y value of public key, represented as positive integer in little-endian into a BIGNUM + bn_pub_y = BN_lebin2bn((unsigned char*)p_public->gy, sizeof(p_public->gy), bn_pub_y); + if (NULL == bn_pub_y) { + break; + } + // creates new point and assigned the group object that the point relates to + point = EC_POINT_new(group); + if (NULL == point) { + break; + } + + // sets point based on public key's x,y coordinates + if (1 != EC_POINT_set_affine_coordinates(group, point, bn_pub_x, bn_pub_y, NULL)) { + break; + } + + // check point if the point is on curve + if (1 != EC_POINT_is_on_curve(group, point, NULL)) { + break; + } + + // convert point to octet string + key_len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pub_key, sizeof(pub_key), NULL); + if (key_len == 0) { + break; + } + + // build OSSL_PARAM + params_build = OSSL_PARAM_BLD_new(); + if (NULL == params_build) { + break; + } + nid = EC_GROUP_get_curve_name(group); + if (nid == NID_undef) { + break; + } + curvename = OBJ_nid2sn(nid); + if (curvename == NULL) { + break; + } + if (1 != OSSL_PARAM_BLD_push_utf8_string(params_build, "group", curvename, 0)) { + break; + } + if (1 != OSSL_PARAM_BLD_push_octet_string(params_build, OSSL_PKEY_PARAM_PUB_KEY, pub_key, key_len)) { + break; + } + params = OSSL_PARAM_BLD_to_param(params_build); + if (NULL == params) { + break; + } + + // get pkey from params + pkey_ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + if (NULL == pkey_ctx) { + break; + } + if (1 != EVP_PKEY_fromdata_init(pkey_ctx)) { + break; + } + if (1 != EVP_PKEY_fromdata(pkey_ctx, &evp_key, EVP_PKEY_PUBLIC_KEY, params)) { + EVP_PKEY_free(evp_key); + evp_key = NULL; + } + } while(0); + + BN_clear_free(bn_pub_x); + BN_clear_free(bn_pub_y); + EC_POINT_clear_free(point); + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(params_build); + EVP_PKEY_CTX_free(pkey_ctx); + EC_GROUP_free(group); + + return evp_key; +} + +static int EVP_PKEY_to_sgx_public(EVP_PKEY* ecdsa_key, sgx_ec256_public_t* sgx_public) { + EC_GROUP* group = NULL; + EC_POINT *point = NULL; + BIGNUM* pub_x = NULL; + BIGNUM* pub_y = NULL; + size_t ec_key_buf_len = 0; + unsigned char ec_key_buf[1024]; + int ret; + int retval; + + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (group == NULL) + return 1; + + point = EC_POINT_new(group); + if (point == NULL) + return 2; + + ret = EVP_PKEY_get_octet_string_param(ecdsa_key, OSSL_PKEY_PARAM_PUB_KEY, ec_key_buf, 1024, &ec_key_buf_len); + if (ret != 1) + return 3; + + ret = EC_POINT_oct2point(group, point, ec_key_buf, ec_key_buf_len, NULL); + if (ret != 1){ + retval = 4; + goto cleanup; + } + + pub_x = BN_new(); + pub_y = BN_new(); + + ret = EC_POINT_get_affine_coordinates(group, point, pub_x, pub_y, NULL); + if (ret != 1){ + retval = 5; + goto cleanup; + } + + ret = BN_bn2lebinpad(pub_x, sgx_public->gx, SGX_ECP256_KEY_SIZE); + if (ret == -1){ + retval = 6; + goto cleanup; + } + + ret = BN_bn2lebinpad(pub_y, sgx_public->gy, SGX_ECP256_KEY_SIZE); + if (ret == -1){ + retval = 7; + goto cleanup; + } + +cleanup: + if (pub_x != NULL) + BN_clear_free(pub_x); + if (pub_y != NULL) + BN_clear_free(pub_y); + if (point != NULL) + EC_POINT_clear_free(point); + if (group != NULL) + EC_GROUP_free(group); + + return (retval); +} + +/* +sgx_status_t pfz_ecdsa_verify_hash(const uint8_t *p_data, + const sgx_ec256_public_t *p_public, + const sgx_ec256_signature_t *p_signature, + uint8_t *p_result, + sgx_ecc_state_handle_t ecc_handle) +{ + if ((ecc_handle == NULL) || (p_public == NULL) || (p_signature == NULL) || + (p_data == NULL) || (p_result == NULL)) { + return SGX_ERROR_INVALID_PARAMETER; + } + + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *public_key = NULL; + BIGNUM *bn_r = NULL; + BIGNUM *bn_s = NULL; + ECDSA_SIG *ecdsa_sig = NULL; + unsigned char *sig_data = NULL; + size_t sig_size = 0; + sgx_status_t retval = SGX_ERROR_UNEXPECTED; + int ret = -1; + + *p_result = SGX_EC_INVALID_SIGNATURE; + + do { + public_key = pfz_get_pub_key_from_coords(p_public, ecc_handle); + if(NULL == public_key) { + break; + } + // converts the x value of the signature, represented as positive integer in little-endian into a BIGNUM + // + bn_r = BN_lebin2bn((unsigned char*)p_signature->x, sizeof(p_signature->x), 0); + if (NULL == bn_r) { + break; + } + + // converts the y value of the signature, represented as positive integer in little-endian into a BIGNUM + // + bn_s = BN_lebin2bn((unsigned char*)p_signature->y, sizeof(p_signature->y), 0); + if (NULL == bn_s) { + break; + } + + + // allocates a new ECDSA_SIG structure (note: this function also allocates the BIGNUMs) and initialize it + // + ecdsa_sig = ECDSA_SIG_new(); + if (NULL == ecdsa_sig) { + retval = SGX_ERROR_OUT_OF_MEMORY; + break; + } + + // setes the r and s values of ecdsa_sig + // calling this function transfers the memory management of the values to the ECDSA_SIG object, + // and therefore the values that have been passed in should not be freed directly after this function has been called + // + if (1 != ECDSA_SIG_set0(ecdsa_sig, bn_r, bn_s)) { + ECDSA_SIG_free(ecdsa_sig); + ecdsa_sig = NULL; + break; + } + sig_size = i2d_ECDSA_SIG(ecdsa_sig, &sig_data); + if (sig_size <= 0) { + break; + } + ctx = EVP_PKEY_CTX_new(public_key, NULL); + if (!ctx) { + break; + } + if (1 != EVP_PKEY_verify_init(ctx)) { + break; + } + if (1 != EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256())) { + break; + } + ret = EVP_PKEY_verify(ctx, sig_data, sig_size, p_data, SGX_SHA256_HASH_SIZE); + if (ret < 0) { + break; + } + + // sets the p_result based on verification result + // + if (ret == 1) + *p_result = SGX_EC_VALID; + + retval = SGX_SUCCESS; + } while(0); + + if (ecdsa_sig) { + ECDSA_SIG_free(ecdsa_sig); + bn_r = NULL; + bn_s = NULL; + } + if (ctx) + EVP_PKEY_CTX_free(ctx); + if (public_key) + EVP_PKEY_free(public_key); + if (bn_r) + BN_clear_free(bn_r); + if (bn_s) + BN_clear_free(bn_s); + + return retval; +} + + +sgx_status_t pfz_ecc256_open_context(sgx_ecc_state_handle_t* p_ecc_handle) +{ + if (p_ecc_handle == NULL) { + return SGX_ERROR_INVALID_PARAMETER; + } + + sgx_status_t retval = SGX_SUCCESS; + + EC_GROUP* ec_group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + if (NULL == ec_group) { + retval = SGX_ERROR_UNEXPECTED; + } else { + *p_ecc_handle = (void*)ec_group; + } + return retval; +} + +sgx_status_t pfz_ecdsa_verify(const uint8_t *p_data, + uint32_t data_size, + const sgx_ec256_public_t *p_public, + const sgx_ec256_signature_t *p_signature, + uint8_t *p_result, + sgx_ecc_state_handle_t ecc_handle) +{ + if ((ecc_handle == NULL) || (p_public == NULL) || (p_signature == NULL) || + (p_data == NULL) || (data_size < 1) || (p_result == NULL)) { + return SGX_ERROR_INVALID_PARAMETER; + } + unsigned char digest[SGX_SHA256_HASH_SIZE] = { 0 }; + + SHA256((const unsigned char *)p_data, data_size, (unsigned char *)digest); + return (pfz_ecdsa_verify_hash(digest, p_public, p_signature, p_result, ecc_handle)); +} +*/ + +int handle_proxysetup(int argc, char** argv) { + struct ProxysetupArgs args = { + NULL, + NULL + }; + + FILE* sealed_file; + + sgx_status_t sgx_ret; + + /* + * Parse Input + */ + + int i = 0; + while(i < argc) { + if(strcmp(argv[i], "-s")==0 && argc-i >=2){ + args.sealed_key_file_path = argv[i+1]; + i += 2; + }else if(strcmp(argv[i], "-t")==0 && argc-i >=2){ + args.sgx_token_path = argv[i+1]; + i += 2; + }else + syntax_exit(); + } + + if(args.sealed_key_file_path == NULL) + syntax_exit(); + + /* + * Initialize SGX Enclave + */ + + if (initialize_enclave(args.sgx_token_path) != 0) + exit(1); + + /* + * Setup Sealed Keypair + */ + + sealed_file = fopen(args.sealed_key_file_path, "wb"); + if(sealed_file == NULL){ + perror("Error opening sealed_key_file file"); + exit(1); + } + + int sealed_size; + sgx_ret = get_sealed_size(get_global_eid(), &sealed_size); + if (sgx_ret != SGX_SUCCESS) { + print_error_message(sgx_ret); + exit (1); + } + uint8_t* sealed = malloc(sizeof(uint8_t)*sealed_size); + if (sealed == NULL) { + fprintf(stderr, "failed to allocate for sealed key"); + exit(1); + } + + /* + * Use Enclave To Generate Keypair + */ + + generate_key_pair(get_global_eid(), &sgx_ret, sealed, sealed_size); + if (sgx_ret != SGX_SUCCESS) { + print_error_message(sgx_ret); + exit (1); + } + + /* + * Store Sealed Keypair + */ + + if (fwrite(sealed, sealed_size, 1, sealed_file) != 1 || ferror(sealed_file) != 0) { + fprintf(stderr, "failed to write sealed key"); + exit(1); + } + fflush(sealed_file); + fclose(sealed_file); + + /* + * Fetch Public Key From Enclave And Print + */ + + sgx_ec256_public_t sgx_public_key; + get_public_key(get_global_eid(), &sgx_ret, sealed, sealed_size, (uint8_t*)&sgx_public_key); + if (sgx_ret != SGX_SUCCESS) { + print_error_message(sgx_ret); + exit (1); + } + + EVP_PKEY* public_key = sgx_public_to_EVP_PKEY(&sgx_public_key); + + if (PEM_write_PUBKEY(stdout, public_key, NULL, NULL) != 1) { + fprintf(stderr, "could not write publickey\n"); + exit (EXIT_FAILURE); + } + + fflush(stdout); + + EVP_PKEY_free(public_key); + free(sealed); + + exit(0); +} + + + diff --git a/7-SGX_Hands-on/src/app/proxysetup.h b/7-SGX_Hands-on/src/app/proxysetup.h new file mode 100644 index 0000000..e4cf0f3 --- /dev/null +++ b/7-SGX_Hands-on/src/app/proxysetup.h @@ -0,0 +1,23 @@ +#ifndef _APP_PROXY_H_ +#define _APP_PROXY_H_ + + +/* + * @brief getter for proxysetup subcommand syntax string + * + * @returns null-terminated syntax string + */ +char* proxysetup_syntax(void); + +/* + * @brief CLI implementation for the "proxysetup" subcommand + * + * @param argc number of arguments with command and subcommand stripped + * @param argv arguments with command and subcommand stripped + * + * @returns 0 on success, else error with output on stderr + */ +int handle_proxysetup(int argc, char** argv); + + +#endif diff --git a/7-SGX_Hands-on/src/app/util.c b/7-SGX_Hands-on/src/app/util.c index f5b5791..8faf5e1 100644 --- a/7-SGX_Hands-on/src/app/util.c +++ b/7-SGX_Hands-on/src/app/util.c @@ -1,13 +1,17 @@ +#include #include #include #include "util.h" #include "proxy.h" +#include "proxysetup.h" #include "intermediary.h" static char* BIN_NAME = "SignatureProxy"; +static sgx_enclave_id_t global_eid = 0; + void syntax_exit(void) { char* syntax = "SignatureProxy Version 0.0.0\n" @@ -16,12 +20,166 @@ void syntax_exit(void) { "Commands:\n" "%s" "\n" + "%s" + "\n" "%s"; - printf(syntax, BIN_NAME, intermediary_syntax(), proxy_syntax()); + printf(syntax, BIN_NAME, intermediary_syntax(), proxy_syntax(), proxysetup_syntax()); exit(1); } void set_bin_name(char* bin_name) { BIN_NAME = bin_name; } + +typedef struct _sgx_errlist_t { + sgx_status_t err; + const char *msg; + const char *sug; /* Suggestion */ +} sgx_errlist_t; + +/* Error code returned by sgx_create_enclave */ +static sgx_errlist_t sgx_errlist[] = { + { + SGX_ERROR_UNEXPECTED, + "Unexpected error occurred.", + NULL + }, + { + SGX_ERROR_INVALID_PARAMETER, + "Invalid parameter.", + NULL + }, + { + SGX_ERROR_OUT_OF_MEMORY, + "Out of memory.", + NULL + }, + { + SGX_ERROR_ENCLAVE_LOST, + "Power transition occurred.", + "Please refer to the sample \"PowerTransition\" for details." + }, + { + SGX_ERROR_INVALID_ENCLAVE, + "Invalid enclave image.", + NULL + }, + { + SGX_ERROR_INVALID_ENCLAVE_ID, + "Invalid enclave identification.", + NULL + }, + { + SGX_ERROR_INVALID_SIGNATURE, + "Invalid enclave signature.", + NULL + }, + { + SGX_ERROR_OUT_OF_EPC, + "Out of EPC memory.", + NULL + }, + { + SGX_ERROR_NO_DEVICE, + "Invalid SGX device.", + "Please make sure SGX module is enabled in the BIOS, and install SGX driver afterwards." + }, + { + SGX_ERROR_MEMORY_MAP_CONFLICT, + "Memory map conflicted.", + NULL + }, + { + SGX_ERROR_INVALID_METADATA, + "Invalid enclave metadata.", + NULL + }, + { + SGX_ERROR_DEVICE_BUSY, + "SGX device was busy.", + NULL + }, + { + SGX_ERROR_INVALID_VERSION, + "Enclave version was invalid.", + NULL + }, + { + SGX_ERROR_INVALID_ATTRIBUTE, + "Enclave was not authorized.", + NULL + }, + { + SGX_ERROR_ENCLAVE_FILE_ACCESS, + "Can't open enclave file.", + NULL + }, +}; + +/* Check error conditions for loading enclave */ +void print_error_message(sgx_status_t ret) +{ + size_t idx = 0; + size_t ttl = sizeof sgx_errlist/sizeof sgx_errlist[0]; + + for (idx = 0; idx < ttl; idx++) { + if(ret == sgx_errlist[idx].err) { + if(NULL != sgx_errlist[idx].sug) + printf("Info: %s\n", sgx_errlist[idx].sug); + printf("Error: %s\n", sgx_errlist[idx].msg); + break; + } + } + + if (idx == ttl) + printf("Error code is 0x%X. Please refer to the \"Intel SGX SDK Developer Reference\" for more details.\n", ret); +} + +int initialize_enclave(char* token_path) { + FILE* sgx_token_file = NULL; + sgx_launch_token_t token = {0}; + sgx_status_t ret; + int updated = 0; + + if (token_path != NULL) { + sgx_token_file = fopen(token_path, "rb"); + } + + if(sgx_token_file == NULL){ + if (errno != ENOENT && token_path != NULL) { + perror("Error opening sgx token file"); + exit(1); + } + }else{ + size_t read_num = fread(token, 1, sizeof(sgx_launch_token_t), sgx_token_file); + if (read_num != 0 && read_num != sizeof(sgx_launch_token_t)) { + fprintf(stderr, "sgx token file is corrupted"); + return (1); + } + } + + ret = sgx_create_enclave("enclave.signed.so", SGX_DEBUG_FLAG, &token, &updated, &global_eid, NULL); + if (ret != SGX_SUCCESS) { + print_error_message(ret); + return (1); + } + + if (updated && token_path != NULL) { + sgx_token_file = freopen(token_path, "wb", sgx_token_file); + if(sgx_token_file == NULL){ + perror("Error opening sgx token file"); + return (1); + } + size_t write_num = fwrite(token, 1, sizeof(sgx_launch_token_t), sgx_token_file); + if (write_num != sizeof(sgx_launch_token_t)){ + fprintf(stderr,"Warning: Failed to save launch token to \"%s\".\n", token_path); + return (1); + } + } + return (0); +} + +sgx_enclave_id_t get_global_eid(void){ + return global_eid; +} diff --git a/7-SGX_Hands-on/src/app/util.h b/7-SGX_Hands-on/src/app/util.h index f1aa72e..05d43e0 100644 --- a/7-SGX_Hands-on/src/app/util.h +++ b/7-SGX_Hands-on/src/app/util.h @@ -1,6 +1,9 @@ #ifndef _APP_UTIL_H_ #define _APP_UTIL_H_ +#include + + /* * @brief prints the command syntax and exits with EXIT_FAILURE @@ -9,4 +12,10 @@ void syntax_exit(void); void set_bin_name(char* bin_name); +void sgx_print_error_message(sgx_status_t ret); + +int initialize_enclave(char* token_path); + +sgx_enclave_id_t get_global_eid(void); + #endif