diff options
author | Hugo Landau <hlandau@openssl.org> | 2022-11-22 13:26:51 +0000 |
---|---|---|
committer | Hugo Landau <hlandau@openssl.org> | 2023-01-19 13:17:39 +0000 |
commit | b83cf3fcf1149326f215cffd37f5c9725a4b61de (patch) | |
tree | 7dd12b2666b4bf21133124d84daed48088394b89 /ssl | |
parent | 93e9b6cc4e2b47a5fb32f093c38b7963e9c270aa (diff) |
QUIC DHS: (Server support) Add server state machine for DHS
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/19734)
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/quic/quic_dummy_handshake.c | 324 |
1 files changed, 278 insertions, 46 deletions
diff --git a/ssl/quic/quic_dummy_handshake.c b/ssl/quic/quic_dummy_handshake.c index f3e5bcee2b..9c37db98b2 100644 --- a/ssl/quic/quic_dummy_handshake.c +++ b/ssl/quic/quic_dummy_handshake.c @@ -18,17 +18,27 @@ #define QUIC_DHS_MSG_TYPE_CERT_VERIFY 0x0F #define QUIC_DHS_MSG_TYPE_FINISHED 0x14 -#define QUIC_DHS_STATE_INITIAL 0 -#define QUIC_DHS_STATE_SENT_CH 1 -#define QUIC_DHS_STATE_RECEIVED_SH 2 -#define QUIC_DHS_STATE_RECEIVED_EE_HDR 8 -#define QUIC_DHS_STATE_RECEIVED_EE 3 -#define QUIC_DHS_STATE_RECEIVED_CERT 4 -#define QUIC_DHS_STATE_RECEIVED_CERT_VERIFY 5 -#define QUIC_DHS_STATE_RECEIVED_FINISHED 6 -#define QUIC_DHS_STATE_SENT_FINISHED 7 - -#define QUIC_DHS_STATE_ERROR 0xFF +#define QUIC_DHS_CLIENT_STATE_INITIAL 0x00 +#define QUIC_DHS_CLIENT_STATE_SENT_CH 0x01 +#define QUIC_DHS_CLIENT_STATE_RECEIVED_SH 0x02 +#define QUIC_DHS_CLIENT_STATE_RECEIVED_EE_HDR 0x08 +#define QUIC_DHS_CLIENT_STATE_RECEIVED_EE 0x03 +#define QUIC_DHS_CLIENT_STATE_RECEIVED_CERT 0x04 +#define QUIC_DHS_CLIENT_STATE_RECEIVED_CERT_VERIFY 0x05 +#define QUIC_DHS_CLIENT_STATE_RECEIVED_FINISHED 0x06 +#define QUIC_DHS_CLIENT_STATE_SENT_FINISHED 0x07 +#define QUIC_DHS_CLIENT_STATE_ERROR 0xFF + +#define QUIC_DHS_SERVER_STATE_INITIAL 0x00 +#define QUIC_DHS_SERVER_STATE_RECEIVED_CH_HDR 0x01 +#define QUIC_DHS_SERVER_STATE_RECEIVED_CH 0x02 +#define QUIC_DHS_SERVER_STATE_SENT_SH 0x03 +#define QUIC_DHS_SERVER_STATE_SENT_EE 0x04 +#define QUIC_DHS_SERVER_STATE_SENT_CERT 0x05 +#define QUIC_DHS_SERVER_STATE_SENT_CERT_VERIFY 0x06 +#define QUIC_DHS_SERVER_STATE_SENT_FINISHED 0x07 +#define QUIC_DHS_SERVER_STATE_RECEIVED_FINISHED 0x08 +#define QUIC_DHS_SERVER_STATE_ERROR 0xFF struct quic_dhs_st { QUIC_DHS_ARGS args; @@ -39,7 +49,7 @@ struct quic_dhs_st { size_t local_transport_params_len; unsigned char rx_hdr[4]; size_t rx_hdr_bytes_read; - size_t rx_ee_bytes_read; + size_t rx_bytes_read; }; QUIC_DHS *ossl_quic_dhs_new(const QUIC_DHS_ARGS *args) @@ -54,8 +64,7 @@ QUIC_DHS *ossl_quic_dhs_new(const QUIC_DHS_ARGS *args) if (dhs == NULL) return NULL; - dhs->args = *args; - dhs->state = QUIC_DHS_STATE_INITIAL; + dhs->args = *args; return dhs; } @@ -68,6 +77,7 @@ void ossl_quic_dhs_free(QUIC_DHS *dhs) OPENSSL_free(dhs); } +/* Send a handshake message. */ static int dhs_send(QUIC_DHS *dhs, unsigned char type, const void *buf, size_t buf_len) { @@ -97,6 +107,11 @@ static int dhs_send(QUIC_DHS *dhs, unsigned char type, return 1; } +/* + * Receive header of a handshake message. Length of body is written to + * *frame_len, and if non-zero this call should be followed by one or more calls + * to dhs_recv_body. + */ static int dhs_recv_sof(QUIC_DHS *dhs, uint32_t *type, size_t *frame_len) { size_t bytes_read = 0; @@ -130,6 +145,7 @@ static int dhs_recv_sof(QUIC_DHS *dhs, uint32_t *type, size_t *frame_len) return 1; } +/* Receive the body of an incoming message, or part thereof. */ static int dhs_recv_body(QUIC_DHS *dhs, unsigned char *buf, size_t buf_len, size_t *bytes_read) { @@ -151,7 +167,7 @@ static const unsigned char default_1rtt_write[32] = {43, 1}; int ossl_quic_dhs_set_transport_params(QUIC_DHS *dhs, const unsigned char *transport_params, size_t transport_params_len) { - if (!dhs->args.is_server && dhs->state != QUIC_DHS_STATE_INITIAL) + if (!dhs->args.is_server && dhs->state != QUIC_DHS_CLIENT_STATE_INITIAL) return 0; dhs->local_transport_params = transport_params; @@ -159,7 +175,8 @@ int ossl_quic_dhs_set_transport_params(QUIC_DHS *dhs, const unsigned char *trans return 1; } -int ossl_quic_dhs_tick(QUIC_DHS *dhs) +/* Tick implementation for the client role. */ +static int dhs_tick_client(QUIC_DHS *dhs) { int ret; uint32_t type; @@ -167,21 +184,21 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) for (;;) { switch (dhs->state) { - case QUIC_DHS_STATE_INITIAL: + case QUIC_DHS_CLIENT_STATE_INITIAL: /* We need to send a CH */ if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_CH, dhs->local_transport_params, dhs->local_transport_params_len)) return 0; - dhs->state = QUIC_DHS_STATE_SENT_CH; + dhs->state = QUIC_DHS_CLIENT_STATE_SENT_CH; break; - case QUIC_DHS_STATE_SENT_CH: + case QUIC_DHS_CLIENT_STATE_SENT_CH: ret = dhs_recv_sof(dhs, &type, &frame_len); if (ret == 1) { if (type == QUIC_DHS_MSG_TYPE_SH && frame_len == 0) { - dhs->state = QUIC_DHS_STATE_RECEIVED_SH; + dhs->state = QUIC_DHS_CLIENT_STATE_RECEIVED_SH; if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_HANDSHAKE, /*TX=*/0, @@ -189,8 +206,10 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) NULL, default_handshake_read, sizeof(default_handshake_read), - dhs->args.yield_secret_cb_arg)) + dhs->args.yield_secret_cb_arg)) { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; + } if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_HANDSHAKE, /*TX=*/1, @@ -198,10 +217,13 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) NULL, default_handshake_write, sizeof(default_handshake_write), - dhs->args.yield_secret_cb_arg)) + dhs->args.yield_secret_cb_arg)) { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; + } } else { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; /* error state, unexpected type */ } } else if (ret == 2) { @@ -211,18 +233,19 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) } break; - case QUIC_DHS_STATE_RECEIVED_SH: + case QUIC_DHS_CLIENT_STATE_RECEIVED_SH: ret = dhs_recv_sof(dhs, &type, &frame_len); if (ret == 1) { if (type == QUIC_DHS_MSG_TYPE_EE) { - dhs->state = QUIC_DHS_STATE_RECEIVED_EE_HDR; - dhs->rx_ee_bytes_read = 0; + dhs->state = QUIC_DHS_CLIENT_STATE_RECEIVED_EE_HDR; + dhs->rx_bytes_read = 0; dhs->remote_transport_params_len = frame_len; dhs->remote_transport_params = OPENSSL_malloc(dhs->remote_transport_params_len); if (dhs->remote_transport_params == NULL) return 0; } else { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; /* error state, unexpected type */ } } else if (ret == 2) { @@ -232,19 +255,21 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) } break; - case QUIC_DHS_STATE_RECEIVED_EE_HDR: - ret = dhs_recv_body(dhs, dhs->remote_transport_params + dhs->rx_ee_bytes_read, - dhs->remote_transport_params_len - dhs->rx_ee_bytes_read, + case QUIC_DHS_CLIENT_STATE_RECEIVED_EE_HDR: + ret = dhs_recv_body(dhs, dhs->remote_transport_params + dhs->rx_bytes_read, + dhs->remote_transport_params_len - dhs->rx_bytes_read, &bytes_read); if (ret == 1) { - dhs->rx_ee_bytes_read += bytes_read; + dhs->rx_bytes_read += bytes_read; if (bytes_read == dhs->remote_transport_params_len) { if (!dhs->args.got_transport_params_cb(dhs->remote_transport_params, dhs->remote_transport_params_len, - dhs->args.got_transport_params_cb_arg)) + dhs->args.got_transport_params_cb_arg)) { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; + } - dhs->state = QUIC_DHS_STATE_RECEIVED_EE; + dhs->state = QUIC_DHS_CLIENT_STATE_RECEIVED_EE; } } else if (ret == 2) { return 1; /* no more data yet, not an error */ @@ -253,14 +278,16 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) } break; - case QUIC_DHS_STATE_RECEIVED_EE: + case QUIC_DHS_CLIENT_STATE_RECEIVED_EE: /* Expect Cert */ ret = dhs_recv_sof(dhs, &type, &frame_len); if (ret == 1) { - if (type == QUIC_DHS_MSG_TYPE_CERT && frame_len == 0) - dhs->state = QUIC_DHS_STATE_RECEIVED_CERT; - else + if (type == QUIC_DHS_MSG_TYPE_CERT && frame_len == 0) { + dhs->state = QUIC_DHS_CLIENT_STATE_RECEIVED_CERT; + } else { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; /* error state, unexpected type */ + } } else if (ret == 2) { return 1; /* no more data yet, not an error */ } else { @@ -268,14 +295,16 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) } break; - case QUIC_DHS_STATE_RECEIVED_CERT: + case QUIC_DHS_CLIENT_STATE_RECEIVED_CERT: /* Expect CertVerify */ ret = dhs_recv_sof(dhs, &type, &frame_len); if (ret == 1) { - if (type == QUIC_DHS_MSG_TYPE_CERT_VERIFY && frame_len == 0) - dhs->state = QUIC_DHS_STATE_RECEIVED_CERT_VERIFY; - else + if (type == QUIC_DHS_MSG_TYPE_CERT_VERIFY && frame_len == 0) { + dhs->state = QUIC_DHS_CLIENT_STATE_RECEIVED_CERT_VERIFY; + } else { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; /* error state, unexpected type */ + } } else if (ret == 2) { return 1; /* no more data yet, not an error */ } else { @@ -283,14 +312,16 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) } break; - case QUIC_DHS_STATE_RECEIVED_CERT_VERIFY: + case QUIC_DHS_CLIENT_STATE_RECEIVED_CERT_VERIFY: /* Expect Finished */ ret = dhs_recv_sof(dhs, &type, &frame_len); if (ret == 1) { - if (type == QUIC_DHS_MSG_TYPE_FINISHED && frame_len == 0) - dhs->state = QUIC_DHS_STATE_RECEIVED_FINISHED; - else + if (type == QUIC_DHS_MSG_TYPE_FINISHED && frame_len == 0) { + dhs->state = QUIC_DHS_CLIENT_STATE_RECEIVED_FINISHED; + } else { + dhs->state = QUIC_DHS_CLIENT_STATE_ERROR; return 0; /* error state, unexpected type */ + } } else if (ret == 2) { return 1; /* no more data yet, not an error */ } else { @@ -298,12 +329,12 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) } break; - case QUIC_DHS_STATE_RECEIVED_FINISHED: + case QUIC_DHS_CLIENT_STATE_RECEIVED_FINISHED: /* Send Finished */ if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_FINISHED, NULL, 0)) return 0; - dhs->state = QUIC_DHS_STATE_SENT_FINISHED; + dhs->state = QUIC_DHS_CLIENT_STATE_SENT_FINISHED; if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_1RTT, /*TX=*/0, @@ -330,7 +361,200 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) dhs->local_transport_params_len = 0; break; - case QUIC_DHS_STATE_SENT_FINISHED: + case QUIC_DHS_CLIENT_STATE_SENT_FINISHED: + /* Nothing to do, handshake complete. */ + return 1; + + default: + return 0; /* error state */ + } + } + + return 1; +} + +/* Tick implementation for the server role. */ +static int dhs_tick_server(QUIC_DHS *dhs) +{ + int ret; + uint32_t type; + size_t frame_len, bytes_read = 0; + + for (;;) { + switch (dhs->state) { + case QUIC_DHS_SERVER_STATE_INITIAL: + /* Waiting for ClientHello message */ + ret = dhs_recv_sof(dhs, &type, &frame_len); + if (ret == 1) { + if (type == QUIC_DHS_MSG_TYPE_CH && frame_len > 0) { + dhs->state = QUIC_DHS_SERVER_STATE_RECEIVED_CH_HDR; + dhs->rx_bytes_read = 0; + dhs->remote_transport_params_len = frame_len; + dhs->remote_transport_params + = OPENSSL_malloc(dhs->remote_transport_params_len); + + if (dhs->remote_transport_params == NULL) + return 0; + + } else { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; /* error state, unexpected type */ + } + } else if (ret == 2) { + return 1; /* no more data yet, not an error */ + } else { + return 0; + } + + break; + + case QUIC_DHS_SERVER_STATE_RECEIVED_CH_HDR: + ret = dhs_recv_body(dhs, dhs->remote_transport_params + dhs->rx_bytes_read, + dhs->remote_transport_params_len - dhs->rx_bytes_read, + &bytes_read); + if (ret == 1) { + dhs->rx_bytes_read += bytes_read; + if (dhs->rx_bytes_read == dhs->remote_transport_params_len) { + if (!dhs->args.got_transport_params_cb(dhs->remote_transport_params, + dhs->remote_transport_params_len, + dhs->args.got_transport_params_cb_arg)) { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; + } + + dhs->state = QUIC_DHS_SERVER_STATE_RECEIVED_CH; + } + } else if (ret == 2) { + return 1; /* no more data yet, not an error */ + } else { + return 0; + } + break; + + case QUIC_DHS_SERVER_STATE_RECEIVED_CH: + /* We need to send a ServerHello message */ + if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_SH, NULL, 0)) + return 0; + + /* + * Our send function automatically sends at the highest + * available EL so we need to do this after sending the SH. + */ + if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_HANDSHAKE, + /* (Keys reversed - server) */ + /*TX=*/0, + QRL_SUITE_AES128GCM, + NULL, + default_handshake_write, + sizeof(default_handshake_write), + dhs->args.yield_secret_cb_arg)) { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; + } + + if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_HANDSHAKE, + /* (Keys reversed - server) */ + /*TX=*/1, + QRL_SUITE_AES128GCM, + NULL, + default_handshake_read, + sizeof(default_handshake_read), + dhs->args.yield_secret_cb_arg)) { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; + } + + dhs->state = QUIC_DHS_SERVER_STATE_SENT_SH; + break; + + case QUIC_DHS_SERVER_STATE_SENT_SH: + /* We need to send an EncryptedExtensions message */ + if (dhs->local_transport_params == NULL + || dhs->local_transport_params_len == 0) + return 0; + + if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_EE, + dhs->local_transport_params, + dhs->local_transport_params_len)) + return 0; + + dhs->local_transport_params = NULL; + dhs->local_transport_params_len = 0; + + dhs->state = QUIC_DHS_SERVER_STATE_SENT_EE; + break; + + case QUIC_DHS_SERVER_STATE_SENT_EE: + /* We need to send a Certificate message */ + if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_CERT, NULL, 0)) + return 0; + + dhs->state = QUIC_DHS_SERVER_STATE_SENT_CERT; + break; + + case QUIC_DHS_SERVER_STATE_SENT_CERT: + /* We need to send a CertificateVerify message */ + if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_CERT_VERIFY, NULL, 0)) + return 0; + + dhs->state = QUIC_DHS_SERVER_STATE_SENT_CERT_VERIFY; + break; + + case QUIC_DHS_SERVER_STATE_SENT_CERT_VERIFY: + /* We need to send a Finished message */ + if (!dhs_send(dhs, QUIC_DHS_MSG_TYPE_FINISHED, NULL, 0)) + return 0; + + dhs->state = QUIC_DHS_SERVER_STATE_SENT_FINISHED; + break; + + case QUIC_DHS_SERVER_STATE_SENT_FINISHED: + /* We are waiting for a Finished message. */ + ret = dhs_recv_sof(dhs, &type, &frame_len); + if (ret == 1) { + if (type == QUIC_DHS_MSG_TYPE_FINISHED && frame_len == 0) { + if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_1RTT, + /* (Keys reversed - server) */ + /*TX=*/0, + QRL_SUITE_AES128GCM, + NULL, + default_1rtt_write, + sizeof(default_1rtt_write), + dhs->args.yield_secret_cb_arg)) { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; + } + + if (!dhs->args.yield_secret_cb(QUIC_ENC_LEVEL_1RTT, + /* (Keys reversed - server) */ + /*TX=*/1, + QRL_SUITE_AES128GCM, + NULL, + default_1rtt_read, + sizeof(default_1rtt_read), + dhs->args.yield_secret_cb_arg)) { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; + } + + if (!dhs->args.handshake_complete_cb(dhs->args.handshake_complete_cb_arg)) { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; + } + + dhs->state = QUIC_DHS_SERVER_STATE_RECEIVED_FINISHED; + } else { + dhs->state = QUIC_DHS_SERVER_STATE_ERROR; + return 0; /* error state, unexpected type */ + } + } else if (ret == 2) { + return 1; /* no more data yet, not an error */ + } else { + return 0; + } + break; + + case QUIC_DHS_SERVER_STATE_RECEIVED_FINISHED: /* Nothing to do, handshake complete. */ return 1; @@ -341,3 +565,11 @@ int ossl_quic_dhs_tick(QUIC_DHS *dhs) return 1; } + +int ossl_quic_dhs_tick(QUIC_DHS *dhs) +{ + if (dhs->args.is_server) + return dhs_tick_server(dhs); + else + return dhs_tick_client(dhs); +} |