Skip to content

Commit

Permalink
feat: Modify s2nd/c to do serialization/deserialization (#4533)
Browse files Browse the repository at this point in the history
  • Loading branch information
maddeleine authored May 7, 2024
1 parent 8aa419e commit 4862e7f
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 7 deletions.
31 changes: 31 additions & 0 deletions bin/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ int s2n_set_common_server_config(int max_early_data, struct s2n_config *config,

int s2n_setup_server_connection(struct s2n_connection *conn, int fd, struct s2n_config *config, struct conn_settings settings)
{
if (settings.deserialize_in) {
GUARD_RETURN(s2n_connection_deserialize_in(conn, settings.deserialize_in), "Failed to deserialize file");
}

if (settings.self_service_blinding) {
s2n_connection_set_blinding(conn, S2N_SELF_SERVICE_BLINDING);
}
Expand Down Expand Up @@ -529,3 +533,30 @@ int wait_for_shutdown(struct s2n_connection *conn, int fd)
}
return S2N_SUCCESS;
}

int s2n_connection_serialize_out(struct s2n_connection *conn, const char *file_path)
{
uint32_t serialize_length = 0;
GUARD_RETURN(s2n_connection_serialization_length(conn, &serialize_length), "Failed to get serialized connection length");
uint8_t *mem = malloc(serialize_length);
GUARD_RETURN_NULL(mem);
GUARD_RETURN(s2n_connection_serialize(conn, mem, serialize_length), "Failed to get serialized connection");
GUARD_RETURN(write_array_to_file(file_path, mem, serialize_length), "Failed to write serialized connection to file");
free(mem);

return 0;
}

int s2n_connection_deserialize_in(struct s2n_connection *conn, const char *file_path)
{
size_t deserialize_length = 0;
GUARD_RETURN(get_file_size(file_path, &deserialize_length), "Failed to read deserialize-in file size");
ENSURE_RETURN(deserialize_length <= UINT32_MAX, "deserialize-in file size is too large");
uint8_t *mem = malloc(deserialize_length);
GUARD_RETURN_NULL(mem);
GUARD_RETURN(load_file_to_array(file_path, mem, deserialize_length), "Failed to read deserialize-in file");
GUARD_RETURN(s2n_connection_deserialize(conn, mem, (uint32_t) deserialize_length), "Failed to deserialize connection");
free(mem);

return 0;
}
28 changes: 28 additions & 0 deletions bin/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@
} \
} while (0)

#define ENSURE_EXIT(x, msg) \
do { \
if (!(x)) { \
fprintf(stderr, "%s\n", msg); \
exit(1); \
} \
} while (0)

#define GUARD_RETURN_NULL(x) \
do { \
if (x == NULL) { \
fprintf(stderr, "NULL pointer encountered\n"); \
return -1; \
} \
} while (0)

#define GUARD_RETURN(x, msg) \
do { \
if ((x) < 0) { \
Expand All @@ -43,6 +59,14 @@
} \
} while (0)

#define ENSURE_RETURN(x, msg) \
do { \
if (!(x)) { \
fprintf(stderr, "%s\n", msg); \
return -1; \
} \
} while (0)

