Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for writing encrypted private keys #1372

Open
Dmitry-Frantsev opened this issue Feb 14, 2018 · 12 comments
Open

Add support for writing encrypted private keys #1372

Dmitry-Frantsev opened this issue Feb 14, 2018 · 12 comments
Labels
component-crypto Crypto primitives and low-level interfaces enhancement help-wanted This issue is not being actively worked on, but PRs welcome.

Comments

@Dmitry-Frantsev
Copy link

Description

  • Type: Enhancement\Feature Request
  • Priority: Major

Enhancement\Feature Request

Add support a cipher for storing private keys please.
I use mbedtls library for RSA key pair generation.
It is very important to store a private key with cipher.

@RonEld
Copy link
Contributor

RonEld commented Feb 14, 2018

Hi @Dmitry-Frantsev I am not sure what your request is.
Do you mean a way to store the private key in the file system?
Can you please explain why it is important to store a private key with cipher? IMHO, a cipher is meant for encryption\decryption data. Not to store a private key in the file system.

@Dmitry-Frantsev
Copy link
Author

Dmitry-Frantsev commented Feb 15, 2018

Hi.
I have used openSSL library until now.
My program has a file system storage with ecrypted users private keys (PEM format).
The program loads the encrypted private key and decrypts it when user is logging in.

MBEDTLS library can load encrypted RSA keys (PEM format).
I use mbedtls_pk_parse_key( ) function to load keys. It works perfectly.
But function mbedtls_pk_write_key_pem( ) can not save a RSA key with encription.

Could you add encryption support for mbedtls_pk_write_key_pem( ).

@RonEld RonEld changed the title Add support a cipher for storing private keys. Add support for writing encrypted private keys Feb 17, 2019
@RonEld RonEld added the component-crypto Crypto primitives and low-level interfaces label Feb 17, 2019
@fayak
Copy link

fayak commented Jul 3, 2019

Bump!

@Patater
Copy link
Contributor

Patater commented Jul 3, 2019

Mbed TLS supports key wrapping. See https://github.com/ARMmbed/mbedtls/blob/development/include/mbedtls/nist_kw.h

Does this work in your use case? If not, why not?

@Ender-events
Copy link

It can work but a solution that will export in PEM format a passphrase-protected key will be appreciated. Like said before, a function mbedtls_pk_write_key_pem that will take a passphrase in arguments.

@r4bbit-r4
Copy link

Is there a solution for this? I really need to take use this. There really isn't any other solution for me.

@gilles-peskine-arm gilles-peskine-arm added the help-wanted This issue is not being actively worked on, but PRs welcome. label Nov 2, 2020
@gilles-peskine-arm
Copy link
Contributor

This feature would make sense, but Arm isn't likely to work on it in the foreseeable future. Pull requests welcome.

@loafer-mka
Copy link

Is there a solution for this? I really need to take use this. There really isn't any other solution for me.

Some preview of this is available at fork https://github.com/loafer-mka/mbedtls, branch ‘dev_clean’.
The last four commits in this branch add new features, and the optional three previous ones slightly adjust the project for older versions of visual studio, gcc and python 3.4.

This is an attempt to add enhanced support for load/store encrypted and plain keys in different formats... there are not tests at all (added/changed functions were tested together with other project which uses mbedtls... so they are working ... it seems to me ;) )
Also I'm not sure about the convenient API... may be some functions may be combined.

Over time, I hope to add tests and refine the pull request, but it will take time.

If you can check and suggest a better API, then that would be great.

Questions and wishes are welcome.
Andrey Makarov, [email protected]

@seppestas
Copy link

What is missing in MBed TLS is support (in the form of utility functions) for writing PKCS#8 formatted private keys. I think this is what most people colloquially refer to as "PEM formatted" private keys. A better title for this issue would be "Add support for writing encrypted PKCS#8 keys".

Note that MBed TLS already has features for converting ASN.1 DER data to PEM (mbedtls_pem_write_buffer). However, it is missing easy ways to encrypt private keys and store the encrypted keys in a standard format. Personally, I prefer to keep keys in DER format on (typically memory / CPU constrained) systems using MBed TLS.

