#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "enclave_u.h" #include "proxy.h" #include "util.h" struct ProxyArgs { char* sealed_key_file_path; char* sgx_token_path; char* employee_public_key_path; char* firmware_path; }; 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" " 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* sealed_file; FILE* firmware_file; uint8_t *sealed; 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 */ 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 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.employee_public_key_path == NULL || args.firmware_path == NULL) syntax_exit(); /* * Read Signature Input */ ecdsa_signature_data = malloc(1024); if (ecdsa_signature_data == NULL) { perror("failed to allocate signature"); exit(1); } 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); } 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); } /* * Read Sealed Proxy Keypair */ sealed_file = fopen(args.sealed_key_file_path, "rb"); if(sealed_file == NULL){ perror("Error opening sealed_key_file file"); exit(1); } 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); } 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); } fclose(sealed_file); /* * 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); }