summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-11-22 13:26:51 +0000
committerHugo Landau <hlandau@openssl.org>2023-01-19 13:17:39 +0000
commitb83cf3fcf1149326f215cffd37f5c9725a4b61de (patch)
tree7dd12b2666b4bf21133124d84daed48088394b89 /ssl
parent93e9b6cc4e2b47a5fb32f093c38b7963e9c270aa (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.c324
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);
+}