Skip to content

EC keys written with as DER could be incorrectly formatted #268

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

Closed

Conversation

joelpalsson74
Copy link

When writing EC keys using mbedtls_pk_write_key_der() the private
part of the key got incorrectly pre-pended with 0 if MSB of the
key was 1.

See issue:
Mbed-TLS/mbedtls#1028

When writing EC keys using mbedtls_pk_write_key_der() the private
part of the key got incorrectly pre-pended with 0 if MSB of the
key was 1.
Copy link
Collaborator

@gilles-peskine-arm gilles-peskine-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! Unfortunately, this is still not correct. RFC 5915 states

privateKey is the private key. It is an octet string of length ceiling (log2(n)/8) (where n is the order of the curve)

The length of the octet string only depends on the curve, not on the numerical value of the private key. But your implementation writes the number with no leading zeros, so it fixes the cases where the most significant bit is 1 but not the cases where the most significant octet is 0.

For a proper fix, mbedtls_asn1_write_mpi_to_octet_string would need to take the size of the octet string as an argument.

Also we need unit tests for the ASN.1 module these days.

@gilles-peskine-arm gilles-peskine-arm added bug Something isn't working needs: work The pull request needs rework before it can be merged. open for community contribution labels Oct 29, 2019
According to RFC 3447 (chapter 4.1, I2OSP) MPIs shall be prepended with
zero data to its full size when written as an octet string.
@joelpalsson74
Copy link
Author

Gilles, thanks for you comments.
Unfortunately I got no idea how to make the unit tests.

/Joel

@joelpalsson74
Copy link
Author

Gilles,
It seems as one of the unit test fails:
Failed test suite: MBEDTLS_ECP_DP_SECP192R1_ENABLED

I don't understand how to check if the test is correct or not.
Can you please help out?

Best regards,
Joel

@@ -106,6 +106,26 @@ int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
*/
int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start,
const mbedtls_mpi *X );

/**
* \brief Write a arbitrary-precision number as an
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Write a arbitrary-precision number” + “in binary in big-endian order”

* \param start The start of the buffer, for bounds-checking.
* \param X The MPI to write.
* \param len The intended number of octets of the resulting string.
* If the MPI results in less octets, leading zeros is
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“leading zeros is” → “leading zeros are”

Comment on lines +181 to +191
if( mpi_size > len )
return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );

(*p) -= mpi_size;
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, mpi_size ) );

for( i = 0; i < (int)(len - mpi_size); i++ )
{
(*p)--;
**p = 0;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need the check on mpi_size and the padding. Just

*p -= len;
MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len) );

MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) );
*c = MBEDTLS_ASN1_OCTET_STRING;
/* privateKey */
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi_to_octet_string( &c, buf, &ec->d, ec->d.n * 4 ) );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ec->d.n * 4 is (almost) never correct on 64-bit machines and not always correct on 32-bit machines. That's the size of the buffer in memory and it may have leading zeros or have fewer limbs if the number has leading enough zero bits (about 0.05% of P521 keys are like that).

The correct size is the nominal key size. That's the value of the nbits field in the group structure, converted to bytes: ( ec->grp->nbits + 7 ) / 8

@gilles-peskine-arm
Copy link
Collaborator

So… this is embarrassing… it turns out that we had already fixed that bug, but the fix slipped through the net. It was applied to the long-time support branches, but it was never released in the development branch of Mbed TLS. We missed this and one other bug fix when we split the crypto code between Mbed TLS and Mbed Crypto.

In the interest of simplifying our maintenance, we're going to apply the same patch to Mbed Crypto that we made to the Mbed TLS LTS branches: #314 . It fixes Mbed-TLS/mbedtls#1028, but does not add mbedtls_asn1_write_mpi_to_octet_string.

Do you have a need for mbedtls_asn1_write_mpi_to_octet_string beyond fixing pkwrite on EC keys? If so, please rebase this pull request on top of the new code after #314 is merged. If not, I think this pull request can be closed.

Please accept our apologies for the inconvenience.

@joelpalsson74
Copy link
Author

Gilles,
Thanks for the information.
We have no other use case for mbedtls_asn1_write_mpi_to_octet_string(), so this pull request can be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working needs: work The pull request needs rework before it can be merged. open for community contribution
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants