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

Refactor alerts to make behavior clear #4019

Merged
merged 6 commits into from
Jun 5, 2023
Merged

Conversation

lrstewart
Copy link
Contributor

@lrstewart lrstewart commented May 24, 2023

Resolved issues:

resolves #3941
resolves #3937

Description of changes:

Currently, the s2n-tls alerts / shutdown logic is difficult to follow and fairly deceptive. This refactor simplifies the flow.

There are three alert cases to consider:

Generic close_notify alerts

Described in #3941. In summary, s2n-tls only sends close_notify alerts from s2n_shutdown, so we can safely remove the logic that appears to send them from s2n_flush.

Specific error alerts

Described in #3937. In summary, the alerts can be sent from s2n_flush, but that skips self-service blinding.

We only queue specific fatal alerts in a handful of places in the code (unsupported version alerts, and handshake failure alerts), all in s2n_negotiate. In each case, we also immediately return a fatal error, causing the connection to be marked closed and s2n_negotiate to fail with a fatal error. s2n_negotiate DOES call s2n_flush even if marked closed. However, in order to trigger that behavior, an application would need to be deliberately calling s2n_negotiate again despite a fatal error. That's not impossible: you could get that behavior if you ignored the error type and only checked blocked, but in that case it would also look like all your connections failed with S2N_ERR_T_CLOSED, regardless of the actual underlying error.

Because of the limited scope (only a few cases where we use a specific alert) and the already not recommended application logic required (calling s2n_negotiate again after a fatal error), I think this is behavior we can safely change in order to ensure blinding is enforced and simplify the code.

Warnings

Warnings do still need to be sent from s2n_flush. They're the only alert that isn't blinded and shouldn't wait for s2n_shutdown.

Call-outs:

  • Watch out for me writing "error" when I mean "alert" and vice versa in the comments 😅
  • Other than the "Specific error alerts" case called out above, there should be no behavior changes. Let me know if you think of cases that might have changed and should be specifically tested.
  • Very minor bonus: we save a handful of bytes in s2n_connection without the heavy-weight alert stuffers

Testing:

Existing tests + new ones pass. I added a lot of new tests recently for s2n_shutdown / alerts, so there should be sufficient testing to catch any regressions.

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

@github-actions github-actions bot added the s2n-core team label May 24, 2023
@lrstewart lrstewart marked this pull request as ready for review May 25, 2023 00:05
@lrstewart lrstewart requested review from goatgoose and camshaft May 25, 2023 00:05
uint8_t writer_alert_out;
uint8_t reader_alert_out;
uint8_t reader_warning_out;
bool alert_sent;
Copy link
Contributor

@goatgoose goatgoose May 25, 2023

Choose a reason for hiding this comment

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

Should alert_sent go where close_notify_queued was, to save a byte?

Copy link
Contributor Author

@lrstewart lrstewart May 26, 2023

Choose a reason for hiding this comment

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

I opened an issue for why we shouldn't do that: #4026

It's arguable whether alert_sent falls into this category, but I believe it does. Our documentation doesn't currently say it, but I think we have to support calling s2n_shutdown_send while s2n_recv is still active.

tls/s2n_alerts.c Show resolved Hide resolved
tests/unit/s2n_alerts_test.c Show resolved Hide resolved
@lrstewart lrstewart requested review from goatgoose and maddeleine June 2, 2023 06:25
docs/DEVELOPMENT-GUIDE.md Outdated Show resolved Hide resolved
docs/DEVELOPMENT-GUIDE.md Outdated Show resolved Hide resolved
tls/s2n_alerts.c Show resolved Hide resolved
tls/s2n_alerts.c Show resolved Hide resolved
tls/s2n_alerts.c Show resolved Hide resolved
tls/s2n_alerts.c Show resolved Hide resolved
if (conn->reader_warning_out) {
POSIX_GUARD_RESULT(s2n_alerts_write_warning(conn));
conn->reader_warning_out = 0;
POSIX_GUARD(s2n_flush(conn, blocked));
Copy link
Contributor

Choose a reason for hiding this comment

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

Recursion?? You found an appropriate use of recursion??

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 mean... I found a use of recursion ;) It's a little cleaner than the previous goto.

tls/s2n_shutdown.c Show resolved Hide resolved
@lrstewart lrstewart requested a review from maddeleine June 2, 2023 22:41
@@ -35,8 +35,8 @@ int main(int argc, char **argv)
BEGIN_TEST();

const uint8_t close_notify_alert[] = {
2 /* AlertLevel = fatal */,
0 /* AlertDescription = close_notify */
S2N_TLS_ALERT_LEVEL_WARNING,
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this be alert level fatal?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope: https://github.com/aws/s2n-tls/blame/e5d334e33f705487b501347085792c5222d095e6/tls/s2n_alerts.c#L253

I couldn't find a line in the RFC stating that the level should be warning, but you can see the message on the relevant commit: b0b3871 It also just makes sense that it would be a warning. Most implementations (including ours) probably ignore the level completely, but it'd be an easy implementation mistake to treat it as an arbitrary fatal error instead of a close_notify if the level was set to fatal.

@lrstewart lrstewart enabled auto-merge (squash) June 5, 2023 19:18
@lrstewart lrstewart merged commit 6e971f9 into aws:main Jun 5, 2023
@lrstewart lrstewart deleted the alerts_refactor branch June 5, 2023 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

writer_alert_out is unnecessary Possible issue with self-service blinding and reader alerts
3 participants