#define S2N_MAX_PSK_LIST_LENGTH 10
#define MAX_KEY_LEN 32
#define MAX_VAL_LEN 255
Expand Down Expand Up @@ -74,6 +98,8 @@ struct conn_settings {
int max_conns;
const char *ca_dir;
const char *ca_file;
const char *serialize_out;
const char *deserialize_in;
char *psk_optarg_list[S2N_MAX_PSK_LIST_LENGTH];
size_t psk_list_len;
};
Expand Down Expand Up @@ -130,3 +156,5 @@ int s2n_setup_external_psk_list(struct s2n_connection *conn, char *psk_optarg_li
uint8_t unsafe_verify_host(const char *host_name, size_t host_name_len, void *data);
int s2n_setup_server_connection(struct s2n_connection *conn, int fd, struct s2n_config *config, struct conn_settings settings);
int s2n_set_common_server_config(int max_early_data, struct s2n_config *config, struct conn_settings conn_settings, const char *cipher_prefs, const char *session_ticket_key_file_path);
int s2n_connection_serialize_out(struct s2n_connection *conn, const char *file_path);
int s2n_connection_deserialize_in(struct s2n_connection *conn, const char *file_path);
40 changes: 37 additions & 3 deletions bin/s2nc.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#define OPT_PREFER_LOW_LATENCY 1005
#define OPT_PREFER_THROUGHPUT 1006
#define OPT_BUFFERED_SEND 1007
#define OPT_SERIALIZE_OUT 1008
#define OPT_DESERIALIZE_IN 1009

/*
* s2nc is an example client that uses many s2n-tls APIs.
Expand Down Expand Up @@ -292,6 +294,8 @@ int main(int argc, char *const *argv)
bool client_key_input = false;
const char *ticket_out = NULL;
char *ticket_in = NULL;
const char *serialize_out = NULL;
const char *deserialize_in = NULL;
uint16_t mfl_value = 0;
uint8_t insecure = 0;
int reconnect = 0;
Expand Down Expand Up @@ -340,6 +344,8 @@ int main(int argc, char *const *argv)
{ "ticket-out", required_argument, 0, OPT_TICKET_OUT },
{ "ticket-in", required_argument, 0, OPT_TICKET_IN },
{ "no-session-ticket", no_argument, 0, 'T' },
{ "serialize-out", required_argument, 0, OPT_SERIALIZE_OUT },
{ "deserialize-in", required_argument, 0, OPT_DESERIALIZE_IN },
{ "dynamic", required_argument, 0, 'D' },
{ "timeout", required_argument, 0, 't' },
{ "corked-io", no_argument, 0, 'C' },
Expand Down Expand Up @@ -419,6 +425,22 @@ int main(int argc, char *const *argv)
case OPT_TICKET_IN:
ticket_in = optarg;
break;
/* The serialize_out and deserialize_in options are not documented
* in the usage section as they are not intended to work correctly
* using s2nc by itself. s2nc and s2nd are processes which close
* their TCP connection upon exit. This will cause an error if one
* peer serializes and exits and the other doesn't, as serialization
* depends on a continuous TCP connection with the peer. Therefore, our
* only usage of this feature is in our integ test framework,
* which serializes and deserializes both client and server at the
* same time. Do not expect these options to work when using s2nc alone.
*/
case OPT_SERIALIZE_OUT:
serialize_out = optarg;
break;
case OPT_DESERIALIZE_IN:
deserialize_in = optarg;
break;
case 'T':
session_ticket = 0;
break;
Expand Down Expand Up @@ -629,13 +651,22 @@ int main(int argc, char *const *argv)
GUARD_EXIT(s2n_config_set_npn(config, 1), "Error setting npn support");
}

if (serialize_out) {
GUARD_EXIT(s2n_config_set_serialization_version(config, S2N_SERIALIZED_CONN_V1),
"Error setting serialized version");
}

struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT);

if (conn == NULL) {
print_s2n_error("Error getting new connection");
exit(1);
}

if (deserialize_in) {
GUARD_EXIT(s2n_connection_deserialize_in(conn, deserialize_in), "Failed to deserialize file");
}

GUARD_EXIT(s2n_connection_set_config(conn, config), "Error setting configuration");

GUARD_EXIT(s2n_set_server_name(conn, server_name), "Error setting server name");
Expand Down Expand Up @@ -684,8 +715,7 @@ int main(int argc, char *const *argv)
}
}

/* See echo.c */
if (negotiate(conn, sockfd) != 0) {
if (!deserialize_in && negotiate(conn, sockfd) != 0) {
/* Error is printed in negotiate */
S2N_ERROR_PRESERVE_ERRNO();
}
Expand Down Expand Up @@ -746,7 +776,11 @@ int main(int argc, char *const *argv)
GUARD_EXIT(renegotiate(conn, sockfd, reneg_ctx.wait), "Renegotiation failed");
}

GUARD_EXIT(wait_for_shutdown(conn, sockfd), "Error closing connection");
if (serialize_out) {
GUARD_EXIT(s2n_connection_serialize_out(conn, serialize_out), "Error serializing connection");
} else {
GUARD_EXIT(wait_for_shutdown(conn, sockfd), "Error closing connection");
}

