openenclave / openenclave

SDK for developing enclaves
https://openenclave.io/sdk/
MIT License
1.07k stars 357 forks source link

Asymmetric RSA key code #3031

Open wintersteiger opened 4 years ago

wintersteiger commented 4 years ago

The code to initialize an oe_public_key_t in oe_public_key_init has different behavior on the host and in the enclave. The mbedTLS code sometimes copies keys: https://github.com/openenclave/openenclave/blob/5eb82c855a3874817578b17a5e46671c1a77d077/enclave/crypto/key.c#L77 while the OpenSSL code never does so: https://github.com/openenclave/openenclave/blob/5eb82c855a3874817578b17a5e46671c1a77d077/host/crypto/openssl/key.c#L30 For me, the result was a double free that took me quite a while to trace. It would have helped me if the oe_public_key_free functions had set the corresponding key fields (public_key/impl->pkey) to NULL, because my code would have failed much earlier.

Relates to #1003, #3007.

mikbras commented 4 years ago

Thank you Christoph for filing the issue.

I was wondering whether you're calling oe_public_key_init() directly or indirectly. If indirectly, which of these functions are you calling?

oe_rsa_public_key_init()
oe_cert_get_rsa_public_key()
oe_rsa_get_public_key_from_private()

Hopefully this information will help me pinpoint the bug.

Thanks!

wintersteiger commented 4 years ago

Hi Mike, thanks for taking a look at this!

I use oe_rsa_public_key_init and oe_rsa_public_key_free (here). The mbedTLS version of oe_rsa_public_key_init creates an internal copy, while the OpenSSL version doesn't, so I need an additional mbedtls_pk_free. I may well be using the API in an unusual way, so let me know if there's a better/cleaner way to do this.

mikbras commented 4 years ago

Hi Mike, thanks for taking a look at this!

I use oe_rsa_public_key_init and oe_rsa_public_key_free (here). The mbedTLS version of oe_rsa_public_key_init creates an internal copy, while the OpenSSL version doesn't, so I need an additional mbedtls_pk_free. I may well be using the API in an unusual way, so let me know if there's a better/cleaner way to do this.

Oh, I see. I guess oe_rsa_public_key_init is an internal function since it is not exposed under the include directory. There seem to be three solutions.

  1. Pass the key to oe_ras_public_key_init and never free it (the function takes over the key and decrements the reference count eventually).
  2. Up-ref the key (EVP_PKEY_up_ref) before calling oe_ras_public_key_init and then free it later (EVP_PKEY_free).
  3. Convert the key to PEM format, and then call the public (well more public) function called oe_rsa_private_key_read_pem.

If you tried #1 or #2 and they don't work, then OE might have a bug and I'll look into it.

The APIs are dissimilar because mbedtls uses copying whereas openssl uses reference counting. Maybe the openssl RSA functions should have increased the reference count (but then the caller would have to free the key). Since the init functions are internal, I guess little attention was paid to the diferences.

wintersteiger commented 4 years ago

I see, makes sense now! It's been a while, but if I remember correctly, not freeing the mbedTLS key reports a memory leak, that why I dug deeper. You're right, maybe I should just up-ref the OpenSSL key to make it symmetric again. I would expect oe_rsa_public_key_init to do that for me though.

mikbras commented 4 years ago

I would expect oe_rsa_public_key_init to do that for me though.

I agree and if this ever becomes a public API, I would suggest that the function should make a deep copy of the key since changing the key after the call affects the behavior in one case (OpenSSL) but not the other (mbedtls).

manojrupireddy commented 4 years ago

I have few questions here.

@CodeMonkeyLeet - Adding Simon for context.

CodeMonkeyLeet commented 4 years ago

@manojrupireddy

manojrupireddy commented 4 years ago

From the above discussion comments, action items were summarized below.