Search code examples
c++csgx

Copying a Public key Mod from an Intel SGX Enclave to Untrusted area


I am developing a C pseudo-API in which Java code calls C code through the JNI, in which it connects to an Intel SGX Enclave. I have a function in which I create an RSA-Key pair to be used further on.

Create RSA Pair:

sgx_status_t create_rsa_pair(){
unsigned char p_n[RSA_MOD_SIZE];
unsigned char p_d[RSA_MOD_SIZE];
unsigned char p_p[RSA_MOD_SIZE];
unsigned char p_q[RSA_MOD_SIZE];
unsigned char p_dmp1[RSA_MOD_SIZE];
unsigned char p_dmq1[RSA_MOD_SIZE];
unsigned char p_iqmp[RSA_MOD_SIZE];

int n_byte_size = RSA_MOD_SIZE;
long e = 65537;


sgx_status_t ret_create_key_params = sgx_create_rsa_key_pair(n_byte_size, sizeof(e), p_n, p_d, (unsigned char*)&e, p_p, p_q, p_dmp1, p_dmq1, p_iqmp);

if (ret_create_key_params != SGX_SUCCESS) {
    ocall_print("Key param generation failed");
}

//void *private_key = NULL;

sgx_status_t ret_create_private_key = sgx_create_rsa_priv2_key(n_byte_size, sizeof(e), (unsigned char*)&e, p_p, p_q, p_dmp1, p_dmq1, p_iqmp, &private_rsa);

if(ret_create_private_key != SGX_SUCCESS) {
    ocall_print("Private key generation failed");
}

void *public_key = NULL;

sgx_status_t ret_create_public_key = sgx_create_rsa_pub1_key(n_byte_size, sizeof(e), p_n, (unsigned char*)&e, &public_key);

if(ret_create_public_key != SGX_SUCCESS) {
    ocall_print("Public key generation failed");
}

//Copy the result and send it in an ocall.
uint8_t* ocall_mod = (uint8_t*)malloc(RSA_MOD_SIZE);
uint8_t* ocall_exp = (uint8_t*)malloc(sizeof(long));
memcpy(ocall_mod,p_n,RSA_MOD_SIZE);
memcpy(ocall_exp,&e,sizeof(long));
printf("pre/ocall_mod::");
for(int i = 0; i < RSA_MOD_SIZE;i++){
    printf("%"PRIu8",",ocall_mod[i]);
}
printf("\n");
ocall_return_pubkey(ocall_mod,ocall_exp);
return SGX_SUCCESS;
}

Ocall code:

void ocall_return_pubkey(uint8_t* key_mod,long *key_exp){
  printf("Post/Ocall key-mod:: ");
  for(int i = 0; i < RSA_PUBLIC_SIZE;i++)
    printf("%"PRIu8",",key_mod[i]);
   printf("\n");

Now, If I compile this and check terminal results:

pre/ocall_mod::199,100,141,174,148,185,21,88,102,216,116,190,170,232,156,196,107,78,228,1,5,38,92,154,20,11,234,149,74,19,254,237,240,223,145,92,188,248,25

Post/Ocall key-mod:: 199,0,0,0,0,0,0,0,0,0,57,44,0,127,0,0,0,83,144,167,247,127,0,0,9,107,99,240,0,0,0,0,172,141,193,3,0,0,0,0,68,83,144,167,247

I've posted only a portion of the mod for brevity's sake, but the information does seem to be corrupted or deleted, especially considering the large number of 0's.

I've tried passing a pointer throught the Ecall as an argument in order to receive my result through it, but (at least in this scenario), the enclave blocks the program execution due to this copy from trusted to untrusted memory, meaning that sending a pointer from the enclave through an ocall seems like the only option. Any help or tips for this? Thanks in advance.

Edit: On a separate note, All the code I've written works if all used in a single function (Encryption, Decryption + Creation of an AES key), but if it is separated into multiple functions, it fails, for some reason.


Solution

  • Using ocalls to return information is not the way to go for this.

    While I had failed previously with this Idea, the way to go is by adding a pointer and its size to a functions arguments in order to copy the results.

    so Enclave EDL

    public sgx_status_t whatever([out,size=output_size]uint8_t* output,size_t output_size)
    

    Now, bear in mind that output_size is not the number of bytes written. By setting output_size = 0 before using the Ecall, the corresponding buffer inside the enclave will be NULL, returning a segfault upon usage. if at any point you require the number of bytes written, i.e encryption, you should use the following:

    sgx_status_t encrypt([out,size=output_size]uint8_t *output, size_t output_size, [out,size=num_size]size_t* bytes_written,size_t num_size);
    

    In which num_size should be equal to sizeof(size_t).

    I was able to solve this problem, Hope it helps you guys.