GUARD_EXIT(s2n_connection_free(conn), "Error freeing connection");

Expand Down
37 changes: 33 additions & 4 deletions bin/s2nd.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ static char default_private_key[] =
"ggF9KQ0xWz7Km3GXv5+bwM5bcgt1A/s6sZCimXuj3Fle3RqOTF0="
"-----END RSA PRIVATE KEY-----";

#define OPT_BUFFERED_SEND 1000
#define OPT_BUFFERED_SEND 1000
#define OPT_SERIALIZE_OUT 1001
#define OPT_DESERIALIZE_IN 1002

void usage()
{
Expand Down Expand Up @@ -221,9 +223,9 @@ int handle_connection(int fd, struct s2n_config *config, struct conn_settings se
S2N_ERROR_PRESERVE_ERRNO();
}

s2n_setup_server_connection(conn, fd, config, settings);
GUARD_EXIT(s2n_setup_server_connection(conn, fd, config, settings), "Error setting up connection");

if (negotiate(conn, fd) != S2N_SUCCESS) {
if (!settings.deserialize_in && negotiate(conn, fd) != S2N_SUCCESS) {
if (settings.mutual_auth) {
if (!s2n_connection_client_cert_used(conn)) {
print_s2n_error("Error: Mutual Auth was required, but not negotiated");
Expand All @@ -243,7 +245,11 @@ int handle_connection(int fd, struct s2n_config *config, struct conn_settings se
echo(conn, fd, &stop_echo);
}

GUARD_RETURN(wait_for_shutdown(conn, fd), "Error closing connection");
if (settings.serialize_out) {
GUARD_RETURN(s2n_connection_serialize_out(conn, settings.serialize_out), "Error serializing connection");
} else {
GUARD_RETURN(wait_for_shutdown(conn, fd), "Error closing connection");
}

GUARD_RETURN(s2n_connection_wipe(conn), "Error wiping connection");

Expand Down Expand Up @@ -307,6 +313,8 @@ int main(int argc, char *const *argv)
{ "ca-file", required_argument, 0, 't' },
{ "insecure", no_argument, 0, 'i' },
{ "stk-file", required_argument, 0, 'a' },
{ "serialize-out", required_argument, 0, OPT_SERIALIZE_OUT },
{ "deserialize-in", required_argument, 0, OPT_DESERIALIZE_IN },
{ "no-session-ticket", no_argument, 0, 'T' },
{ "corked-io", no_argument, 0, 'C' },
{ "max-conns", optional_argument, 0, 'X' },
Expand Down Expand Up @@ -426,6 +434,22 @@ int main(int argc, char *const *argv)
send_buffer_size = (uint32_t) send_buffer_size_scanned_value;
break;
}
/* The serialize_out and deserialize_in options are not documented
* in the usage section as they are not intended to work correctly
* using s2nd by itself. s2nc and s2nd are processes which close
* their TCP connection upon exit. This will cause an error if one
* peer serializes and exits and the other doesn't, as serialization
* depends on a continuous TCP connection with the peer. Therefore, our
* only usage of this feature is in our integ test framework,
* which serializes and deserializes both client and server at the
* same time. Do not expect these options to work when using s2nd alone.
*/
case OPT_SERIALIZE_OUT:
conn_settings.serialize_out = optarg;
break;
case OPT_DESERIALIZE_IN:
conn_settings.deserialize_in = optarg;
break;
case 'A':
alpn = optarg;
break;
Expand Down Expand Up @@ -616,6 +640,11 @@ int main(int argc, char *const *argv)
GUARD_EXIT(s2n_config_set_npn(config, 1), "Error setting npn support");
}

if (conn_settings.serialize_out) {
GUARD_EXIT(s2n_config_set_serialization_version(config, S2N_SERIALIZED_CONN_V1),
"Error setting serialized version");
}

FILE *key_log_file = NULL;

if (key_log_path) {
Expand Down

0 comments on commit 4862e7f

Please sign in to comment.