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.56k stars 2.61k forks source link

Parse a public key in PEM format error #9037

Closed linhongz closed 7 months ago

linhongz commented 7 months ago

Summary

I stored the public key in PEM format inside an array in ROM, then attempted to parse it using mbedtls_pk_parse_public_key, but it failed.

System information

Mbed TLS version: 3.1.0 Operating system and version: ARM Cortex-M4F bare metal Configuration:

#define MBEDTLS_AES_ROM_TABLES
#define MBEDTLS_GENPRIME
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_ENTROPY_HARDWARE_ALT
#define MBEDTLS_PKCS1_V15
#define MBEDTLS_PKCS1_V21
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_ASN1_WRITE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_MD_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PEM_WRITE_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PK_WRITE_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA512_C

Compiler and options: ARMCC

Steps to reproduce

The following is my minimal implementation:

const char publicKey[] =    "-----BEGIN RSA PUBLIC KEY-----\n"\
                            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArM6wMjgCViDkO2hBA0tn\n"\
                            "zKn0FWN77tf4DwJGabvddpE2sji4ixX8jsw3mZfvFFwlVLpUYBPDebytNkandIK6\n"\
                            "4q0C5sUa38RiUw8SLyfXF/oOXkJIV6VM4wZGW9kgC7gPq1SfUTP27VQP5ms6TA3K\n"\
                            "F07FAnCp2B8Abv6DuzN4Z6bBvch56JkSKnBtrt3rEDnXvHh1o/i3oGdiZTWfax2Q\n"\
                            "8zDykFr8dTkJI2WvemQ8qV2t9FPdGbuV2Gfh6FrleYRpPuvZnlernMZY3nh7/bYn\n"\
                            "E6zszNWf+6ay9VRvEFeNKbsmmA1duk8VHdGywfFPxSd0ny9cdp5x4wCqhby5cx3E\n"\
                            "gQIDAQAB\n"\
                            "-----END RSA PUBLIC KEY-----\n";
mbedtls_rsa_context *loadRsa;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_pk_context pk;
const char *pers = "rsa_key_generation";

mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_pk_init(&pk);
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                                    (const uint8_t *) pers, strlen(pers));

mbedtls_pk_parse_public_key(&pk, (const unsigned char *)publicKey, strlen((char *)publicKey) + 1);
mbedtls_pk_get_type(&pk);
loadRsa = mbedtls_pk_rsa(pk);

mbedtls_pk_parse_public_key-->>pk_get_rsapubkey-->>

/* Import N */
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 )
    return( MBEDTLS_ERROR_ADD( MBEDTLS_ERR_PK_INVALID_PUBKEY, ret ) );

Here is where the function ultimately fails to execute. Could it be that the format of the array where I stored the keys is incorrect? The key pair was generated by mbedTLS on the platform I'm using. I also tried using key pairs generated by OpenSSL, but encountered the same issue

Additional information

