Skip to content

Introduce ASN.1 SEQUENCE traversal API #263

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

Merged

Conversation

hanno-becker
Copy link

Summary: This PR is a spin-out from the X.509 on demand parsing work Mbed-TLS/mbedtls#2478, one of the main drivers of which is to avoid dynamically allocated presentations of ASN.1 SEQUENCEs by traversing the raw ASN.1 in-place whenever needed. To this end, this PR introduces the ASN.1 API mbedtls_asn1_traverse_sequence_of() which can be used to traverse an ASN.1 SEQUENCE container, triggering a user-specified callback for each entry found.
The PR also introduces two helper macros MBEDTLS_ASN1_IS_STRING_TAG and MBEDTLS_OID_CMP_RAW. Those are technically unrelated to the SEQUENCE traversal API and are included here solely to keep the number of dependencies for the on demand parsing PR low.

@hanno-becker hanno-becker added the needs: review The pull request is ready for review. This generally means that it has no known issues. label Sep 17, 2019
@gilles-peskine-arm
Copy link
Collaborator

#75 fixes some edge cases in the ASN.1 library and adds tests. Can you please make sure that your X.509 code and tests are compatible with these fixes? This PR doesn't have tests; I'm willing to accept it without tests but the lack of tests needs to be filed as a separate bug.

@hanno-becker
Copy link
Author

hanno-becker commented Sep 18, 2019

@gilles-peskine-arm It's not fully satisfactory, but because the PR reimplements mbedtls_asn1_get_sequence_of() in terms of the new traversal API, any tests for the former will also test the latter.
But of course, it'd be better to have standalone tests, too.

* call a callback for each entry.
*
* \warning This function is still experimental and may change
* at any time.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why should this be experimental? When can it be non-experimental? Could we make asn1_internal.h and place it there if it's only for internal use for now?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It isn't internal since it will be used by Mbed TLS.

Copy link
Author

Choose a reason for hiding this comment

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

@gilles-peskine-arm @Patater What's your view on this? This function must be public, as @gilles-peskine-arm said, so what remains is to decide whether we want to declare it as experimental or not. I'm open either way. If you think the API is good as-is, I'm happy to remove the qualification.

Copy link
Collaborator

Choose a reason for hiding this comment

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

My preference is what you wrote: declare this function as experimental. We don't care about this function except as an internal detail of the implementation an X509 feature that we do care about. It has a complex API that I would prefer not to make official, but that I'm ok to include with the understanding that we're likely to modify it in the future.

Copy link
Contributor

@mpg mpg Feb 3, 2020

Choose a reason for hiding this comment

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

The situation should be temporary, since I think we're aiming at making the whole asn1.h private in Mbed TLS 3.0 (or some point in the future at least) anyway.

