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

feat: add constant time comparison for grpc authentication #5902

Merged

Conversation

hansieodendaal
Copy link
Contributor

@hansieodendaal hansieodendaal commented Nov 2, 2023

Description

  • Added constant-time username comparison for gRPC authentication. This will largely mitigate side-channel attacks to uncover the gRPC username. (See BasicAuthCredentials::constant_time_compare_username)

  • Edit: Credential validation for the combined username and password will now also run in constant time and not return if the username did not match as it did previously.

  • Edit: Fixed an issue where the BasicAuthCredentials from header did not pass validation, impacted in fn it_generates_a_valid_header() and it_decodes_from_well_formed_header.

(Closes #5810)

Motivation and Context

See #5810

How Has This Been Tested?

  • Added two unit tests to compare constant time performance with varying length username guesses. The unit test was performed in release mode with a no-load and fully loaded CPU.
  • fn it_compares_user_names_in_constant_time()
        // This unit test asserts that the minimum variance is less than 10% (chosen to be robust for running the unit
        // test with CI), indicating that the function behaves within acceptable constant-time constraints.
        //
        // Some consecutive results running in release mode on a Core i7-12700H (with no other processes running):
        //
        // Minimum variance:                          0.247 %
        // Average variance:                          4.65738 %
        // Average short username time:               1.17486 microseconds
        // Average long username time:                1.17344 microseconds
        // Average actual username time:              1.18388 microseconds
        //
        // Minimum variance:                          0.10214 %
        // Average variance:                          4.32226 %
        // Average short username time:               1.1619 microseconds
        // Average long username time:                1.16591 microseconds
        // Average actual username time:              1.18157 microseconds
        //
        // Minimum variance:                          0.17953 %
        // Average variance:                          5.51519 %
        // Average short username time:               1.17974 microseconds
        // Average long username time:                1.19232 microseconds
        // Average actual username time:              1.18709 microseconds
        //
        // Some consecutive results running in release mode on a Core i7-12700H (while entire CPU fully stressed):
        //
        // Minimum variance:                          0.60357 %
        // Average variance:                          6.30167 %
        // Average short username time:               1.81708 microseconds
        // Average long username time:                1.77562 microseconds
        // Average actual username time:              1.74824 microseconds
        //
        // Minimum variance:                          0.28176 %
        // Average variance:                          6.47136 %
        // Average short username time:               1.8317 microseconds
        // Average long username time:                1.8304 microseconds
        // Average actual username time:              1.80362 microseconds
        //
        // Minimum variance:                          0.53593 %
        // Average variance:                          6.99394 %
        // Average short username time:               1.82322 microseconds
        // Average long username time:                1.81431 microseconds
        // Average actual username time:              1.78002 microseconds
  • fn it_compares_credentials_in_constant_time()
        // This unit test asserts that the minimum variance is less than 10% (chosen to be robust for running the unit
        // test with CI), indicating that the function behaves within acceptable constant-time constraints.
        //
        // Some consecutive results running in release mode on a Core i7-12700H (with no other processes running):
        //
        // Minimum variance:                          0.43478 %
        // Average variance:                          2.08995 %
        // Average short username time:               34.580 microseconds
        // Average long username time:                34.315 microseconds
        // Average actual username time:              34.260 microseconds
        //
        // Minimum variance:                          0.43731 %
        // Average variance:                          1.77209 %
        // Average short username time:               34.560 microseconds
        // Average long username time:                34.755 microseconds
        // Average actual username time:              34.690 microseconds
        //
        // Minimum variance:                          0.43988 %
        // Average variance:                          1.61299 %
        // Average short username time:               34.33999 microseconds
        // Average long username time:                34.38500 microseconds
        // Average actual username time:              34.28500 microseconds
        //
        // Some consecutive results running in release mode on a Core i7-12700H (while entire CPU fully stressed):
        //
        // Minimum variance:                          0.30326 %
        // Average variance:                          2.29341 %
        // Average short username time:               64.87500 microseconds
        // Average long username time:                65.55499 microseconds
        // Average actual username time:              65.81000 microseconds
        //
        // Minimum variance:                          1.18168 %
        // Average variance:                          2.99206 %
        // Average short username time:               67.970 microseconds
        // Average long username time:                68.000 microseconds
        // Average actual username time:              68.005 microseconds
        //
        // Minimum variance:                          1.01083 %
        // Average variance:                          2.31316 %
        // Average short username time:               68.715 microseconds
        // Average long username time:                69.675 microseconds
        // Average actual username time:              69.715 microseconds

What process can a PR reviewer use to test or verify this change?

Code walk through
Run the unit tests

Breaking Changes

  • None
  • Requires data directory on base node to be deleted
  • Requires hard fork
  • Other - Please specify

Copy link

github-actions bot commented Nov 2, 2023

Test Results (CI)

1 257 tests   1 257 ✔️  11m 7s ⏱️
     39 suites         0 💤
       1 files           0

Results for commit 0765a6a.

♻️ This comment has been updated with latest results.

@ghpbot-tari-project ghpbot-tari-project added P-acks_required Process - Requires more ACKs or utACKs P-reviews_required Process - Requires a review from a lead maintainer to be merged labels Nov 2, 2023
Copy link

github-actions bot commented Nov 2, 2023

Test Results (Integration tests)

31 tests   31 ✔️  15m 5s ⏱️
11 suites    0 💤
  2 files      0

Results for commit 0765a6a.

♻️ This comment has been updated with latest results.

@AaronFeickert
Copy link
Collaborator

AaronFeickert commented Nov 3, 2023

It's possible to simplify this design significantly while making it likely more robust against unwanted compiler optimizations. As noted in the earlier review, using subtle can simplify constant-time equality testing on byte slices. Second, it's not necessary to use the randomized byte slice interleaving. Simply prepending fixed-length byte arrays with each username's length (to avoid padding collisions) and then padding with zeros results in low timing variance.

Also, even supposing that a leak occurs, security really shouldn't depend on the username being secret.

Here's a commit on a test branch that uses this design.

@hansieodendaal
Copy link
Contributor Author

@AaronFeickert, thanks for the comments, the code is now greatly simplified with additional unit tests.

@AaronFeickert
Copy link
Collaborator

AaronFeickert commented Nov 7, 2023

It looks like the real kerfuffle is trying to mitigate the effects of padding the actual username. One alternate design that eliminates this entirely is to create a PaddedString type that stores the length of the original username and a padded byte array. You can then use subtle to cleanly implement ConstantTimeEq for this type. When a comparison username is supplied, you create a PaddedString from it and run ct_eq. Padding the supplied username on demand leaks nothing to an attacker, and all the constant-time logic is neatly handled by the ConstantTimeEq trait. Most importantly, it means that no length-dependent operations are performed on the actual username except at creation time.

@AaronFeickert
Copy link
Collaborator

This closes #5904.

Added constant time username comparison for gRPC authentication. This will largely
mitigate side-channel attacks to uncover the gRPC username.
Copy link
Collaborator

@AaronFeickert AaronFeickert left a comment

Choose a reason for hiding this comment

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

LGTM

@SWvheerden SWvheerden merged commit 2fe44db into tari-project:development Nov 10, 2023
14 checks passed
@hansieodendaal hansieodendaal deleted the ho_constant_time_compare branch November 10, 2023 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P-acks_required Process - Requires more ACKs or utACKs P-reviews_required Process - Requires a review from a lead maintainer to be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GRPC - Wallet username vulnerable to timing attacks
4 participants