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

Error during RSA Key parse. #7786

Closed
SangsubLim opened this issue Jun 16, 2023 · 7 comments
Closed

Error during RSA Key parse. #7786

SangsubLim opened this issue Jun 16, 2023 · 7 comments

Comments

@SangsubLim
Copy link

Summary

First of all, I'm not sure if I can leave a question here as it's my first time here.
Calling mbedtls_pk_parse_key returns 3d00.
I am trying to write a code that checks whether the RSA private key data input from the outside is PKCS#1 or PKCS#8.

The code I'm testing is:

#include "mbedtls/pk.h"
#include "mbedtls/error.h"
#include <stdio.h>
#include <string.h>

char * rsapkey_1024_pem_pkcs1 =  
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQDN/ZPFtPE4p4UP3pPZijbSRn7HqJ4BQ/J75fqDta/QEpIafzb+\n"
"pL0/pd5I+Ojo+mSvfvNrsXF4AD1bnNX3P7KEXWnawzIldrr7m8DWZ5N3noUHLenh\n"
"o2tmV+DEhdrhUJ6Kw8bXWPYAov7ldPk2fp51g/n1QGEBRV8HYMJrVsnQiQIDAf/B\n"
"AoGAARMjaX5oI/Aph9DrQMqLDFcJXYiv02lT8YjWg7Jq/hHxqtUabxGVuP6W/zGd\n"
"E5sdXz3uKuhd9ybjcDv4kv1cnBwRX6z2WnENXNHfVRFe4Xu+J4TPlMv61qS1ki+o\n"
"D2sMgZnhHJy4ZegkP9tpxwX+DctLMp/b1y184IyUgkqa5SECQQDouwbxBPMJWRd7\n"
"1syA6FOJqBmZOH6e4LY3kjn5eNV1Tx8DEgZLSR+X0g7aIWJKziA1VFcjD2bi6Ccd\n"
"f7Z12CTpAkEA4pYcqdjVapAPQyDrF1hv+GQOB/2dIKt/4uhN990Znat5mSe8Ejl5\n"
"NZteK6au03csHaaKduN+IaZhdnVk0S2KoQJBAONu5smiWpQXN/0Qbw9WEOvq8sXa\n"
"GHfXkdJSG+4edRM40XLn5yHLCbEe72NB0Vj+sKmECMnqPBvpHJ/kcwdbsrkCQFab\n"
"bHw2ySpyWX6y8wV27A0LaImncrmgjGFop2YaTu2EQ/+CcDUu81cNnRN2F5NdieOd\n"
"aYWulWPh2Ec71kyOlyECQFswa1Uj43H8TXVg6qGu4STbZkn+yTiAQHFtzQiTx0tY\n"
"K1id3QQj/GmNb6ogZbmLZK4h43aFwnJb3vI+oug13ic=\n"
"-----END RSA PRIVATE KEY-----\n\0";

