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

mbedtls_x509_crt_parse_der fails to parse public key in DER format X509 certificate #4772

Closed
jorking opened this issue Jul 13, 2021 · 2 comments

Comments

@jorking
Copy link

jorking commented Jul 13, 2021

Summary

I generated a DER format X509 certificate by OPENSSL, however, when I pass the hex string to mbedtls_x509_crt_parse_der(), it results in MBEDTLS_ERR_ASN1_INVALID_DATA error in function mbedtls_asn1_get_bitstring_null().

The hex string of the test X509 certificate is (DER) :
308201e73082018da00302010202143b3a90a1abef554f62916fd10413b4b20950a59a300a06082a8648ce3d0403023041310b300906035504061302434e310e300c06035504080c054368696e61310e300c060355040a0c057a686968753112301006035504030c09526f6f745f53746172301e170d3231303731323130343130385a170d3431303730373130343130385a3041310b300906035504061302434e310e300c06035504080c054368696e61310e300c060355040a0c057a686968753112301006035504030c09526f6f745f537461723059301306072a8648ce3d020106082a8648ce3d03010703422004b785d341c20af9cef8a91124e5565dabab57cd38143e676680a720e0e20f9a9daee11cc5211ddfb0defd5c63eca6b1f3f8ba327af76a8b650870769c745fa6c6a3633061301d0603551d0e041604148a6a45c0942afa1d6c9160c4ed77187869f44265301f0603551d230418301680148a6a45c0942afa1d6c9160c4ed77187869f44265300f0603551d130101ff040530030101ff300e0603551d0f0101ff040403020186300a06082a8648ce3d040302034820304502204a3805ca0bfe9ce78082edb68ae370b0db38a86514787d5f8bc805e84cf8c56d022120cdde2e283db9b4b608c7db273c97ba812091dd3b8655dc55729e3af187350ef5

The error occurs when parsing the public key field. After 03 42, it expects 0004, while the actual value is 2004.

    30 59
      30 13
        06 07 2A8648CE3D0201
        06 08 2A8648CE3D030107
        03 42 2004B785D341C20AF9CEF8A91124E5565DABAB57CD38143E676680A720E0E20F...

The error line is as bellows:

int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end,
                             size_t *len )
{
    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;

    if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 )
        return( ret );

    if( *len == 0 )
        return( MBEDTLS_ERR_ASN1_INVALID_DATA );
    --( *len );

    if( **p != 0 )    // it fails here, actual value is 0x20 instead of 0x00
        return( MBEDTLS_ERR_ASN1_INVALID_DATA );
    ++( *p );

    return( 0 );
}

I did some search and found the link below:
https://docs.microsoft.com/en-us/windows/win32/seccertenroll/about-bit-string
It says:

The BIT STRING data type is encoded into a TLV triplet that begins with a Tag byte of 0x03. The Value field of the TLV triplet contains a leading byte that specifies the number of bits left unused in the final byte of content.

I don't know if it's bug or the format of certificate is incorrect. Thanks if anyone could help!

System information

Mbed TLS version (number or commit id):
2.26.0
Operating system and version:
windows 10

Compiler and options (if you used a pre-built binary, please indicate how you obtained it):
VS 2019
Additional environment information:

Expected behavior

mbedtls_x509_crt_parse_der correctly parses the DER format certificate and generate a correct mbedtls_x509_crt structure.

Actual behavior

mbedtls_x509_crt_parse_der returns results in MBEDTLS_ERR_ASN1_INVALID_DATA error in function mbedtls_asn1_get_bitstring_null() when parsing public key field.

Steps to reproduce

Additional information

OpenSSL command line tool is able to parse the DER certificate as bellows:

Certificate:
  Data:
       Version: 3 (0x2)
       Serial Number:
           3b:3a:90:a1:ab:ef:55:4f:62:91:6f:d1:04:13:b4:b2:09:50:a5:9a
       Signature Algorithm: ecdsa-with-SHA256
       Issuer: C = CN, ST = China, O = zhihu, CN = Root_Star
       Validity
           Not Before: Jul 12 10:41:08 2021 GMT
           Not After : Jul  7 10:41:08 2041 GMT
       Subject: C = CN, ST = China, O = zhihu, CN = Root_Star
       Subject Public Key Info:
           Public Key Algorithm: id-ecPublicKey
               Public-Key: (256 bit)
               pub:
                   04:b7:85:d3:41:c2:0a:f9:ce:f8:a9:11:24:e5:56:
                   5d:ab:ab:57:cd:38:14:3e:67:66:80:a7:20:e0:e2:
                   0f:9a:9d:ae:e1:1c:c5:21:1d:df:b0:de:fd:5c:63:
                   ec:a6:b1:f3:f8:ba:32:7a:f7:6a:8b:65:08:70:76:
                   9c:74:5f:a6:c6
               ASN1 OID: prime256v1
               NIST CURVE: P-256
       X509v3 extensions:
           X509v3 Subject Key Identifier:
               8A:6A:45:C0:94:2A:FA:1D:6C:91:60:C4:ED:77:18:78:69:F4:42:65
           X509v3 Authority Key Identifier:
               keyid:8A:6A:45:C0:94:2A:FA:1D:6C:91:60:C4:ED:77:18:78:69:F4:42:65

           X509v3 Basic Constraints: critical
               CA:TRUE
           X509v3 Key Usage: critical
               Digital Signature, Certificate Sign, CRL Sign
   Signature Algorithm: ecdsa-with-SHA256
        30:45:02:20:4a:38:05:ca:0b:fe:9c:e7:80:82:ed:b6:8a:e3:
        70:b0:db:38:a8:65:14:78:7d:5f:8b:c8:05:e8:4c:f8:c5:6d:
        02:21:00:cd:de:2e:28:3d:b9:b4:b6:08:c7:db:27:3c:97:ba:
        81:00:91:dd:3b:86:55:dc:55:72:9e:3a:f1:87:35:0e:f5
@gilles-peskine-arm
Copy link
Contributor

I think the data is genuinely invalid. In a BIT STRING, the first value after the 0x03 type and the length byte(s) (here 0x42) is the number of unused bits in the last byte. This can only range from 0 to 7.

Mbed TLS only supports bit strings containing a whole number of bytes, so it would complain about any bit string where the number of unused bits is nonzero. However, here, the bit string is invalid, not just not-supported-here.

In any case, what is expected at this position in the certificate is an EC public key, and those are always encoded in a whole number of bytes. The content would be a plausible secp256r1 public key if the number of unused bits was 0.

OpenSSL can't even read back this value (I tried with OpenSSL 1.1.1f).

$ openssl x509 -text -inform DER -in a.crt 
unable to load certificate
140142747309376:error:0D0BD0DC:asn1 encoding routines:c2i_ASN1_BIT_STRING:invalid bit string bits left:../crypto/asn1/a_bitstr.c:137:
140142747309376:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:646:Field=public_key, Type=X509_PUBKEY
140142747309376:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:646:Field=key, Type=X509_CINF
140142747309376:error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error:../crypto/asn1/tasn_dec.c:646:Field=cert_info, Type=X509

If I edit the file and change this 0x20 to 0x00, and same in another bit-string at the end of the file containing the signature (also a whole number of bytes), OpenSSL is happy with it.

I conclude that either the version of OpenSSL that generated the certificate was buggy, or the data got corrupted somewhere.

@gilles-peskine-arm
Copy link
Contributor

I am closing this issue since it is not a bug: the data is invalid and was correctly rejected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants