# HG changeset patch # User Sergey Kandaurov # Date 1628081358 -10800 # Node ID fe919fd63b0bb3a4dd02429fd3044df4023b560b # Parent c35b255d80dc70f111efa13cc8806c292768ab57 QUIC: client certificate validation with OCSP. diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c --- a/src/event/quic/ngx_event_quic.c +++ b/src/event/quic/ngx_event_quic.c @@ -304,6 +304,8 @@ ngx_quic_new_connection(ngx_connection_t ctp->max_ack_delay = NGX_QUIC_DEFAULT_MAX_ACK_DELAY; ctp->active_connection_id_limit = 2; + ngx_queue_init(&qc->streams.uninitialized); + qc->streams.recv_max_data = qc->tp.initial_max_data; qc->streams.recv_window = qc->streams.recv_max_data; diff --git a/src/event/quic/ngx_event_quic.h b/src/event/quic/ngx_event_quic.h --- a/src/event/quic/ngx_event_quic.h +++ b/src/event/quic/ngx_event_quic.h @@ -69,6 +69,7 @@ typedef struct { struct ngx_quic_stream_s { ngx_rbtree_node_t node; + ngx_queue_t queue; ngx_connection_t *parent; ngx_connection_t *connection; uint64_t id; diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h --- a/src/event/quic/ngx_event_quic_connection.h +++ b/src/event/quic/ngx_event_quic_connection.h @@ -114,6 +114,7 @@ struct ngx_quic_socket_s { typedef struct { ngx_rbtree_t tree; ngx_rbtree_node_t sentinel; + ngx_queue_t uninitialized; uint64_t sent; uint64_t recv_offset; @@ -131,6 +132,9 @@ typedef struct { uint64_t client_max_streams_bidi; uint64_t client_streams_uni; uint64_t client_streams_bidi; + + ngx_uint_t initialized; + /* unsigned initialized:1; */ } ngx_quic_streams_t; diff --git a/src/event/quic/ngx_event_quic_ssl.c b/src/event/quic/ngx_event_quic_ssl.c --- a/src/event/quic/ngx_event_quic_ssl.c +++ b/src/event/quic/ngx_event_quic_ssl.c @@ -361,6 +361,7 @@ static ngx_int_t ngx_quic_crypto_input(ngx_connection_t *c, ngx_chain_t *data) { int n, sslerr; + ngx_int_t rc; ngx_buf_t *b; ngx_chain_t *cl; ngx_ssl_conn_t *ssl_conn; @@ -462,6 +463,19 @@ ngx_quic_crypto_input(ngx_connection_t * return NGX_ERROR; } + rc = ngx_ssl_ocsp_validate(c); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + c->ssl->handler = ngx_quic_init_streams; + return NGX_OK; + } + + ngx_quic_init_streams(c); + return NGX_OK; } diff --git a/src/event/quic/ngx_event_quic_streams.c b/src/event/quic/ngx_event_quic_streams.c --- a/src/event/quic/ngx_event_quic_streams.c +++ b/src/event/quic/ngx_event_quic_streams.c @@ -15,8 +15,10 @@ static ngx_quic_stream_t *ngx_quic_create_client_stream(ngx_connection_t *c, uint64_t id); +static ngx_int_t ngx_quic_init_stream(ngx_quic_stream_t *qs); static ngx_quic_stream_t *ngx_quic_create_stream(ngx_connection_t *c, uint64_t id); +static void ngx_quic_empty_handler(ngx_event_t *ev); static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size); static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, @@ -146,6 +148,8 @@ ngx_quic_find_stream(ngx_rbtree_t *rbtre ngx_int_t ngx_quic_close_streams(ngx_connection_t *c, ngx_quic_connection_t *qc) { + ngx_pool_t *pool; + ngx_queue_t *q; ngx_event_t *rev, *wev; ngx_rbtree_t *tree; ngx_rbtree_node_t *node; @@ -155,6 +159,17 @@ ngx_quic_close_streams(ngx_connection_t ngx_uint_t ns; #endif + while (!ngx_queue_empty(&qc->streams.uninitialized)) { + q = ngx_queue_head(&qc->streams.uninitialized); + ngx_queue_remove(q); + + qs = ngx_queue_data(q, ngx_quic_stream_t, queue); + pool = qs->connection->pool; + + ngx_close_connection(qs->connection); + ngx_destroy_pool(pool); + } + tree = &qc->streams.tree; if (tree->root == tree->sentinel) { @@ -310,7 +325,9 @@ ngx_quic_create_client_stream(ngx_connec return NULL; } - qs->connection->listening->handler(qs->connection); + if (ngx_quic_init_stream(qs) != NGX_OK) { + return NULL; + } if (qc->shutdown) { return NGX_QUIC_STREAM_GONE; @@ -321,6 +338,59 @@ ngx_quic_create_client_stream(ngx_connec } +static ngx_int_t +ngx_quic_init_stream(ngx_quic_stream_t *qs) +{ + ngx_connection_t *c; + ngx_quic_connection_t *qc; + + qc = ngx_quic_get_connection(qs->parent); + + c = qs->connection; + + if (!qc->streams.initialized) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "quic postpone stream init"); + + ngx_queue_insert_tail(&qc->streams.uninitialized, &qs->queue); + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic init stream"); + + c->listening->handler(c); + + return NGX_OK; +} + + +void +ngx_quic_init_streams(ngx_connection_t *c) +{ + ngx_queue_t *q; + ngx_quic_stream_t *qs; + ngx_quic_connection_t *qc; + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic init streams"); + + qc = ngx_quic_get_connection(c); + + while (!ngx_queue_empty(&qc->streams.uninitialized)) { + q = ngx_queue_head(&qc->streams.uninitialized); + ngx_queue_remove(q); + + qs = ngx_queue_data(q, ngx_quic_stream_t, queue); + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, qs->connection->log, 0, + "quic init postponed stream"); + + qs->connection->listening->handler(qs->connection); + } + + qc->streams.initialized = 1; +} + + static ngx_quic_stream_t * ngx_quic_create_stream(ngx_connection_t *c, uint64_t id) { @@ -387,6 +457,9 @@ ngx_quic_create_stream(ngx_connection_t sc->read->log = log; sc->write->log = log; + sc->read->handler = ngx_quic_empty_handler; + sc->write->handler = ngx_quic_empty_handler; + log->connection = sc->number; if ((id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0 @@ -432,6 +505,12 @@ ngx_quic_create_stream(ngx_connection_t } +static void +ngx_quic_empty_handler(ngx_event_t *ev) +{ +} + + static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, size_t size) { @@ -832,9 +911,7 @@ ngx_quic_handle_stream_frame(ngx_connect goto cleanup; } - sc->listening->handler(sc); - - return NGX_OK; + return ngx_quic_init_stream(qs); } sc = qs->connection; @@ -986,7 +1063,9 @@ ngx_quic_handle_stream_data_blocked_fram limit = qs->recv_max_data; - qs->connection->listening->handler(qs->connection); + if (ngx_quic_init_stream(qs) != NGX_OK) { + return NGX_ERROR; + } } else { limit = qs->recv_max_data; @@ -1043,9 +1122,7 @@ ngx_quic_handle_max_stream_data_frame(ng qs->send_max_data = f->limit; } - qs->connection->listening->handler(qs->connection); - - return NGX_OK; + return ngx_quic_init_stream(qs); } if (f->limit <= qs->send_max_data) { @@ -1117,9 +1194,7 @@ ngx_quic_handle_reset_stream_frame(ngx_c goto cleanup; } - sc->listening->handler(sc); - - return NGX_OK; + return ngx_quic_init_stream(qs); } sc = qs->connection; @@ -1202,9 +1277,7 @@ ngx_quic_handle_stop_sending_frame(ngx_c wev->error = 1; wev->ready = 1; - sc->listening->handler(sc); - - return NGX_OK; + return ngx_quic_init_stream(qs); } wev = qs->connection->write; diff --git a/src/event/quic/ngx_event_quic_streams.h b/src/event/quic/ngx_event_quic_streams.h --- a/src/event/quic/ngx_event_quic_streams.h +++ b/src/event/quic/ngx_event_quic_streams.h @@ -31,6 +31,7 @@ ngx_int_t ngx_quic_handle_stop_sending_f ngx_int_t ngx_quic_handle_max_streams_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, ngx_quic_max_streams_frame_t *f); +void ngx_quic_init_streams(ngx_connection_t *c); void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); ngx_quic_stream_t *ngx_quic_find_stream(ngx_rbtree_t *rbtree,