]> git.kaiwu.me - nginx.git/commitdiff
Address validation using NEW_TOKEN frame.
authorSergey Kandaurov <pluknet@nginx.com>
Thu, 14 May 2020 12:47:24 +0000 (15:47 +0300)
committerSergey Kandaurov <pluknet@nginx.com>
Thu, 14 May 2020 12:47:24 +0000 (15:47 +0300)
src/event/ngx_event_quic.c
src/event/ngx_event_quic_transport.c
src/event/ngx_event_quic_transport.h

index 2fd629c3b3c8f8cb9881d8be2d808582c9ae112c..6bb34889206178dad51a9a7afb6cafc9487fe0b6 100644 (file)
@@ -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);
     }
 
@@ -1950,6 +1967,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.
index 7f064eb54869c7467a0baa55ebd2150ed2db44a7..ddf99a3bc94b77e1ac49dba6fa6469bf4fb9dbb2 100644 (file)
@@ -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:
@@ -1231,6 +1236,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)
 {
index 62ec842d65ea0ed3c60ebc186d8e8b08a3fe1787..1ff70f97b275acdb7b18813992bcd4c6a2d56b92 100644 (file)
@@ -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;