changeset 8827:fe919fd63b0b quic

QUIC: client certificate validation with OCSP.
author Sergey Kandaurov <pluknet@nginx.com>
date Wed, 04 Aug 2021 15:49:18 +0300
parents c35b255d80dc
children a9f6540e61da
files src/event/quic/ngx_event_quic.c src/event/quic/ngx_event_quic.h src/event/quic/ngx_event_quic_connection.h src/event/quic/ngx_event_quic_ssl.c src/event/quic/ngx_event_quic_streams.c src/event/quic/ngx_event_quic_streams.h
diffstat 6 files changed, 109 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- 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;
 
--- 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;
--- 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;
 
 
--- 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;
 }
 
--- 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;
--- 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,