char * rsapkey_1024_pem_pkcs8 =  
"-----BEGIN PRIVATE KEY-----\n"
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAM39k8W08TinhQ/e\n"
"k9mKNtJGfseongFD8nvl+oO1r9ASkhp/Nv6kvT+l3kj46Oj6ZK9+82uxcXgAPVuc\n"
"1fc/soRdadrDMiV2uvubwNZnk3eehQct6eGja2ZX4MSF2uFQnorDxtdY9gCi/uV0\n"
"+TZ+nnWD+fVAYQFFXwdgwmtWydCJAgMB/8ECgYABEyNpfmgj8CmH0OtAyosMVwld\n"
"iK/TaVPxiNaDsmr+EfGq1RpvEZW4/pb/MZ0Tmx1fPe4q6F33JuNwO/iS/VycHBFf\n"
"rPZacQ1c0d9VEV7he74nhM+Uy/rWpLWSL6gPawyBmeEcnLhl6CQ/22nHBf4Ny0sy\n"
"n9vXLXzgjJSCSprlIQJBAOi7BvEE8wlZF3vWzIDoU4moGZk4fp7gtjeSOfl41XVP\n"
"HwMSBktJH5fSDtohYkrOIDVUVyMPZuLoJx1/tnXYJOkCQQDilhyp2NVqkA9DIOsX\n"
"WG/4ZA4H/Z0gq3/i6E333Rmdq3mZJ7wSOXk1m14rpq7Tdywdpop2434hpmF2dWTR\n"
"LYqhAkEA427myaJalBc3/RBvD1YQ6+ryxdoYd9eR0lIb7h51EzjRcufnIcsJsR7v\n"
"Y0HRWP6wqYQIyeo8G+kcn+RzB1uyuQJAVptsfDbJKnJZfrLzBXbsDQtoiadyuaCM\n"
"YWinZhpO7YRD/4JwNS7zVw2dE3YXk12J451pha6VY+HYRzvWTI6XIQJAWzBrVSPj\n"
"cfxNdWDqoa7hJNtmSf7JOIBAcW3NCJPHS1grWJ3dBCP8aY1vqiBluYtkriHjdoXC\n"
"clve8j6i6DXeJw==\n"
"-----END PRIVATE KEY-----\n\0";

int main() {
    int ret;
    unsigned char *buf;
    size_t buflen; 
    mbedtls_pk_context pk;

    mbedtls_pk_init(&pk);

    buf = (unsigned char *)rsapkey_1024_pem_pkcs1;
    buflen = strlen(buf);

    ret = mbedtls_pk_parse_key(&pk, buf, buflen, NULL, 0);
    if (ret != 0) {
        printf("Failed to parse PKCS#1 private key :: %x\n", -ret);
        mbedtls_pk_free(&pk);
        return -1;
    }

    if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) != 0) {
        printf("This is a PKCS#1 private key\n");
    } else if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT) != 0) {
        printf("This is a PKCS#8 private key\n");
    } else {
        printf("Failed to determine private key format\n");
    }

    mbedtls_pk_free(&pk);

    mbedtls_pk_init(&pk);

    buf = (unsigned char *)rsapkey_1024_pem_pkcs8;
    buflen = strlen(buf);

    ret = mbedtls_pk_parse_key(&pk, buf, buflen, NULL, 0);
    if (ret != 0) {
        printf("Failed to parse PKCS#8 private key :: %x\n", -ret);
        mbedtls_pk_free(&pk);
        return -1;
    }

    if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) != 0) {
        printf("This is a PKCS#1 private key\n");
    } else if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT) != 0) {
        printf("This is a PKCS#8 private key\n");
    } else {
        printf("Failed to determine private key format\n");
    }

    mbedtls_pk_free(&pk);

    return 0;
}

System information

Mbed TLS version (number or commit id):
-> mbedtls version: 2.16.3

Operating system and version:
-> ubuntu 20.04

Configuration (if not default, please attach mbedtls_config.h):
Compiler and options (if you used a pre-built binary, please indicate how you obtained it):
Additional environment information:
-> I just downloaded the package from ubuntu as below.

sudo apt-get install libmbedtls-dev

Expected behavior

If I run the above test code, I hope the log will come out as below.
This is a PKCS#1 private key
This is a PKCS#8 private key

Actual behavior

mbedtls version: 2.16.3
Failed to parse PKCS#1 private key :: 3d00

Steps to reproduce

Just compile and run the test code above.

Additional information

The key data used the following site.
https://keytool.online/

@gilles-peskine-arm
Copy link
Contributor

    buflen = strlen(buf);

Please try with buflen = strlen(buf) + 1, since the documentation of mbedtls_pk_parse_key states

For PEM, the buffer must contain a null-terminated string.

Also, please note that Mbed TLS 2.16 has not been supported since December 2021. Please upgrade to Mbed TLS 2.28 LTS (which will be supported until December 2024) or the current releases (3.x).

@ljluestc
Copy link

