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: correct handling of fatal errors. #168

Merged
merged 5 commits into from Sep 8, 2023

Conversation

cpu
Copy link
Member

@cpu cpu commented Sep 7, 2023

Description

This change fell out of an observation I made while back-porting the budget fixes in main to the rel-0.100 release branch. In that branch the error handling for path building is simpler. Notably we don't carry forward a Error result from the first loop_while_non_fatal_error into the second, later ranking encountered errors to determine which to return.

In the rel-0.100 branch there was existing logic for terminating for a fatal error from the first loop without carrying anything forward:

// If the error is not fatal, then keep going.
match result {
Ok(()) => return Ok(()),
err @ Err(Error::MaximumSignatureChecksExceeded) => return err,
_ => {}
};

On main and in rel-0.101 we did not have that logic:

webpki/src/verify_cert.rs

Lines 206 to 209 in 932ad95

let err = match result {
Ok(()) => return Ok(()),
Err(err) => err,
};

All three branches should be terminating further path building when the first loop_while_non_fatal_error encounters a fatal err, but in practice only rel-0.100 handled this properly. This was demonstrated when that branch started failing the backported test_too_many_path_calls test, because the first fatal error encountered is from expending the signature checking budget. In main and rel-0.101 that error is ignored and we continue until the path building call budget is expended.

This branch fixes the fatal error handling, and requires adjusting the test_too_many_path_calls test to do what it was intending to do in the presence of proper fatal error handling. I slightly refactored the verify_chain helper to make this easier (and to let the existing name_constraint_budget test also benefit from the shared helper).

@cpu cpu self-assigned this Sep 7, 2023
@codecov
Copy link

codecov bot commented Sep 7, 2023

Codecov Report

Merging #168 (c69804e) into main (932ad95) will decrease coverage by 0.06%.
Report is 3 commits behind head on main.
The diff coverage is 98.83%.

@@            Coverage Diff             @@
##             main     #168      +/-   ##
==========================================
- Coverage   96.70%   96.64%   -0.06%     
==========================================
  Files          15       16       +1     
  Lines        4549     4532      -17     
==========================================
- Hits         4399     4380      -19     
- Misses        150      152       +2     
Files Changed Coverage Δ
src/verify_cert.rs 97.67% <98.70%> (-0.46%) ⬇️
src/error.rs 59.01% <100.00%> (+3.24%) ⬆️

... and 4 files with indirect coverage changes

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

📢 Have feedback on the report? Share it here.

@cpu cpu force-pushed the cpu-adjust-fatal-err-handling branch from d16d7aa to adb8c32 Compare September 7, 2023 16:32
@cpu cpu mentioned this pull request Sep 1, 2023
13 tasks
@djc
Copy link
Member

djc commented Sep 7, 2023

Maybe split the extraction of the is_fatal() method from the core fix to make it more obvious what the problem was?

@cpu cpu force-pushed the cpu-adjust-fatal-err-handling branch from adb8c32 to 06a4ae1 Compare September 7, 2023 17:11
@cpu
Copy link
Member Author

cpu commented Sep 7, 2023

Maybe split the extraction of the is_fatal() method from the core fix to make it more obvious what the problem was?

Done. I also split the test helper refactoring into two parts.

@djc
Copy link
Member

djc commented Sep 7, 2023

Sorry: if you add an is_fatal() helper it should happen in the same commit as starting to use it, so that we can verify that the logic remains the same, and then changing the logic should be a separate commit (either order could make sense).

@cpu
Copy link
Member Author

cpu commented Sep 7, 2023

@djc Ah! Ok, will rework 👍

This commit adjusts the arguments to the `verify_chain` test helper to
take references instead of moving the arguments. This makes it easier to
use the same inputs for multiple `verify_chain` invocations.
This commit updates the `verify_chain` helper to allow providing an
optional `Budget` argument (using the default if not provided). This
makes it easier to write tests that need to customize the path building
budget (e.g. `name_constraint_budget`).
This commit adds a method to `Error` for testing whether an error should
be considered fatal, e.g. should stop any further path building
progress. The existing consideration of fatal errors in
`loop_while_non_fatal_error` is updated to use the `is_fatal` fn.

Having this in a central place means we can avoid duplicating the match
arms in multiple places, where they are likely to fall out-of-sync.
@cpu cpu force-pushed the cpu-adjust-fatal-err-handling branch from 06a4ae1 to 1293561 Compare September 7, 2023 17:55
@cpu
Copy link
Member Author

cpu commented Sep 7, 2023

if you add an is_fatal() helper it should happen in the same commit as starting to use it, so that we can verify that the logic remains the same, and then changing the logic should be a separate commit (either order could make sense).

Updated so the new helper is added in bcdd680 and immediately used to replace the existing fatal err handling in loop_while_non_fatal_error.

The change in error handling behaviour is now isolated to b5af2ce where the helper is added to the error handling between the two loop_while_non_fatal_error invocations.

Hopefully that better matches what you were looking for 🤞

Previously the handling of fatal path building errors (e.g. those that
should halt all further exploration of the path space) was mishandled
such that we could hit the maximum signature budget and still pursue
additional path building. This was demonstrated by the
`test_too_many_path_calls` unit test which was hitting
a `MaximumSignatureChecksExceeded` error, but yet proceeding until
hitting a `MaximumPathBuildCallsExceeded` error.

This commit updates the error handling between the first and second
`loop_while_non_fatal_error` calls to properly terminate the search when
a fatal error is encountered, instead of proceeding with further search.

The existing `test_too_many_path_calls` test is updated to use an
artificially large signature check budget so that we can focus on testing
the limit we care about for that test without needing to invest in
more complicated test case generation. This avoids hitting
a `MaximumSignatureChecksExceeded` error early in the test (which now
terminates further path building), instead allowing execution to
continue until the maximum path building call budget is expended
(matching the previous behaviour and intent of the original test).
@cpu cpu force-pushed the cpu-adjust-fatal-err-handling branch from 1293561 to b5af2ce Compare September 7, 2023 17:58
src/verify_cert.rs Show resolved Hide resolved
@cpu cpu force-pushed the cpu-adjust-fatal-err-handling branch 2 times, most recently from 361dcf6 to 9fbc05a Compare September 8, 2023 13:26
The `loop_while_non_fatal_error` helper can return one of three things:

* success, when a validated chain to a trust anchor was built.
* a fatal error, e.g. when a `Budget` has been exceeded and no further
  path building should occur because we've exhausted a budget.
* a non-fatal error, when a candidate chain results in an error
  condition, but other paths could be considered if the options are not
  exhausted.

This commit attempts to express this in the type system, centralizing
a check for what is/isn't a fatal error and ensuring that downstream
callers to `loop_while_non_fatal_error` handle the fatal case
appropriately.
@cpu cpu force-pushed the cpu-adjust-fatal-err-handling branch from 9fbc05a to c69804e Compare September 8, 2023 13:28
@cpu
Copy link
Member Author

cpu commented Sep 8, 2023

I'd like to merge this to make progress on backports. If there's any late feedback I'm happy to iterate further!

@cpu cpu added this pull request to the merge queue Sep 8, 2023
Merged via the queue into rustls:main with commit 7ff3664 Sep 8, 2023
23 of 24 checks passed
@cpu cpu deleted the cpu-adjust-fatal-err-handling branch September 8, 2023 14:31
This was referenced Sep 8, 2023
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