* \p cb in case the latter returns a non-zero value.
*/
int mbedtls_asn1_traverse_sequence_of(
unsigned char **p,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can the unsigned char be const unsigned char? I don't think we'd be modifying **p, only p or *p.

Copy link
Collaborator

Choose a reason for hiding this comment

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

const unsigned char ** and unsigned char ** do not mix. If this function used a different type, it couldn't be used with the other asn1 parsing functions.

Copy link
Author

Choose a reason for hiding this comment

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

I agree with @Patater in that in principle the type of p should be const unsigned char ** here. However, the rest of the ASN.1 parsing library unfortunately also uses unsigned char **, which we can't change and which forces the use of unsigned char ** here, too (not just for consistency, but simply because this function calls e.g. mbedtls_asn1_get_tag() which has a unsigned char ** argument). An alternative would be to extend the documentation of all ASN.1 parsing functions to explicitly mention that, despite the missing const qualification, the **p is never written to, and that it is hence safe to use the functions in a const unsigned char ** context. If we did that, we could start improving the API by using const unsigned char ** at least for this new API function, and doing a const-cast when calling the other parsing functions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We can tweak the API in Mbed TLS 3. Until we get there, let's keep the API consistent.

Copy link
Author

Choose a reason for hiding this comment

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

Ok, no change here, then.

uint8_t tag_must_mask, uint8_t tag_must_val,
uint8_t tag_may_mask, uint8_t tag_may_val,
int (*cb)( void *ctx, int tag,
unsigned char* start, size_t len ),
Copy link
Contributor

Choose a reason for hiding this comment

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

Can start be made const?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm wondering about that. In 99% of the cases it would be const: parsing a read-only string. But it may be useful occasionally to modify an input in place.

Copy link
Author

Choose a reason for hiding this comment

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

I agree that it should be const. However, if we want to call other ASN.1 parsing functions from within the callback, then we can't have const here because those parsing functions don't have const qualification, as mentioned above.

/*
* Parses and splits an ASN.1 "SEQUENCE OF <tag>"
*/
int mbedtls_asn1_get_sequence_of( unsigned char **p,
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, too bad this is not const. I guess we can't have our callback with p const because of this.

Copy link
Author

Choose a reason for hiding this comment

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

This way it would work, but what doesn't work is calling parsing functions from within mbedtls_asn1_traverse_sequence_of().

@Patater Patater added the needs: work The pull request needs rework before it can be merged. label Sep 19, 2019
@gilles-peskine-arm gilles-peskine-arm self-assigned this Oct 30, 2019
@gilles-peskine-arm
Copy link
Collaborator

I rebased this pull request on top of the current base branch. The previous content by Hanno is at https://github.com/gilles-peskine-arm/mbed-crypto/tree/asn1_traversal_api-1.

Compared with the previous content:

  • I removed most updates to existing documentation because they were largely superseded by ASN.1 tests without x509 #75.
  • I added tests for the new functions.
  • I tweaked the documentation of the new functions.

@gilles-peskine-arm gilles-peskine-arm removed the needs: work The pull request needs rework before it can be merged. label Oct 30, 2019
@gilles-peskine-arm gilles-peskine-arm added the needs: ci Needs a passing full CI run label Nov 12, 2019
@gilles-peskine-arm
Copy link
Collaborator

gilles-peskine-arm commented Nov 12, 2019

New CI run now that the problems with the Cypress boards are fixed: https://jenkins-internal.mbed.com/job/mbed-crypto-pr/job/PR-263-merge/20/ → PASS

@gilles-peskine-arm gilles-peskine-arm added enhancement New feature or request and removed needs: ci Needs a passing full CI run labels Nov 12, 2019
@hanno-becker
Copy link
Author

hanno-becker commented Jan 31, 2020

Rebased on top of development. The only conflict stemmed from @yanesca's introduction of default error codes and was easy to fix.

@mpg
Copy link
Contributor

mpg commented Feb 3, 2020

The CI found a problem, in test-ref-configs, with config-symmetric-only.h, the first error is:

/var/lib/build/include/mbedtls/asn1.h:504:5: error: unknown type name 'uint8_t'
     uint8_t tag_must_mask, uint8_t tag_must_val,
     ^

and the other errors look similar. I suggest including stdint.h directly in asn1.h - it probably happens to be included indirectly in some configurations including the default one, but apparently not all of them.

@hanno-becker
Copy link
Author

Thank you @mpg, I'll fix that.

The rest of the ASN.1 API uses `unsigned char`, too.
@hanno-becker
Copy link
Author

@mpg @gilles-peskine-arm Fixed the issue by replacing uint8_t by unsigned char.

Copy link
Contributor

@mpg mpg left a comment

Choose a reason for hiding this comment

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

LGTM

@gilles-peskine-arm
Copy link
Collaborator

CI passes except for the Mbed OS tests which are failing for unrelated reasons.

@gilles-peskine-arm gilles-peskine-arm added ready for merge Design and code approved, CI passed, and likewise for backports. Label added by gatekeepers only. and removed needs: review The pull request is ready for review. This generally means that it has no known issues. labels Feb 3, 2020
@gilles-peskine-arm gilles-peskine-arm merged commit c69c2c5 into ARMmbed:development Feb 3, 2020
gilles-peskine-arm added a commit to gilles-peskine-arm/mbed-crypto that referenced this pull request Mar 23, 2020
* ARMmbed#352: Parse RSA parameters DP, DQ and QP from PKCS1 private keys
* ARMmbed#263: Introduce ASN.1 SEQUENCE traversal API
* ARMmbed#345: Fix possible error code mangling in psa_mac_verify_finish
* ARMmbed#357: Update Mbed Crypto with latest Mbed TLS changes as of 2020-02-03
* ARMmbed#350: test_suite_asn1parse: improve testing of trailing garbage in parse_prefixes
* ARMmbed#346: Improve robustness and testing of mbedtls_mpi_copy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request ready for merge Design and code approved, CI passed, and likewise for backports. Label added by gatekeepers only.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants