Generating private/public key pair in pem format

Hello,

Please forgive the fact that I am a little new to generating key pairs. I have done this using openssl in the past but now I’m working on an embedded device(ESP32) and have to do this at a much lower level so some things are going over my head.

Essentially I am provisioning a device to Google IoT but this requires a key pair to be generated on the device for customer ease of use. This is google’s documenation on generating the pair with openssl:

I am attempting to accomplish the same thing using mbedtls.

I found mbedtls_rsa_gen_key and did some slight porting of this code to get it running successfully on the ESP32.

This does appear to create a public key file and a private key file. However it is not in the format I’m use to seeing(PEM). How do I go about converting these two files(rsa_pub.txt/rsa_priv.txt) into PEM files? I tried creating a pk_context and copied the information over to the Public Key abstraction Layer as @ roneld01 explained on Write RSA public key top PEM but I’m a bit lost.

A light nudge in the right direction would be most appreciated.

Thank you so much for reading and have a great day.
Travis

I think what is really hanging me up is my rsa context appears to contain both the public and private key so this code essentially instantiates a new Public Key context and then copies the rsa context into it:

mbedtls_pk_context pk;
if(mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA) ) != 0){
     Serial.println("pk_setup failed");
}
memcpy( mbedtls_pk_rsa( pk ),  &rsa, sizeof(rsa));

So if I copy that rsa context into the new public key context it would contain two keys but pk does not seem to have handling for that. Do I need to create two separate RSA contexts and then from those create two separate PK contexts?

HI @IOTrav
I apologize but I don’t quite understand your question.

The rsa_pub.txt and rsa_priv.txt files are not in a ny standard format.
If you want to generate from scratch a key, then I would recomend you use directly the pk layer, and follow the example gen_key.

This article should help you get started

Regards,
Mbed TLS Support
Ron

Hi @roneld01,

I apologize for not being clear on my question. I’m new to doing something like this at such a low level.

Yes, I want to generate key files from scratch, but I need both a private and public key.

Essentially what I need is to replicate this openssl sequence which results in a private key pem and a public key pem:

openssl genpkey -algorithm RSA -out rsa_private.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem

I need to replicate this functionality using the mbedtls library.

That sample application only appears to generate 1 key if I’m reading it correctly. I need a private key pem file and a public key pem file. How would this be accomplished?

Hi @IOTrav
The sample application shows an example how to generate a key pair into a context ( rsa or ecp ).

Once you have the relevant context, you can use this context to write both the public key and the private key in PEM format, using mbedtls_pk_write_pubkey_pem() and mbedtls_pk_write_key_pem().
You can look at the key_app_writer sample application to learn how to write the public and private keys from a mbedtls_pk_context.
Regards

Thank you @roneld01,

I had actually just found that mbedtls_pk_write_key_pem() function(not sure how I missed that yesterday).

I just implemented that function but it is failing. I did a check on both mbedtls_rsa_check_pubkey and mbedtls_rsa_check_privkey on my rsa context and both return 0. If the RSA context contains both and I perform: memcpy( mbedtls_pk_rsa( pk ), &rsa, sizeof(rsa)); then why would mbedtls_pk_write_key_pem() fail? mbedtls_pk_write_pubkey_pem by the way is succeeding. I do not understand what mbedtls_pk_ec is, do I need that(Not sure what an EC context is)?

Break down of my order of operations:

mbedtls_rsa_gen_key
mbedtls_rsa_check_pubkey
mbedtls_rsa_check_privkey
mbedtls_rsa_export
mbedtls_rsa_export_crt
mbedtls_pk_init
mbedtls_pk_setup( &pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA) )
memcpy( mbedtls_pk_rsa( pk ), &rsa, sizeof(rsa))
mbedtls_pk_write_pubkey_pem
mbedtls_pk_write_key_pem *Fails

Hi @IOTrav

EC context is when you are using an elliptic curve algorithm. Since you are using rsa, it is not relevant.

You don’t need to export your rsa components, for writing the key. In addition, you either use mbedtls_rsa_export or mbedtls_rsa_export_crt, but not both.

As mention, it is better you follow the instructions in gen_key, and generate the key directly inside the PK context (This will save you the need to use memcpy)