int main() {
    int ret;
    unsigned char *buf;
    size_t buflen; 
    mbedtls_pk_context pk;
    mbedtls_pk_init(&pk);
    buf = (unsigned char *)rsapkey_1024_pem_pkcs1;
    buflen = sizeof(rsapkey_1024_pem_pkcs1) - 1; // Exclude the null terminator

    ret = mbedtls_pk_parse_key(&pk, buf, buflen, NULL, 0);
    if (ret != 0) {
        printf("Failed to parse PKCS#1 private key :: %x\n", -ret);
        mbedtls_pk_free(&pk);
        return -1;
    }

    if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) != 0) {
        printf("This is a PKCS#1 private key\n");
    } else if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT) != 0) {
        printf("This is a PKCS#8 private key\n");
    } else {
        printf("Failed to determine private key format\n");
    }

    mbedtls_pk_free(&pk);

    mbedtls_pk_init(&pk);

    buf = (unsigned char *)rsapkey_1024_pem_pkcs8;
    buflen = sizeof(rsapkey_1024_pem_pkcs8) - 1; // Exclude the null terminator

    ret = mbedtls_pk_parse_key(&pk, buf, buflen, NULL, 0);
    if (ret != 0) {
        printf("Failed to parse PKCS#8 private key :: %x\n", -ret);
        mbedtls_pk_free(&pk);
        return -1;
    }

    if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) != 0) {
        printf("This is a PKCS#1 private key\n");
    } else if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT) != 0) {
        printf("This is a PKCS#8 private key\n");
    } else {
        printf("Failed to determine private key format\n");
    }

    mbedtls_pk_free(&pk);

    return 0;
}

Try this please

@SangsubLim
Copy link
Author

@ljluestc
Thanks for your reply.
I tested after changing the size part in the code you provided as follows, but it is not in the form I want.
Here's what I've tested:

#include "mbedtls/pk.h"
#include "mbedtls/error.h"
#include "mbedtls/version.h"
#include <stdio.h>
#include <string.h>

char * rsapkey_1024_pem_pkcs1 =  
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQDN/ZPFtPE4p4UP3pPZijbSRn7HqJ4BQ/J75fqDta/QEpIafzb+\n"
"pL0/pd5I+Ojo+mSvfvNrsXF4AD1bnNX3P7KEXWnawzIldrr7m8DWZ5N3noUHLenh\n"
"o2tmV+DEhdrhUJ6Kw8bXWPYAov7ldPk2fp51g/n1QGEBRV8HYMJrVsnQiQIDAf/B\n"
"AoGAARMjaX5oI/Aph9DrQMqLDFcJXYiv02lT8YjWg7Jq/hHxqtUabxGVuP6W/zGd\n"
"E5sdXz3uKuhd9ybjcDv4kv1cnBwRX6z2WnENXNHfVRFe4Xu+J4TPlMv61qS1ki+o\n"
"D2sMgZnhHJy4ZegkP9tpxwX+DctLMp/b1y184IyUgkqa5SECQQDouwbxBPMJWRd7\n"
"1syA6FOJqBmZOH6e4LY3kjn5eNV1Tx8DEgZLSR+X0g7aIWJKziA1VFcjD2bi6Ccd\n"
"f7Z12CTpAkEA4pYcqdjVapAPQyDrF1hv+GQOB/2dIKt/4uhN990Znat5mSe8Ejl5\n"
"NZteK6au03csHaaKduN+IaZhdnVk0S2KoQJBAONu5smiWpQXN/0Qbw9WEOvq8sXa\n"
"GHfXkdJSG+4edRM40XLn5yHLCbEe72NB0Vj+sKmECMnqPBvpHJ/kcwdbsrkCQFab\n"
"bHw2ySpyWX6y8wV27A0LaImncrmgjGFop2YaTu2EQ/+CcDUu81cNnRN2F5NdieOd\n"
"aYWulWPh2Ec71kyOlyECQFswa1Uj43H8TXVg6qGu4STbZkn+yTiAQHFtzQiTx0tY\n"
"K1id3QQj/GmNb6ogZbmLZK4h43aFwnJb3vI+oug13ic=\n"
"-----END RSA PRIVATE KEY-----\n\0";