private key:

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEArM6wMjgCViDkO2hBA0tnzKn0FWN77tf4DwJGabvddpE2sji4
ixX8jsw3mZfvFFwlVLpUYBPDebytNkandIK64q0C5sUa38RiUw8SLyfXF/oOXkJI
V6VM4wZGW9kgC7gPq1SfUTP27VQP5ms6TA3KF07FAnCp2B8Abv6DuzN4Z6bBvch5
6JkSKnBtrt3rEDnXvHh1o/i3oGdiZTWfax2Q8zDykFr8dTkJI2WvemQ8qV2t9FPd
GbuV2Gfh6FrleYRpPuvZnlernMZY3nh7/bYnE6zszNWf+6ay9VRvEFeNKbsmmA1d
uk8VHdGywfFPxSd0ny9cdp5x4wCqhby5cx3EgQIDAQABAoIBACrigEd2Lt5A+2Li
1H+EzxWzd6d3MOJtJlpTLjY/MQ6jqvc/rEyYAD1P4Nx1IBflZj5In3fYb8JeWH4H
urbnWom2denfMHQnwF7sdo7NTEve+oHZ4SofE52jiQJyN8mwu/LA5Wi5hKYRHoEI
S0dkhKqUGcApRX0k9G6XKwniFBdkmd/KT24yyzFfF9OkF6kYPLu5FNCm7d15Nxl8
vWLOA0TyvBxwX2rtNyv9Fs7XXDJKIJMkIZFhDpbCVxBP0Kqz6RC0wXjAURc9blu5
Z94au6H724hvALsHNqeUWCWNWNWjHVh9tZAjvb0B9N3xQf/dYp+DycBvq8cBlnn9
p0C+qCECgYEA6kA2BcZrnmc+M2mUOySHlA4I+BQoy576CCgYXxOM3WCZn/oGwGnQ
xWOcFiPfTr1nC3/3k7Cfat5ccWWnKpWiqISy2HkADSCApzfngu0UMN+wBuxNNi9b
HO01JdeA7yT4+ghaUSbmWW97EQfWIeN+6+grg73338VMkDK0Biz9jOcCgYEAvNoP
IQRMiHleqMmSCmCNx/aflZXsZ1cRm+14kA7aximadDiyvdGJOScaRWlvugQKfDeX
haQAFnRM9A6+y7lfveJtGh4i9F8U37hTNuaIn78DnGWXweliWfxdPn0gr1lQ7EjB
0AqC1RsDnpScYFvQCNOf2CavMW20pWmCUlbHzlcCgYAaEyGwTODn1fgvgt4UI0HQ
Miu/aYcM+1o7lDL6SlPQxJL1IsCjpGOvxSG3uTB/NEgHGKx3TR7Bp5TErpsH+3YK
qhK6U+W0kFyhwHBNu5QWyJ9wddc2Y9kRhDn5R167v/LS6iEbjWfwpp8dSzEDvq3/
Fm3ZkUjJKM4X8vzk/xcOGwKBgHLboMXw6mc6gfLgHX1IOhL7ERYWR+CWGPSf2mqr
Ti2lkfXLohJGhVIIUTcUKEqXOJVR7krucss1UrRA35PiG7POKZLv70x3I6fpYFsM
nN2jfBu7wi/CtPmLvl5KFf3vsYLzwUS5j9byhiIFupH0ZTNpGleJN5Y1ZeAQqp1P
gFgjAoGBAMV6tSOfjtr/oRv0l4lL1Cbad/A/6yzPbE4FyijgaGSiYu99r/hGKfQk
QGdpXnA6uRq2T0bvkCVnX2BzavxkMX1amwBkTACAT8+jACgko6qcUppqUuqleeO2
LrWBLFHTBAEGYk8YR5Xi215Fv9PYeK3GceEmtAvzuWJxyEc2GRam
-----END RSA PRIVATE KEY-----
gilles-peskine-arm commented 7 months ago

Change BEGIN RSA PUBLIC KEY to BEGIN PUBLIC KEY and same with the END.

There are two popular binary formats for RSA public keys: the PKCS1 format that's specifically about for keys, and the SubjectPublicKeyInfo format that can encode other key types such as ECC. Mbed TLS supports both transparently for DER. For PEM, you need to have the correct BEGIN/END descriptor.

This also happens with RSA private keys (PKCS1 vs PKCS8) and ECC private key (SEC1 vs PKCS8). Transparent for DER parsing, but a PEM file needs to have the correct header.

Did some popular tool produce that PEM encoding with a mismatched header? We could make the Mbed TLS parsing code sloppier, I don't think it would be harmful except for making the code messier, but I don't remember this being requested before.

linhongz commented 7 months ago

Change BEGIN RSA PUBLIC KEY to BEGIN PUBLIC KEY and same with the END.

There are two popular binary formats for RSA public keys: the PKCS1 format that's specifically about for keys, and the SubjectPublicKeyInfo format that can encode other key types such as ECC. Mbed TLS supports both transparently for DER. For PEM, you need to have the correct BEGIN/END descriptor.

This also happens with RSA private keys (PKCS1 vs PKCS8) and ECC private key (SEC1 vs PKCS8). Transparent for DER parsing, but a PEM file needs to have the correct header.

Did some popular tool produce that PEM encoding with a mismatched header? We could make the Mbed TLS parsing code sloppier, I don't think it would be harmful except for making the code messier, but I don't remember this being requested before.

image Sorry for the oversight. I manually edited the key header based on what I saw in the code. After changing it to the standard PEM format, importing it worked fine. Additionally, regarding storing PEM format in an array, are there any special requirements for newline characters like '\r', '\n' or spaces?