Since both mbedtls_rsa_check_pubkey and mbedtls_rsa_check_privkey succeed, this means that you have a valid key pair, and writing both public key and private key should succeed, if you set up everything correct.
Note that a private key contains all components of the key pair ( public and private components ) while the public key contains only the public components
You should check what the error code that you are receiving, to understand better the root cause for failure.
Is the size of the buffer you are sending to mbedtls_pk_write_key_pem big enough?
Regards

I have tried your operations, and I haven’t received a failure.
Only when I reduced the size of the buffer to write to, I got a failure in the mbedtls_pk_write_key_pem() call. The buffer was big enough for the mbedtls_pk_write_pubkey_pem() call

You were indeed correct. I was only passing a buffer of 1000 bytes to mbedtls_pk_write_key_pem. I increased it to 5000 and it succeeded.

Given that I need a public/private key pair should I use mbedtls_rsa_export or mbedtls_rsa_export_crt?

I have converted application to use pk directly instead of rsa and copying over. I will absolutely share a class for this once I have it complete in case anyone needs this for ESP in the future.

@roneld01,

I want to say thank you so much for your help both directly and indirectly through the other threads I read your answers on. I do some technical support as well so I know the struggle.

As a token of my gratitude here is a library designed to generate a public/private key pair and store them in PEM format to ESP’s SPIFFS file system. Please feel free to take a look and let me know if I’m missing anything or if there are any issues with it you can see.

Also if you would PM me with your email account I’d love to send you some cash over PayPal for a beer.

Have a great rest of the week!

Thanks again,
Travis Elliott

HI @IOTrav
Thank you for your kind words and appreciation. I am only doing my job, there is no need to send me any cash, but I appreciate the gesture!

Given that I need a public/private key pair should I use mbedtls_rsa_export or mbedtls_rsa_export_crt ?

Once you have the pk context, you already have the key pair. Calling the export functions will only export the components from your context. The crt stands for Chinese Remainder Theorem, and it is used to speed operations, but it depends on whether your target product requires this or not, depending on the specifications and market. If you want to have the key pair in RAM for future operations with Mbed TLS, you don’t really need to export the components, and you will only need to keep the context.

Looking at your code, you don’t need to export the components at all, as you don’t use them.
I have a couple of comments \ questions on your code regarding the functionality:

  1. If you want to store the keypair on an embedded system, have you considered storing them in DER format, which will save you some Flash size? In addition, if you disable MBEDTLS_PEM_WRITE_C and MBEDTLS_PEM_PARSE_C you will also save code size( and RAM size).
  2. As mentioned, The private key contains both private and public components, while the public key contains only the public components, so there is no need for you to call mbedtls_pk_write_pubkey_pem()

Regards

Hi @roneld01

Thank you for the suggestions! I’ve removed the call to mbedtls_rsa_export. Your explination there makes perfect sense. I suppose this would only be useful if you were creating a PK context from an RSA context(or similar).

  1. I will make a note in the read me for that GitHub repo to suggest storing the keys in DER format if storage space is limited. For my application I must have the keys in PEM format and I have ample storage space available so I’ll probably leave well enough alone there.

  2. If I need two separate char/byte arrays one containing the private key and one containing the public key how would this be accomplished using only mbedtls_pk_write_key_pem? I am still a bit green when it comes to keys at this low level but if I understand correctly an RSA Private key consists of 5 parts(N, P, Q, D, and E), while a public key consists of only 2 parts(N and E). Is that correct? If so I guess it would be possible to extract just the public key portion from a private key and generate an array from that. That however seems a bit more complicated than nessisary given I have pretty good processor resources on the ESP32. I would like to know this information though just in case I need it in the future.

Updated to GitHub repo:

I apologize for this being a lesson in how Keys work :slight_smile:
Thanks again @roneld01

Hi @IOTrav

if I understand correctly an RSA Private key consists of 5 parts(N, P, Q, D, and E), while a public key consists of only 2 parts(N and E). Is that correct?

Yes, you are correct (For ECC keys the components are different, but still a private key d and a public point Q ).
If you need the public key, in PKCS 1 format, to share with other peers, then you can use mbedtls_pk_write_pubkey_pem() on the fly, and send it to the remote peer, without storing it to flash, but this is an optimization that perhaps you may not need.

Regards,
Ron