char * rsapkey_1024_pem_pkcs8 =  
"-----BEGIN PRIVATE KEY-----\n"
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAM39k8W08TinhQ/e\n"
"k9mKNtJGfseongFD8nvl+oO1r9ASkhp/Nv6kvT+l3kj46Oj6ZK9+82uxcXgAPVuc\n"
"1fc/soRdadrDMiV2uvubwNZnk3eehQct6eGja2ZX4MSF2uFQnorDxtdY9gCi/uV0\n"
"+TZ+nnWD+fVAYQFFXwdgwmtWydCJAgMB/8ECgYABEyNpfmgj8CmH0OtAyosMVwld\n"
"iK/TaVPxiNaDsmr+EfGq1RpvEZW4/pb/MZ0Tmx1fPe4q6F33JuNwO/iS/VycHBFf\n"
"rPZacQ1c0d9VEV7he74nhM+Uy/rWpLWSL6gPawyBmeEcnLhl6CQ/22nHBf4Ny0sy\n"
"n9vXLXzgjJSCSprlIQJBAOi7BvEE8wlZF3vWzIDoU4moGZk4fp7gtjeSOfl41XVP\n"
"HwMSBktJH5fSDtohYkrOIDVUVyMPZuLoJx1/tnXYJOkCQQDilhyp2NVqkA9DIOsX\n"
"WG/4ZA4H/Z0gq3/i6E333Rmdq3mZJ7wSOXk1m14rpq7Tdywdpop2434hpmF2dWTR\n"
"LYqhAkEA427myaJalBc3/RBvD1YQ6+ryxdoYd9eR0lIb7h51EzjRcufnIcsJsR7v\n"
"Y0HRWP6wqYQIyeo8G+kcn+RzB1uyuQJAVptsfDbJKnJZfrLzBXbsDQtoiadyuaCM\n"
"YWinZhpO7YRD/4JwNS7zVw2dE3YXk12J451pha6VY+HYRzvWTI6XIQJAWzBrVSPj\n"
"cfxNdWDqoa7hJNtmSf7JOIBAcW3NCJPHS1grWJ3dBCP8aY1vqiBluYtkriHjdoXC\n"
"clve8j6i6DXeJw==\n"
"-----END PRIVATE KEY-----\n\0";

int main() {
    int ret;
    unsigned int ver;
    unsigned char *buf;
    size_t buflen; 
    char version[32] = {0x00,};
    
		mbedtls_version_get_string(&version);
		printf("version : %s\n", version);
		
    mbedtls_pk_context pk;
    mbedtls_pk_init(&pk);
    buf = (unsigned char *)rsapkey_1024_pem_pkcs1;
//    buflen = sizeof(rsapkey_1024_pem_pkcs1) - 1; // Exclude the null terminator
    buflen = strlen(rsapkey_1024_pem_pkcs1) + 1; // include the null terminator

    ret = mbedtls_pk_parse_key(&pk, buf, buflen, NULL, 0);
    if (ret != 0) {
        printf("Failed to parse PKCS#1 private key :: %x\n", -ret);
        mbedtls_pk_free(&pk);
        return -1;
    }

    if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) != 0) {
        printf("[%s/%d] This is a PKCS#1 private key\n", __FUNCTION__, __LINE__);
    } else if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT) != 0) {
        printf("[%s/%d] This is a PKCS#8 private key\n", __FUNCTION__, __LINE__);
    } else {
        printf("Failed to determine private key format\n");
    }

    mbedtls_pk_free(&pk);

    mbedtls_pk_init(&pk);

    buf = (unsigned char *)rsapkey_1024_pem_pkcs8;
    buflen = strlen(rsapkey_1024_pem_pkcs8) + 1; // include the null terminator
