Skip to content

Commit

Permalink
api: add key update request functionality (#4453)
Browse files Browse the repository at this point in the history
  • Loading branch information
jmayclin authored Mar 8, 2024
1 parent 770d3f3 commit d916942
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 9 deletions.
24 changes: 24 additions & 0 deletions api/s2n.h
Original file line number Diff line number Diff line change
Expand Up @@ -1882,6 +1882,30 @@ S2N_API extern uint64_t s2n_connection_get_delay(struct s2n_connection *conn);
*/
S2N_API extern int s2n_connection_set_cipher_preferences(struct s2n_connection *conn, const char *version);

/**
* Used to indicate the type of key update that is being requested. For further
* information refer to `s2n_connection_request_key_update`.
*/
typedef enum {
S2N_KEY_UPDATE_NOT_REQUESTED = 0,
S2N_KEY_UPDATE_REQUESTED
} s2n_peer_key_update;

/**
* Signals the connection to do a key_update at the next possible opportunity. Note that the resulting key update message
* will not be sent until `s2n_send` is called.
*
* @param conn The connection object to trigger the key update on.
* @param peer_request Indicates if a key update should also be requested
* of the peer. When set to `S2N_KEY_UPDATE_NOT_REQUESTED`, then only the sending
* key of `conn` will be updated. If set to `S2N_KEY_UPDATE_REQUESTED`, then
* the sending key of conn will be updated AND the peer will be requested to
* update their sending key. Note that s2n-tls currently only supports
* `peer_request` being set to `S2N_KEY_UPDATE_NOT_REQUESTED` and will return
* S2N_FAILURE if any other value is used.
* @returns S2N_SUCCESS on success. S2N_FAILURE on failure
*/
S2N_API extern int s2n_connection_request_key_update(struct s2n_connection *conn, s2n_peer_key_update peer_request);
/**
* Appends the provided application protocol to the preference list
*
Expand Down
24 changes: 23 additions & 1 deletion tests/unit/s2n_key_update_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ int main(int argc, char **argv)
EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&stuffer, 0));
EXPECT_SUCCESS(s2n_connection_set_io_stuffers(&stuffer, &stuffer, client_conn));

s2n_atomic_flag_set(&client_conn->key_update_pending);
EXPECT_SUCCESS(s2n_connection_request_key_update(client_conn, S2N_KEY_UPDATE_NOT_REQUESTED));

s2n_blocked_status blocked = 0;
EXPECT_SUCCESS(s2n_key_update_send(client_conn, &blocked));
Expand Down Expand Up @@ -677,5 +677,27 @@ int main(int argc, char **argv)
}
}

/* s2n_connection_key_update_requested */
{
/* null safety */
{
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_request_key_update(NULL, S2N_KEY_UPDATE_NOT_REQUESTED), S2N_ERR_NULL);
};

/* usage */
{
DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_request_key_update(conn, S2N_KEY_UPDATE_REQUESTED), S2N_ERR_INVALID_ARGUMENT);
};

/* happy path */
{
DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free);
EXPECT_FALSE(s2n_atomic_flag_test(&conn->key_update_pending));
EXPECT_SUCCESS(s2n_connection_request_key_update(conn, S2N_KEY_UPDATE_NOT_REQUESTED));
EXPECT_TRUE(s2n_atomic_flag_test(&conn->key_update_pending));
};
};

END_TEST();
}
2 changes: 1 addition & 1 deletion tests/unit/s2n_key_update_threads_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
_##name##_record_alg.encryption_limit = limit; \
name.record_alg = &_##name##_record_alg;

S2N_RESULT s2n_set_key_update_request_for_testing(keyupdate_request request);
S2N_RESULT s2n_set_key_update_request_for_testing(s2n_peer_key_update request);

static void *s2n_send_random_data(void *arg)
{
Expand Down
13 changes: 11 additions & 2 deletions tls/s2n_key_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@
#include "utils/s2n_atomic.h"
#include "utils/s2n_safety.h"

static keyupdate_request key_update_request_val = S2N_KEY_UPDATE_NOT_REQUESTED;
static s2n_peer_key_update key_update_request_val = S2N_KEY_UPDATE_NOT_REQUESTED;

int s2n_key_update_write(struct s2n_blob *out);
int s2n_check_record_limit(struct s2n_connection *conn, struct s2n_blob *sequence_number);

S2N_RESULT s2n_set_key_update_request_for_testing(keyupdate_request request)
S2N_RESULT s2n_set_key_update_request_for_testing(s2n_peer_key_update request)
{
RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
key_update_request_val = request;
Expand Down Expand Up @@ -146,3 +146,12 @@ int s2n_check_record_limit(struct s2n_connection *conn, struct s2n_blob *sequenc

return S2N_SUCCESS;
}

int s2n_connection_request_key_update(struct s2n_connection *conn, s2n_peer_key_update peer_request)
{
POSIX_ENSURE_REF(conn);
/* s2n-tls does not currently support requesting key updates from peers */
POSIX_ENSURE(peer_request == S2N_KEY_UPDATE_NOT_REQUESTED, S2N_ERR_INVALID_ARGUMENT);
s2n_atomic_flag_set(&conn->key_update_pending);
return S2N_SUCCESS;
}
5 changes: 0 additions & 5 deletions tls/s2n_key_update.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,5 @@ typedef enum {
RECEIVING
} keyupdate_status;

typedef enum {
S2N_KEY_UPDATE_NOT_REQUESTED = 0,
S2N_KEY_UPDATE_REQUESTED
} keyupdate_request;

int s2n_key_update_recv(struct s2n_connection *conn, struct s2n_stuffer *request);
int s2n_key_update_send(struct s2n_connection *conn, s2n_blocked_status *blocked);

0 comments on commit d916942

Please sign in to comment.