summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/event/ngx_event_quic.c52
-rw-r--r--src/event/ngx_event_quic_transport.c29
-rw-r--r--src/event/ngx_event_quic_transport.h6
3 files changed, 86 insertions, 1 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 2fd629c3b..6bb348892 100644
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -187,6 +187,7 @@ static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c,
static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt);
static ngx_int_t ngx_quic_send_cc(ngx_connection_t *c,
enum ssl_encryption_level_t level, ngx_uint_t err);
+static ngx_int_t ngx_quic_send_new_token(ngx_connection_t *c);
static ngx_int_t ngx_quic_handle_ack_frame(ngx_connection_t *c,
ngx_quic_header_t *pkt, ngx_quic_ack_frame_t *f);
@@ -544,6 +545,7 @@ static ngx_int_t
ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
ngx_quic_header_t *pkt, ngx_connection_handler_pt handler)
{
+ ngx_int_t rc;
ngx_uint_t i;
ngx_quic_tp_t *ctp;
ngx_quic_secrets_t *keys;
@@ -642,7 +644,22 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
return NGX_ERROR;
}
- if (tp->retry) {
+ if (pkt->token.len) {
+ rc = ngx_quic_validate_token(c, pkt);
+
+ if (rc == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token");
+ return NGX_ERROR;
+ }
+
+ if (rc == NGX_DECLINED) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token");
+ return ngx_quic_retry(c);
+ }
+
+ /* NGX_OK */
+
+ } else if (tp->retry) {
return ngx_quic_retry(c);
}
@@ -1951,6 +1968,35 @@ ngx_quic_send_cc(ngx_connection_t *c, enum ssl_encryption_level_t level,
static ngx_int_t
+ngx_quic_send_new_token(ngx_connection_t *c)
+{
+ ngx_str_t token;
+ ngx_quic_frame_t *frame;
+
+ if (!c->quic->tp.retry) {
+ return NGX_OK;
+ }
+
+ if (ngx_quic_new_token(c, &token) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ frame = ngx_quic_alloc_frame(c, 0);
+ if (frame == NULL) {
+ return NGX_ERROR;
+ }
+
+ frame->level = ssl_encryption_application;
+ frame->type = NGX_QUIC_FT_NEW_TOKEN;
+ frame->u.token.length = token.len;
+ frame->u.token.data = token.data;
+ ngx_sprintf(frame->info, "NEW_TOKEN");
+ ngx_quic_queue_frame(c->quic, frame);
+
+ return NGX_OK;
+}
+
+static ngx_int_t
ngx_quic_handle_ack_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
ngx_quic_ack_frame_t *ack)
{
@@ -2405,6 +2451,10 @@ ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data)
ngx_sprintf(frame->info, "HANDSHAKE DONE on handshake completed");
ngx_quic_queue_frame(c->quic, frame);
+ if (ngx_quic_send_new_token(c) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
/*
* Generating next keys before a key update is received.
* See quic-tls 9.4 Header Protection Timing Side-Channels.
diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c
index 7f064eb54..ddf99a3bc 100644
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -72,6 +72,8 @@ static size_t ngx_quic_create_ack(u_char *p, ngx_quic_ack_frame_t *ack);
static size_t ngx_quic_create_crypto(u_char *p,
ngx_quic_crypto_frame_t *crypto);
static size_t ngx_quic_create_hs_done(u_char *p);
+static size_t ngx_quic_create_new_token(u_char *p,
+ ngx_quic_new_token_frame_t *token);
static size_t ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf);
static size_t ngx_quic_create_max_streams(u_char *p,
ngx_quic_max_streams_frame_t *ms);
@@ -1128,6 +1130,9 @@ ngx_quic_create_frame(u_char *p, ngx_quic_frame_t *f)
case NGX_QUIC_FT_HANDSHAKE_DONE:
return ngx_quic_create_hs_done(p);
+ case NGX_QUIC_FT_NEW_TOKEN:
+ return ngx_quic_create_new_token(p, &f->u.token);
+
case NGX_QUIC_FT_STREAM0:
case NGX_QUIC_FT_STREAM1:
case NGX_QUIC_FT_STREAM2:
@@ -1232,6 +1237,30 @@ ngx_quic_create_hs_done(u_char *p)
static size_t
+ngx_quic_create_new_token(u_char *p, ngx_quic_new_token_frame_t *token)
+{
+ size_t len;
+ u_char *start;
+
+ if (p == NULL) {
+ len = ngx_quic_varint_len(NGX_QUIC_FT_NEW_TOKEN);
+ len += ngx_quic_varint_len(token->length);
+ len += token->length;
+
+ return len;
+ }
+
+ start = p;
+
+ ngx_quic_build_int(&p, NGX_QUIC_FT_NEW_TOKEN);
+ ngx_quic_build_int(&p, token->length);
+ p = ngx_cpymem(p, token->data, token->length);
+
+ return p - start;
+}
+
+
+static size_t
ngx_quic_create_stream(u_char *p, ngx_quic_stream_frame_t *sf)
{
size_t len;
diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h
index 62ec842d6..1ff70f97b 100644
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -132,6 +132,11 @@ typedef struct {
} ngx_quic_new_conn_id_frame_t;
+typedef struct {
+ uint64_t length;
+ u_char *data;
+} ngx_quic_new_token_frame_t;
+
/*
* common layout for CRYPTO and STREAM frames;
* conceptually, CRYPTO frame is also a stream
@@ -242,6 +247,7 @@ struct ngx_quic_frame_s {
ngx_quic_crypto_frame_t crypto;
ngx_quic_ordered_frame_t ord;
ngx_quic_new_conn_id_frame_t ncid;
+ ngx_quic_new_token_frame_t token;
ngx_quic_stream_frame_t stream;
ngx_quic_max_data_frame_t max_data;
ngx_quic_close_frame_t close;