//    buflen = sizeof(rsapkey_1024_pem_pkcs8) - 1; // Exclude the null terminator

    ret = mbedtls_pk_parse_key(&pk, buf, buflen, NULL, 0);
    if (ret != 0) {
        printf("Failed to parse PKCS#8 private key :: %x\n", -ret);
        mbedtls_pk_free(&pk);
        return -1;
    }

    if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA) != 0) {
        printf("[%s/%d] This is a PKCS#1 private key\n", __FUNCTION__, __LINE__);
    } else if (mbedtls_pk_can_do(&pk, MBEDTLS_PK_RSA_ALT) != 0) {
        printf("[%s/%d] This is a PKCS#8 private key\n", __FUNCTION__, __LINE__);
    } else {
        printf("Failed to determine private key format\n");
    }

    mbedtls_pk_free(&pk);

    return 0;
}

Actual behavior

version : 2.16.3
[main/66] This is a PKCS#1 private key
[main/89] This is a PKCS#1 private key

I want the second data to be a PKCS#8 private key, but it's not working.
In fact, I'm doing this through OPTEE, and it's the same. For reference, the version of mbedTLS in OPTEE that I am currently using is 2.27.

Does the code you gave me work only with mbedTLS 3.x?
Is there no way to know whether it is PKCS#8 or #1 in mbedTLS 2.x?

BR,

@gilles-peskine-arm
Copy link
Contributor

I want the second data to be a PKCS#8 private key, but it's not working.

PKCS#1 vs PKCS#8 are representation formats. Once the key is parsed, it's an RSA key, regardless of what its format was before parsing. mbedtls_pk_parse_key does not report which format it found (PEM vs DER, PKCS1/SEC vs PKCS8). Why do you need that information?

MBEDTLS_PK_RSA_ALT means that the key is managed by the (deprecated) RSA-ALT alternative implementation instead of the normal mbedtls or psa implementation of RSA operations. Key parsing never constructs a key of that type. RSA-ALT is mostly intended to use an RSA key which already exists in a secure element. The modern replacement is the PSA interface, which allows this for keys of any type.

@SangsubLim
Copy link
Author

@gilles-peskine-arm

I just want to check if the data I input is in PKCS#8 format.
I know that DER, PEM, PKCS#1, #8 are all processed through mbedtls_pk_parse_key.
As a result of some searches, it seems that mbedTLS can be confirmed with the above code, so I asked if it really works.

I wonder if the above code works normally in version 2.28 or higher, or if it is only supported in 3.x.
Finally, is the PSA you mentioned referring to the Platform Security Architecture?
BR,

@gilles-peskine-arm
Copy link
Contributor

I just want to check if the data I input is in PKCS#8 format.

Mbed TLS doesn't have an API for that. If you really need this information, you can do some of the parsing manually:

  • First call mbedtls_pk_parse_key to check that it's a valid private key.
  • If the input is PEM, use the PEM module to decode it. The PEM header tells you whether the content is PKCS1 (-----BEGIN RSA PRIVATE KEY-----) or PKCS8 (-----BEGIN PRIVATE KEY-----) or SEC1 (----- BEGIN EC PRIVATE KEY-----). Note that you can tell between PEM and DER by the first character (- in PEM, 0x30 in DER).
  • With unencrypted DER input, use the ASN.1 module to inspect the contents. All the formats have a SEQUENCE as the outer tag. Both PKCS1 and PKCS8 have an INTEGER with the value 0 as the first element of the sequence. The second element is different: in PKCS1 it's an INTEGER, in PKCS8 it's a SEQUENCE. In SEC1, the first elent of the sequence is also an INTEGER but its value is 1.
  • PKCS1 doesn't specify encryption, so if you have an encrypted RSA key, it has to be in PKCS8 format.

wonder if the above code works normally in version 2.28 or higher, or if it is only supported in 3.x.

I can't think of a relevant difference between 2.28 and 3.x here.

Finally, is the PSA you mentioned referring to the Platform Security Architecture?

Yes.

@gilles-peskine-arm
Copy link
Contributor

I'm closing this issue because the reported code is working as documented.

@gilles-peskine-arm gilles-peskine-arm closed this as not planned Won't fix, can't repro, duplicate, stale Jun 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants