Skip to content

Fix pk_parse_key() validation of RSA private keys #363

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
wants to merge 4 commits into from
Closed

Fix pk_parse_key() validation of RSA private keys #363

wants to merge 4 commits into from

Conversation

mpg
Copy link
Contributor

@mpg mpg commented Feb 7, 2020

We recently added a check of the return value of mbedtls_rsa_export after mbedtls_pk_parse_key in fuzz_privkey (Mbed-TLS/mbedtls#2999) and oss-fuzz found an issue (restricted link: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20467).

This PR fixes the issue by making sure that pk_parse_key() rejects keys that are obviously not valid private keys, as its documentation promises (and as rsa_export() does).

Status: WIP

Todo

  • Add a non-regression test for pk_parse_key()
  • We accept keys with d == 0 and silently fix the value to d = p * q, I don't think we should
  • Fix issue with error code wrapping
  • Write a ChangeLog entry here.

Backports

  • mbedtls-2.16
  • mbedtls-2.7

This will be used in pkparse to make sure that when parsing a private key,
what we're getting will actually looks like a private key to the rest of the
code. Currently pk_parse_key() accepts keys that rsa_export() does not
recognize as private.
@mpg mpg added bug Something isn't working needs: work The pull request needs rework before it can be merged. needs: ci Needs a passing full CI run needs: backports Needs backports to Mbed TLS branches labels Feb 7, 2020
mpg added 3 commits February 10, 2020 10:01
- remove incorrect compile-time dependency (the individual cases already have
  correct run-time dependency information)
- remove unused argument
- remove unused stack buffer
- remove useless code block
(Only the top-level ones, ie, for each call to eg asn1_get_mpi(), ensure
there's at least one test case that makes this call fail in one way, but don't
test the various ways to make asn1_get_mpi fail - that should be covered
elsewhere.)

- the new checks added by the previous commit needed exercising
- existing tests sometimes had wrong descriptions or where passing for the
  wrong reason (eg with the "length mismatch" test, the function actually
failed before reaching the length check)
- while at it, add tests for the rest as well

The valid minimal-size key was generated with:

openssl genrsa 128 2>/dev/null | openssl rsa -outform der 2>/dev/null | xxd -p
int mbedtls_rsa_is_private( const mbedtls_rsa_context *ctx )
{
return(
mbedtls_mpi_cmp_int( &ctx->N, 0 ) != 0 &&
Copy link
Collaborator

Choose a reason for hiding this comment

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

This function returns 0 on an incomplete key. I find this behavior surprising. I'd prefer mbedtls_rsa_is_private(rsa) to return the same thing before and after mbedtls_rsa_complete(rsa). If it doesn't, this should be documented clearly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I agree this should be documented. I'm likely to rework the PR in a way that no longer relies on this function, but I'll make sure to properly document that aspect of the new function.

mbedtls_mpi_cmp_int( &ctx->P, 0 ) != 0 &&
mbedtls_mpi_cmp_int( &ctx->Q, 0 ) != 0 &&
mbedtls_mpi_cmp_int( &ctx->D, 0 ) != 0 &&
mbedtls_mpi_cmp_int( &ctx->E, 0 ) != 0 );
Copy link
Contributor

Choose a reason for hiding this comment

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

Two comments - first this seems to accept values which are negative, values which could be deserialized from the DER structure. Also it seems to ignore the CRT params, which should probably also be checked, if CRT is enabled at least.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for your feedback! Actually I think the checks in rsa_check_context() (called from mbedtls_rsa_complete() called from mbedtls_pk_parse_key()) already prevent that, but I agree that it should be more obvious. I was intending to rework the PR anyway, as I'm no longer convinced mbedtls_rsa_is_private() is the right function here, so I'll keep that in mind when reworking.

@mpg
Copy link
Contributor Author

mpg commented Feb 14, 2020

@gilles-peskine-arm @jack-fortanix I decided to switch to a new approach and I though it would be cleaner to open a new PR for that, so this PR is now superseded by: #367

@mpg mpg added the DO NOT MERGE The PR is not intended to be merged (yet). Usually used for a review of worked in progress. label Feb 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working DO NOT MERGE The PR is not intended to be merged (yet). Usually used for a review of worked in progress. needs: backports Needs backports to Mbed TLS branches needs: ci Needs a passing full CI run needs: work The pull request needs rework before it can be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants