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

Reorganise reseeding #1941

Conversation

torben-hansen
Copy link
Contributor

@torben-hansen torben-hansen commented Oct 22, 2024

Call-outs:

To avoid synchronisation issues for codepoints that reads/mutates the ctr-drbg state in #1919, we must reorganise the reseed logic. This decouples the code that reads/mutates the ctr-drbg state and the code that gathers entropy. The latter is not an issue. The former will later be wrapped as critical code needing synchronisation as part of the global zeroisation.

Testing:

Added new tests that verifies we can predict the time of reseeding based on the configured reseed bound.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.

@codecov-commenter
Copy link

codecov-commenter commented Oct 22, 2024

Codecov Report

Attention: Patch coverage is 90.32258% with 3 lines in your changes missing coverage. Please review.

Project coverage is 78.57%. Comparing base (ccb97ef) to head (59a871f).

Files with missing lines Patch % Lines
crypto/fipsmodule/rand/new_rand.c 86.95% 3 Missing ⚠️
Additional details and impacted files
@@                    Coverage Diff                    @@
##           randomness_generation    #1941      +/-   ##
=========================================================
+ Coverage                  78.46%   78.57%   +0.10%     
=========================================================
  Files                        585      585              
  Lines                      97061    98008     +947     
  Branches                   13920    13922       +2     
=========================================================
+ Hits                       76160    77010     +850     
- Misses                     20282    20380      +98     
+ Partials                     619      618       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@torben-hansen torben-hansen changed the title Restrict RAND_bytes request length and reorganise reseeding Reorganise reseeding Oct 23, 2024
@torben-hansen torben-hansen marked this pull request as ready for review October 23, 2024 22:21
@torben-hansen torben-hansen requested a review from a team as a code owner October 23, 2024 22:21
Comment on lines 161 to 162
uint8_t personalization_string[CTR_DRBG_ENTROPY_LEN],
size_t personalization_string_len) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why take the string length if you're requiring a specific size? You don't take a size for the seed. Also do we need a compiler flag to enforce this? I tried passing in a huge array for seed/personalization string and nothing complained.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

because you might not use the personalization string in which case personalization_string_len would be 0.

Copy link
Member

Choose a reason for hiding this comment

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

For consistency CTR_DRBG_reseed doesn't define the argument in this way. Should we just make them both consistent?

const uint8_t *additional_data,
size_t additional_data_len

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just use the name personalization_string to mean both additional data and personalization string. the latter is the name used in SP800-90A for the extra input for reseeding, while the latter is the name used for the extra input for initial seeding. I renamed stuff. now use "extra entropy" as a general name and flip to either "personalization string" or "additional data" depending on context.

Comment on lines 225 to 232
// must_reseed_before_generate is 1 if we must reseed before invoking the
// CTR-DRBG generate function CTR_DRBG_generate().
int must_reseed_before_generate = 0;

// Ensure the CTR-DRBG state is safe to use.
if (rand_ensure_ctr_drbg_uniqueness(state) == 1) {
rand_ctr_drbg_reseed(state);
must_reseed_before_generate = 1;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is all of this checked up here and not down around 267?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because it doesn't have to be checked iteratively. So, preventing redundant work.

// CTR-DRBG generate function CTR_DRBG_generate().
int must_reseed_before_generate = 0;

// Ensure the CTR-DRBG state is safe to use.
if (rand_ensure_ctr_drbg_uniqueness(state) == 1) {
Copy link
Contributor

Choose a reason for hiding this comment

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

NP: It's not immediately obvious what this function does when reading the name, I had to look up what this function does when reading this. What about is_uniqueness_broken or need_to_reseed_for_uniqueness

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed to rand_check_ctr_drbg_uniqueness and also flipped the return value: 0 is now "bad"and1` is "good"


must_reseed_before_generate = 0;

// TODO: unlock here
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are you planning to lock up on 253 to unlock here and then lock again on 279? Is the only important part to lock in rand_ctr_drbg_reseed? Could that handle the locking inside that function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to synchronise access to the CTR-DRBG with the global memory manager that can also mutate the state.

line 253 and 304 wraps the critical code under the while-loop. The powerpc then necessitates the unlock-lock cycle if needing to reseed due to reseed interval - but only if that condition ever becomes true. I don't want to handle that in a child function because then a post-condition to that function will be that the lock as already been acquired otherwise unlocking will fail and abort the process.

Comment on lines +62 to +67
// Should be able to perform kCtrDrbgReseedInterval-2 generate calls before a
// reseed is emitted. Requesting
// CTR_DRBG_MAX_GENERATE_LENGTH * (kCtrDrbgReseedInterval-2) + 1 would require
// quite a large buffer. Instead iterate until we need
// 5 iterations and request 5 * CTR_DRBG_MAX_GENERATE_LENGTH+1, which is a
// much smaller buffer.
Copy link
Contributor

Choose a reason for hiding this comment

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

What are you trying to test here that isn't covered in the first section?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, it's sorta the same thing. Just trying to make sure to exercise multiple iterations of the while-loop that calls the CTR_DRBG_generate() function.

Comment on lines -163 to -167
uint8_t seed[CTR_DRBG_ENTROPY_LEN];
uint8_t personalization_string[CTR_DRBG_ENTROPY_LEN];
size_t personalization_string_len = 0;
rand_get_ctr_drbg_seed_entropy(state->entropy_source, seed,
personalization_string, &personalization_string_len);
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get why you moved this out of this function. Also it's only used in one spot, does it make more sense to just put this all in RAND_bytes_core?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I need to decouple the two operations 1) gathering entropy 2) using that entropy to reseed. rand_get_ctr_drbg_seed_entropy() is used twice. rand_ctr_drbg_reseed() is now only used once, but I still like to factor out a wrapper for reseeding. I think it makes reading the core function easier.

Comment on lines 161 to 162
uint8_t personalization_string[CTR_DRBG_ENTROPY_LEN],
size_t personalization_string_len) {
Copy link
Member

Choose a reason for hiding this comment

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

For consistency CTR_DRBG_reseed doesn't define the argument in this way. Should we just make them both consistent?

const uint8_t *additional_data,
size_t additional_data_len

crypto/fipsmodule/rand/new_rand.c Outdated Show resolved Hide resolved
static void rand_ctr_drbg_reseed(struct rand_thread_local_state *state,
uint8_t seed[CTR_DRBG_ENTROPY_LEN],
uint8_t personalization_string[CTR_DRBG_ENTROPY_LEN],
size_t personalization_string_len) {

GUARD_PTR_ABORT(state);
Copy link
Member

Choose a reason for hiding this comment

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

Should seed and personalization_string be guarded for NULL or do we enforce that earlier on higher in the function call stack? Since these are just passed as pointers technically, not sure if the compiler would catch these otherwise?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I only use array types when calling these functions. so in practice no problem.

if (must_reseed_before_generate == 1 ||
(state->generate_calls_since_seed + 1) > kCtrDrbgReseedInterval) {

must_reseed_before_generate = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe move this to after reseeding is done.

@torben-hansen torben-hansen merged commit 72f0a9f into aws:randomness_generation Nov 1, 2024
100 of 106 checks passed
torben-hansen added a commit to torben-hansen/aws-lc that referenced this pull request Nov 1, 2024
To avoid synchronisation issues for codepoints that reads/mutates the ctr-drbg state in aws#1919, we must reorganise the reseed logic. This decouples the code that reads/mutates the ctr-drbg state and the code that gathers entropy. The latter is not an issue. The former will later be wrapped as critical code needing synchronisation as part of the global zeroisation.
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.

5 participants