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

verify_cert: bound name constraint comparisons. #165

Merged
merged 8 commits into from Sep 7, 2023

Conversation

cpu
Copy link
Member

@cpu cpu commented Sep 5, 2023

Enforcing name constraints during path building is quadratic with the number of names, and the number of name constraints. To avoid the possibility of excessive CPU consumption enforcing name constraints TLS libraries typically enforce a maximum number of comparisons while evaluating a constrained certificate against subsequent certificate names. Note that unlike #152 the possible runtime of crafted certificate chains within the limits imposed by Rustls/webpki prior to this commit is O(seconds) and not O(hours+), making this a less grave concern generally.

In this branch we move name constraint validation to after the path signatures have been successfully validated, limiting the exposure of name constraint processing to certificates that chain to a known trust anchor. We also adopt a limit for name constraint comparisons inspired by the default limit used by Go's x509 package. However, unlike Go we bound total comparisons for verifying a validated path meets name constraints to 250,000 comparisons overall, not per-certificate in the built path. Since we're applying this check only on a path that has been validated successfully from end entity to trust anchor, with a depth of at most 6 issuers, it seems like a reasonable limit.

Along the way (I recommend reviewing commit-by-commit) I performed a little bit of tidying.

As mentioned in the final commit it is possible to interleave the name constraint validation and the signature validation, but it will require a more complex algorithm and, to be honest, I've had trouble wrapping my head around the logic as-is (there's a lot of recursion, parsing, and iteration involved). This is a pretty complicated intersection of critical features and I think we should tread carefully and start simple.

@codecov
Copy link

codecov bot commented Sep 5, 2023

Codecov Report

Merging #165 (a90f075) into main (7e38e97) will increase coverage by 0.07%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##             main     #165      +/-   ##
==========================================
+ Coverage   96.61%   96.69%   +0.07%     
==========================================
  Files          15       15              
  Lines        4463     4570     +107     
==========================================
+ Hits         4312     4419     +107     
  Misses        151      151              
Files Changed Coverage Δ
src/error.rs 55.76% <100.00%> (+0.86%) ⬆️
src/subject_name/verify.rs 96.33% <100.00%> (+0.13%) ⬆️
src/verify_cert.rs 98.13% <100.00%> (+0.29%) ⬆️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@cpu cpu force-pushed the cpu-bound-name-constraint-checks branch from 80e080e to 47e2de1 Compare September 5, 2023 20:26
@cpu cpu marked this pull request as ready for review September 5, 2023 20:28
src/verify_cert.rs Outdated Show resolved Hide resolved
src/verify_cert.rs Outdated Show resolved Hide resolved
src/verify_cert.rs Outdated Show resolved Hide resolved
src/verify_cert.rs Show resolved Hide resolved
src/verify_cert.rs Show resolved Hide resolved
@cpu cpu force-pushed the cpu-bound-name-constraint-checks branch from 47e2de1 to 131c680 Compare September 6, 2023 14:34
@cpu cpu force-pushed the cpu-bound-name-constraint-checks branch from 131c680 to 870b7fa Compare September 6, 2023 14:41
src/verify_cert.rs Show resolved Hide resolved
This commit updates the name constraint validation done during path
building to apply a budget for the maximum allowed number of name
constraint checks.

We use the same limit that golang crypto/x509 applies by default:
250,000 comparisons.

Note: this commit applies the budget during path building in a manner
that means certificates _not_ part of the built path can consume
comparisons from the budget even though they will not be present in the
complete validated path. Similarly name constraints are evaluated before
signatures, meaning a certificate that doesn't verify to a trusted root
still has its constraints parsed and evaluated. A subsequent commit
will adjust these shortcomings.
This commit updates the path building process such that name constraints
are only evaluated against a complete path where signatures on the chain
have been checked successfully to a trust anchor. This avoids:

* Parsing name constraints before signatures are validated.
* Evaluating name constraints and consuming name constraint comparison
  budget for certificates that are not part of the
  built path.

In the future it could be possible to interleave the name constraint
checking with the signature checking, however the logic for this is more
complicated. For an initial fix let's prefer a simpler solution that
walks the built + validated path to check name constraints from the
trust anchor to the end entity certificate.
@cpu cpu force-pushed the cpu-bound-name-constraint-checks branch from 870b7fa to a90f075 Compare September 6, 2023 15:09
@cpu cpu added this pull request to the merge queue Sep 7, 2023
Merged via the queue into rustls:main with commit 932ad95 Sep 7, 2023
24 checks passed
@cpu cpu deleted the cpu-bound-name-constraint-checks branch September 7, 2023 13:34
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

Successfully merging this pull request may close these issues.

None yet

3 participants