Currently the only way to (somewhat easily) create encrypted private keys in MBed TLS is using the PKCS#5 format, with mbedtls_pkcs5_pbes2 ([mbedtls_pkcs5_pbes2_ext](https://mbed-tls.readthedocs.io/projects/api/en/development/api/file/pkcs5_8h/?highlight=mbedtls_pkcs5_pbes2#_CPPv423mbedtls_pkcs5_pbes2_extPK16mbedtls_asn1_bufiPKh6size_tPKh6size_tPh6size_tP6size_t in newer versions)).

However, this has some downsides:

  • mbedtls_pkcs5_pbes2 requires ASN.1 formatted PBE parameters. It was clearly more designed for parsing (decrypting) existing keys than writing new keys.
  • The PKCS#5 encrypted key itself is not an ASN.1 structure, so it has to be wrapped in e.g. the PKCS#8 structure to be a "standard format" private key.

So it should be possible to create a "PEM PKCS#8 encrypted private key" in MBedTLS, which is the default private key format for tools like OpenSSL, but it's far from convenient, requiring the following steps:

  • Create the private key (e.g. with mbedtls_rsa_gen_key)
  • Convert the key in DER format (or at least BER, see https://datatracker.ietf.org/doc/html/rfc5208#section-6).
  • Create PBE parameters for the encryption
  • Encrypt the private key with mbedtls_pkcs5_pbes2
  • Create a PKCS#8 ASN.1 structure containing the PBE parameters and the encrypted key
  • Convert the DER encoded private key in a PEM format with mbedtls_pem_write_buffer

This is in stark contrast to the easy of use of the private key parsing function mbedtls_pk_parse_key and writing utility functions like mbedtls_x509write_cert and mbedtls_x509write_csr.

@gilles-peskine-arm
Copy link
Contributor

@seppestas Thanks for the feedback! Work on features such as this one is unfortunately paused while we prepare the next major version of Mbed TLS, and we'll need to expand the API to cover encrypted key formats which will likely land after 4.0. So this is on our radar, but won't happen soon.

@seppestas
Copy link

I eventually settled on using a plain AES cypher to encrypt private keys iof. mbedtls_pkcs5_pbes2. 2 reasons for this:

  1. mbedtls_pkcs5_pbes2 is kind of broken, possibly in an insecure way, even when used for decryption. This was only fixed recently in Mbed TLS 3.5.0 : https://github.com/Mbed-TLS/mbedtls/blob/development/ChangeLog#L323-L327.
  2. The version of MBed TLS I use only supports DES and DES-EDE-CDC cyphers for PKCS#5. Probably safe enough, but AES is a bit more modern and probably more efficient.

Either way, my application has fairly little benefit from thing like PBKDF.

I still think it should be possible to use mbedtls_pkcs5_pbes2_ext for generating PKCS#8 format encrypted private keys, but it's quite a pain. I think what @loafer-mka mentions in his fork

Note: mbedtls_pkcs5_pbes2() cannot be used for encrypting key: it does not return [the] actual length of encrypted data after padding, so we cannot assign OCTET_STRING length after encryption.
Moreover: best way is to pad buffer manually and disable padding by cipher because mbedtls_cipher_crypt() (like as mbedtls_cipher_update()) cannot pad if in-place encrypting (input buffer == output buffer) used.

Can be overcome by reserving space (at least one block size) for the padding and calculating the expected padding size (and thus cyphertext size) based on the cypher block size.

Though I never got it working fully and lost interest in getting it working when I realised mbedtls_pkcs5_pbes2 isn't safe in my version of Mbed TLS.

@csmith-morningstar
Copy link

csmith-morningstar commented Aug 1, 2024

Wanted to note that @seppestas workaround seems do-able in version 3.6.0. I have verified it by modifying the gen_key program to encrypt the key using a password:

https://github.com/morningstarcorp/mbedtls-morningstar/tree/experimental/gen_pkcs5_enc_key

The resulting key can be parsed by openssl without issue.

(please note that in my example I hard-code the salt and IV for ease of debugging, it's intended only as an example of constructing the ASN.1 structure properly)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component-crypto Crypto primitives and low-level interfaces enhancement help-wanted This issue is not being actively worked on, but PRs welcome.
Projects
Status: No status
Development

No branches or pull requests

10 participants