Skip to content

Conversation

@jmayclin
Copy link
Contributor

@jmayclin jmayclin commented Nov 23, 2025

Goal

Emit a "handshake event", allowing customers to observe multiple pieces of information about the handshake.

Why

Currently customers have to call large numbers of individual "getter" APIs to gather information about the handshake. We expect that with this event structure will eventually be used to aggregate metrics for e.g. emission to CloudWatch.

How

The handshake is emitted to the application through a callback.

Callouts

  1. all of these APIs are currently unstable, and are expected to remain so for the forseeable future. Accordingly everything in this API is a "two way door".
  2. s2n_event_handshake vs s2n_handshake_event? I went with the former because it felt more neatly namespaced.
  3. I wonder whether we want to have the handshake event emitted by value?

This is adding new code in the hotpath, but it has a minimal impact

handshake-secp256r1/s2n-tls
                        time:   [1.1705 ms 1.1711 ms 1.1718 ms]
                        change: [−0.1650% +0.6024% +1.3401%] (p = 0.08 > 0.05)

Testing

Unit tests, and self-talk tests in the rust bindings.

The tests for this cover a large API surface area, which is tedious to cover in C. Therefore I deliberately have most of the testing in Rust.

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 Nov 23, 2025
@jmayclin jmayclin marked this pull request as ready for review December 5, 2025 23:18
/* This is a special value assigned to handshake_start_epoch_ns to indicate that
* it has already been sent to the application and should not be sent again.
*/
#define HANDSHAKE_EVENT_SENT UINT64_C(1) << 63
Copy link
Contributor

Choose a reason for hiding this comment

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

Pretty sure you need to include the stdint library in order to use this macro.

*
* An event is not emitted if the handshake fails.
*/
S2N_API extern int s2n_config_set_handshake_event(struct s2n_config *config, s2n_event_on_handshake_cb callback);
Copy link
Contributor

Choose a reason for hiding this comment

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

Trying to understand, what's the purpose of the subscriber pointer? Is it just the void ctx pointer that we typically have for callbacks? Why wouldn't you just combine these two APIs so that the set_handshake_event takes a subscriber?

Duration::from_nanos(self.0.handshake_end_ns - self.0.handshake_start_ns)
}

/// Handshake time, which just the amount of time synchronously spent in s2n_negotiate.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/// Handshake time, which just the amount of time synchronously spent in s2n_negotiate.
/// Handshake time, which is just the amount of time synchronously spent in s2n_negotiate.

b"good enough bytes for test",
SystemTime::UNIX_EPOCH,
)?
.enable_session_tickets(true)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: you technically don't need this if you added a session ticket key.

Suggested change
.enable_session_tickets(true)?;

* specific error for a null wall clock config just before the client hello callback.
* The test's assertions are weakened if this check is moved.
*/
POSIX_ENSURE(conn->config->wall_clock, S2N_ERR_CONFIG_NULL_BEFORE_CH_CALLBACK);
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 this change needed?

EXPECT_NOT_NULL(default_config = s2n_fetch_default_config());

/* s2n_config_new() matches s2n_fetch_default_config() */
if (default_config->security_policy != config->security_policy) {
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 know why you need this code change anymore since you fixed the problem?

}

int s2n_config_set_subscriber(struct s2n_config *config, void *subscriber)
{
Copy link
Contributor

Choose a reason for hiding this comment

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

You're missing null checks on both of these. Purposeful?

* specific error for a null wall clock config just before the client hello callback.
* The test's assertions are weakened if this check is moved.
*/
POSIX_ENSURE(conn->config->wall_clock, S2N_ERR_CONFIG_NULL_BEFORE_CH_CALLBACK);
Copy link
Contributor

Choose a reason for hiding this comment

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

What if conn->config is null? 👀

{
RESULT_ENSURE_REF(conn);
RESULT_ENSURE_REF(conn->config);
RESULT_ENSURE_REF(conn->config);
Copy link
Contributor

Choose a reason for hiding this comment

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

Duplicate check: it should be RESULT_ENSURE_REF(event)?

{
BEGIN_TEST();

if (!s2n_is_tls13_fully_supported()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we expect the event subscriber to be used with TLS 1.2? If so, it might be better to include that in the test?


event->protocol_version = s2n_connection_get_actual_protocol_version(conn);
event->cipher = s2n_connection_get_cipher(conn);
s2n_connection_get_key_exchange_group(conn, &event->group);
Copy link
Contributor

@CarolYeh910 CarolYeh910 Dec 8, 2025

Choose a reason for hiding this comment

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

Maybe add a RESULT_GUARD_POSIX to this call?

Edit: After looking into the RSA rust test, seems like the getter will return INVALID_STATE error in this case. That's why we don't check the error?

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.

3 participants