Mbed-TLS / mbedtls

An open source, portable, easy to use, readable and flexible TLS library, and reference implementation of the PSA Cryptography API. Releases are on a varying cadence, typically around 3 - 6 months between releases.
https://www.trustedfirmware.org/projects/mbed-tls/
Other
5.54k stars 2.6k forks source link

Add support for writing encrypted private keys #1372

Open Dmitry-Frantsev opened 6 years ago

Dmitry-Frantsev commented 6 years ago

Description

RonEld commented 6 years ago

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 commented 6 years ago

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( ).

fayak commented 5 years ago

Bump!

Patater commented 5 years ago

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 commented 5 years ago

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 commented 4 years ago

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 commented 4 years ago

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

loafer-mka commented 3 years ago

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, mka-at-mailru@mail.ru

seppestas commented 4 months ago

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:

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:

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 commented 4 months ago

@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 commented 4 months ago

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 commented 3 months ago

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)