Commit Graph

168 Commits

Author SHA1 Message Date
Vladimir Homutov
001b81af88 Free remaining frames on connection close.
Frames can still float in the following queues:

 - crypto frames reordering queues (one per encryption level)
 - moved crypto frames cleanup to the moment where all streams are closed
 - stream frames reordering queues (one per packet number namespace)
 - frames retransmit queues (one per packet number namespace)
2020-04-15 13:09:39 +03:00
Vladimir Homutov
53d47318c5 Sorted functions and functions declarations. 2020-04-14 16:30:41 +03:00
Vladimir Homutov
9542c975b7 Added reordering support for STREAM frames.
Each stream node now includes incoming frames queue and sent/received counters
for tracking offset. The sent counter is not used, c->sent is used, not like
in crypto buffers, which have no connections.
2020-04-15 11:11:54 +03:00
Vladimir Homutov
081682cd3c Crypto buffer frames reordering.
If offset in CRYPTO frame doesn't match expected, following actions are taken:
    a) Duplicate frames or frames within [0...current offset] are ignored
    b) New data from intersecting ranges (starts before current_offset, ends
       after) is consumed
    c) "Future" frames are stored in a sorted queue (min offset .. max offset)

Once a frame is consumed, current offset is updated and the queue is inspected:
    we iterate the queue until the gap is found and act as described
    above for each frame.

The amount of data in buffered frames is limited by corresponding macro.

The CRYPTO and STREAM frame structures are now compatible: they share
the same set of initial fields.  This allows to have code that deals with
both of this frames.

The ordering layer now processes the frame with offset and invokes the
handler when it can organise an ordered stream of data.
2020-04-14 12:16:25 +03:00
Vladimir Homutov
76e99f668d Cleaned up magic numbers in ngx_quic_output_frames(). 2020-04-13 14:57:58 +03:00
Vladimir Homutov
fbf6494f5f Rename types and variables used for packet number space.
Quote: Conceptually, a packet number space is the context in which a packet
       can be processed and acknowledged.

ngx_quic_namespace_t => ngx_quic_send_ctx_t
qc->ns               => qc->send_ctx
ns->largest          => send_ctx->largest_ack

The ngx_quic_ns(level) macro now returns pointer, not just index:
    ngx_quic_get_send_ctx(c->quic, level)

ngx_quic_retransmit_ns() => ngx_quic_retransmit()
ngx_quic_output_ns() => ngx_quic_output_frames()
2020-04-14 12:06:32 +03:00
Vladimir Homutov
c64a3939e4 Added basic offset support in client CRYPTO frames.
The offset in client CRYPTO frames is tracked in c->quic->crypto_offset_in.
This means that CRYPTO frames with non-zero offset are now accepted making
possible to finish handshake with client certificates that exceed max packet
size (if no reordering happens).

The c->quic->crypto_offset field is renamed to crypto_offset_out to avoid
confusion with tracking of incoming CRYPTO stream.
2020-04-07 15:50:38 +03:00
Sergey Kandaurov
f540602ad2 Fixed build with OpenSSL using old callbacks API. 2020-04-07 12:54:34 +03:00
Vladimir Homutov
35878c3796 ACK ranges processing.
+ since number of ranges in unknown, provide a function to parse them once
   again in handler to avoid memory allocation

 + ack handler now processes all ranges, not only the first

 + ECN counters are parsed and saved into frame if present
2020-04-06 16:19:26 +03:00
Vladimir Homutov
1c9ddadd76 Ignore non-yet-implemented frames.
Such frames are grouped together in a switch and just ignored, instead of
closing the connection  This may improve test coverage.  All such frames
require acknowledgment.
2020-04-06 11:16:45 +03:00
Vladimir Homutov
5b41275219 Do not set timers after the connection is closed.
The qc->closing flag is set when a connection close is initiated for the first
time.

No timers will be set if the flag is active.

TODO: this is a temporary solution to avoid running timer handlers after
connection (and it's pool) was destroyed.  It looks like currently we have
no clear policy of connection closing in regard to timers.
2020-04-04 22:27:29 +03:00
Sergey Kandaurov
3f3315aea6 Discarding Handshake packets if no Handshake keys yet.
Found with a previously received Initial packet with ACK only, which
instantiates a new connection but do not produce the handshake keys.

This can be triggered by a fairly well behaving client, if the server
stands behind a load balancer that stripped Initial packets exchange.

Found by F5 test suite.
2020-04-06 14:54:10 +03:00
Sergey Kandaurov
cc704a8c31 Rejecting new connections with non-zero Initial packet. 2020-04-06 14:54:10 +03:00
Sergey Kandaurov
1381982aaa TLS Key Update in QUIC.
Old keys retention is yet to be implemented.
2020-04-06 14:54:08 +03:00
Vladimir Homutov
4cfc98c63f Removed unneccesary milliseconds conversion. 2020-04-03 16:33:59 +03:00
Vladimir Homutov
b3300b5220 Proper handling of packet number in header.
- fixed setting of largest received packet number.
 - sending properly truncated packet number
 - added support for multi-byte packet number
2020-04-03 14:02:16 +03:00
Sergey Kandaurov
b4719e8ea4 Advertizing MAX_STREAMS (0x12) credit in advance.
This makes sending large number of bidirectional stream work within ngtcp2,
which doesn't bother sending optional STREAMS_BLOCKED when exhausted.

This also introduces tracking currently opened and maximum allowed streams.
2020-04-03 13:49:44 +03:00
Vladimir Homutov
723c276a7b Fixed missing propagation of need_ack flag from frames to packet. 2020-04-03 09:53:51 +03:00
Vladimir Homutov
932bfe7b36 Fixed excessive push timer firing.
The timer is set when an output frame is generated; there is no need to arm
it after it was fired.
2020-04-02 14:53:01 +03:00
Vladimir Homutov
01bddf4533 Output buffering.
Currently, the output is called periodically, each 200 ms to invoke
ngx_quic_output() that will push all pending frames into packets.

TODO: implement flags a-là Nagle & co (NO_DELAY/NO_PUSH...)
2020-04-01 17:09:11 +03:00
Vladimir Homutov
7b1a3df37c Implemented retransmission and retransmit queue.
All frames collected to packet are moved into a per-namespace send queue.
QUIC connection has a timer which fires on the closest max_ack_delay time.
The frame is deleted from the queue when a corresponding packet is acknowledged.

The NGX_QUIC_MAX_RETRANSMISSION is a timeout that defines maximum length
of retransmission of a frame.
2020-04-01 17:06:26 +03:00
Vladimir Homutov
d7eeb2e30b Introduced packet namespace in QUIC connection.
The structure contains all data that is related to the namespace:
packet number and output queue (next patch).
2020-04-01 14:31:08 +03:00
Vladimir Homutov
9595417396 Refactored QUIC secrets storage.
The quic->keys[4] array now contains secrets related to the corresponding
encryption level.  All protection-level functions get proper keys and do
not need to switch manually between levels.
2020-04-01 14:25:25 +03:00
Vladimir Homutov
c6859361e3 Added missing debug description. 2020-04-01 17:21:52 +03:00
Sergey Kandaurov
6abff71fc4 TLS Early Data support. 2020-04-01 13:27:42 +03:00
Sergey Kandaurov
140a89ce01 TLS Early Data key derivation support. 2020-04-01 13:27:42 +03:00
Sergey Kandaurov
22671b37e3 Sending HANDSHAKE_DONE just once with BoringSSL.
If early data is accepted, SSL_do_handshake() completes as soon as ClientHello
is processed.  SSL_in_init() will report the handshake is still in progress.
2020-04-01 13:27:42 +03:00
Sergey Kandaurov
833a28244f QUIC packet padding to fulfil header protection sample demands. 2020-04-01 13:27:42 +03:00
Sergey Kandaurov
e9d67086c7 Improved SSL_do_handshake() error handling in QUIC.
It can either return a recoverable SSL_ERROR_WANT_READ or fatal errors.
2020-04-01 13:27:42 +03:00
Sergey Kandaurov
86029005a5 Style. 2020-04-01 13:27:41 +03:00
Roman Arutyunyan
84a7835015 Fixed handling QUIC stream eof.
Set r->pending_eof flag for a new QUIC stream with the fin bit.  Also, keep
r->ready set when r->pending_eof is set and buffer is empty.
2020-03-27 10:02:45 +03:00
Roman Arutyunyan
89a6a4f198 Push QUIC stream frames in send() and cleanup handler. 2020-03-27 19:08:24 +03:00
Sergey Kandaurov
3fbdc04072 Unbreak sending CONNECTION_CLOSE from the send_alert callback. 2020-03-27 12:52:08 +03:00
Vladimir Homutov
41a8b8d392 Merged ngx_quic_send_packet() into ngx_quic_send_frames().
This allows to avoid extra allocation and use two static buffers instead.
Adjusted maximum paket size calculation: need to account a tag.
2020-03-26 18:29:38 +03:00
Vladimir Homutov
7d408f1bba Got rid of memory allocation in decryption.
Static buffers are used instead in functions where decryption takes place.

The pkt->plaintext points to the beginning of a static buffer.
The pkt->payload.data points to decrypted data actual start.
2020-03-26 16:54:46 +03:00
Roman Arutyunyan
d71df64e9a QUIC frames reuse. 2020-03-25 23:40:50 +03:00
Vladimir Homutov
715d8a250b Removed memory allocations from encryption code.
+ ngx_quic_encrypt():
     - no longer accepts pool as argument
     - pkt is 1st arg
     - payload is passed as pkt->payload
     - performs encryption to the specified static buffer

 + ngx_quic_create_long/short_packet() functions:
    - single buffer for everything, allocated by caller
    - buffer layout is: [ ad | payload | TAG ]
      the result is in the beginning of buffer with proper length
    - nonce is calculated on stack
    - log is passed explicitly, pkt is 1st arg
    - no more allocations inside

 + ngx_quic_create_long_header():
    - args changed: no need to pass str_t

 + added ngx_quic_create_short_header()
2020-03-26 12:11:50 +03:00
Roman Arutyunyan
bcd54c2643 Fixed QUIC stream insert and find. 2020-03-25 14:05:40 +03:00
Roman Arutyunyan
95f439630b Safe QUIC stream creation. 2020-03-25 12:56:21 +03:00
Roman Arutyunyan
a0a2e0de1d When closing a QUIC connection, wait for all streams to finish.
Additionally, streams are now removed from the tree in cleanup handler.
2020-03-24 18:05:45 +03:00
Roman Arutyunyan
f75e4e3fef Removed ngx_quic_stream_node_t.
Now ngx_quic_stream_t is directly inserted into the tree.
2020-03-24 16:38:03 +03:00
Roman Arutyunyan
061a42d966 Implemented eof in QUIC streams. 2020-03-24 13:49:42 +03:00
Vladimir Homutov
c5505648d7 Fixed log initialization.
Should be done after memzero.
2020-03-25 19:42:00 +03:00
Vladimir Homutov
8c26e1d148 Logging cleanup.
+ Client-related errors (i.e. parsing) are done at INFO level
 + c->log->action is updated through the process of receiving, parsing.
   handling packet/payload and generating frames/output.
2020-03-24 17:03:39 +03:00
Vladimir Homutov
780f4f660c Added QUIC version check for sending HANDSHAKE_DONE frame. 2020-03-24 12:15:39 +03:00
Vladimir Homutov
57544f7589 Implemented sending HANDSHAKE_DONE frame after handshake.
This makes it possible to switch to draft 27 by default.
2020-03-24 11:59:14 +03:00
Sergey Kandaurov
f20af3dabc Fixed client certificate verification.
For ngx_http_process_request() part to work, this required to set both
r->http_connection->ssl and c->ssl on a QUIC stream.  To avoid damaging
global SSL object, ngx_ssl_shutdown() is managed to ignore QUIC streams.
2020-03-23 20:48:34 +03:00
Roman Arutyunyan
5ac5e51fdf Respect QUIC max_idle_timeout. 2020-03-23 21:20:20 +03:00
Roman Arutyunyan
9975b088bb Allow ngx_queue_frame() to insert frame in the front.
Previously a frame could only be inserted after the first element of the list.
2020-03-23 19:42:09 +03:00
Roman Arutyunyan
f4562d7ed9 Avoid using QUIC connection after CONNECTION_CLOSE. 2020-03-23 19:19:44 +03:00
Roman Arutyunyan
3fa1dec9c7 Better flow control and buffering for QUIC streams. 2020-03-23 15:49:31 +03:00
Roman Arutyunyan
72b0a1b32a Limit output QUIC packets with client max_packet_size.
Additionally, receive larger packets than 512 bytes.
2020-03-23 18:47:17 +03:00
Vladimir Homutov
5018d9eecc Connection states code cleanup.
+ ngx_quic_init_ssl_methods() is no longer there, we setup methods on SSL
   connection directly.

 + the handshake_handler is actually a generic quic input handler

 + updated c->log->action and debug to reflect changes and be more informative

 + c->quic is always set in ngx_quic_input()

 + the quic connection state is set by the results of SSL_do_handshake();
2020-03-23 14:53:04 +03:00
Vladimir Homutov
4490aefa70 Added processing of client transport parameters.
note:
 + parameters are available in SSL connection since they are obtained by ssl
   stack

quote:
   During connection establishment, both endpoints make authenticated
   declarations of their transport parameters.  These declarations are
   made unilaterally by each endpoint.

and really, we send our parameters before we read client's.

no handling of incoming parameters is made by this patch.
2020-03-21 20:51:59 +03:00
Sergey Kandaurov
de095d5f1d Fixed CRYPTO offset generation. 2020-03-22 12:15:54 +03:00
Sergey Kandaurov
ccb0049e3f Closing connection on NGX_QUIC_FT_CONNECTION_CLOSE. 2020-03-22 11:35:15 +03:00
Vladimir Homutov
b26d5deae4 Removed unused variable. 2020-03-20 20:39:41 +03:00
Vladimir Homutov
21b6854bfe Added checks for permitted frame types.
+ cleanup in macros for packet types
 + some style fixes in quic_transport.h (case, indentation)
2020-03-20 20:03:44 +03:00
Vladimir Homutov
30de0ca52d Configurable transport parameters.
- integer parameters can be configured using the following directives:

    quic_max_idle_timeout
    quic_max_ack_delay
    quic_max_packet_size
    quic_initial_max_data
    quic_initial_max_stream_data_bidi_local
    quic_initial_max_stream_data_bidi_remote
    quic_initial_max_stream_data_uni
    quic_initial_max_streams_bidi
    quic_initial_max_streams_uni
    quic_ack_delay_exponent
    quic_active_migration
    quic_active_connection_id_limit

 - only following parameters are actually sent:

    active_connection_id_limit
    initial_max_streams_uni
    initial_max_streams_bidi
    initial_max_stream_data_bidi_local
    initial_max_stream_data_bidi_remote
    initial_max_stream_data_uni

 (other parameters are to be added into ngx_quic_create_transport_params()
  function as needed, should be easy now)

 - draft 24 and draft 27 are now supported
   (at compile-time using quic_version macro)
2020-03-20 13:47:44 +03:00
Roman Arutyunyan
5f9b188c21 Reset QUIC timeout on every datagram. 2020-03-19 21:46:28 +03:00
Roman Arutyunyan
3ba0d03a6e Double MAX_STREAMS on STREAMS_BLOCKED. 2020-03-20 10:14:58 +03:00
Vladimir Homutov
1b4b8af624 The ngx_quic_frame_len() function is not really needed. 2020-03-19 14:59:55 +03:00
Vladimir Homutov
18ce6d5ebf Added boundaries checks into frame parser.
The ngx_quic_parse_frame() functions now has new 'pkt' argument: the packet
header of a currently processed frame.  This allows to log errors/debug
closer to reasons and perform additional checks regarding possible frame
types.  The handler only performs processing of good frames.


A number of functions like read_uint32(), parse_int[_multi] probably should
be implemented as a macro, but currently it is better to have them as
functions for simpler debugging.
2020-03-19 17:07:12 +03:00
Roman Arutyunyan
4cbfc07394 Send a FIN frame when QUIC stream is closed. 2020-03-19 15:34:35 +03:00
Sergey Kandaurov
31e794f0ad MAX_DATA frame parser/handler. 2020-03-18 23:26:26 +03:00
Vladimir Homutov
33d8317dd5 Added parsing of STREAMS BLOCKED frames.
While there, added hex prefix for debug to avoid frame type confusion.
2020-03-19 11:15:43 +03:00
Sergey Kandaurov
6aa611c314 Implemented send_alert callback, CONNECTION_CLOSE writer.
The callback produces a CONNECTION_CLOSE frame, as per quic-tls-24#section-4.9.
2020-03-18 23:07:40 +03:00
Roman Arutyunyan
0561665873 Added copying addr_text to QUIC stream connections.
Now $remote_addr holds client address.
2020-03-18 20:28:28 +03:00
Roman Arutyunyan
5aa8e519c9 Moved setting QUIC methods to runtime.
This allows listening to both https and http3 in the same server.
Also, the change eliminates the ssl_quic directive.
2020-03-18 16:37:16 +03:00
Vladimir Homutov
50f919cec4 Added parsing of RESET_STREAM and STOP_SENDING frames 2020-03-18 16:35:11 +03:00
Vladimir Homutov
2973465556 Implemented creation of server unidirectional streams.
The ngx_quic_create_stream() function is a generic function extracted from
the ngx_quic_handle_stream_frame() function.
2020-03-18 13:49:39 +03:00
Vladimir Homutov
023dbc3cfb Style and handlers.
Cleanup in ngx_event_quic.c:
    + reorderded functions, structures
    + added missing prototypes
    + added separate handlers for each frame type
    + numerous indentation/comments/TODO fixes
    + removed non-implemented qc->state and corresponding enum;
        this requires deep thinking, stub was unused.
    + streams inside quic connection are now in own structure
2020-03-18 13:02:19 +03:00
Vladimir Homutov
23dc6a68a4 Extracted transport part of the code into separate file.
All code dealing with serializing/deserializing
is moved int srv/event/ngx_event_quic_transport.c/h file.

All macros for dealing with data are internal to source file.

The header file exposes frame types and error codes.

The exported functions are currently packet header parsers and writers
and frames parser/writer.

The ngx_quic_header_t structure is updated with 'log' member. This avoids
passing extra argument to parsing functions that need to report errors.
2020-03-18 12:58:27 +03:00
Vladimir Homutov
cd54c1cab7 Firefox fixes.
+ support for more than one initial packet
 + workaround for trailing zeroes in packet
 + ignore application data packet if no keys yet (issue in draft 27/ff nightly)
 + fixed PING frame parser
 + STREAM frames need to be acknowledged

The following HTTP configuration is used for firefox (v74):

http {

    ssl_certificate_key localhost.key;
    ssl_certificate localhost.crt;
    ssl_protocols TLSv1.2 TLSv1.3;

    server {
        listen 127.0.0.1:10368 reuseport http3;
        ssl_quic on;
        server_name  localhost;

        location / {
            return 200 "This-is-QUICK\n";
        }
    }
    server {
        listen 127.0.0.1:5555 ssl; # point the browser here
        server_name  localhost;
        location / {
            add_header Alt-Svc 'h3-24=":10368";ma=100';
            return 200 "ALT-SVC";
        }
    }
}
2020-03-17 14:10:37 +03:00
Vladimir Homutov
ca7943393e Fixed a typo with OpenSSL. 2020-03-16 19:42:57 +03:00
Vladimir Homutov
d0ebfa4cb9 Split transport and crypto parts into separate files.
New files:
    src/event/ngx_event_quic_protection.h
    src/event/ngx_event_quic_protection.c

The protection.h header provides interface to the crypto part of the QUIC:

2 functions to initialize corresponding secrets:

ngx_quic_set_initial_secret()
ngx_quic_set_encryption_secret()

and 2 functions to deal with packet processing:

ngx_quic_encrypt()
ngx_quic_decrypt()

Also, structures representing secrets are defined there.

All functions require SSL connection and a pool, only crypto operations
inside, no access to nginx connections or events.

Currently pool->log is used for the logging (instead of original c->log).
2020-03-16 19:00:47 +03:00
Vladimir Homutov
0d8984083b Added processing of CONNECTION CLOSE frames.
Contents is parsed and debug is output. No actions are taken.
2020-03-16 13:06:43 +03:00
Sergey Kandaurov
1ac31c01b4 Fixed header protection application with pn length > 1. 2020-03-14 03:15:09 +03:00
Roman Arutyunyan
11dfc1c943 Fixed sanitizer errors. 2020-03-13 20:44:32 +03:00
Vladimir Homutov
8f35d300ed Added check for initialized c->ssl before calling SSL shutdown. 2020-03-13 18:55:58 +03:00
Roman Arutyunyan
7739b6073b HTTP/3. 2020-03-13 19:36:33 +03:00
Roman Arutyunyan
365b77b587 Fixed infinite loop in ngx_quic_stream_send_chain(). 2020-03-13 18:30:37 +03:00
Roman Arutyunyan
a1ac82ca0f Implemented tracking offset in STREAM frames. 2020-03-13 18:29:50 +03:00
Roman Arutyunyan
dcb6aab460 Implemented ngx_quic_stream_send_chain() method.
- just call send in a loop
2020-03-13 15:56:10 +03:00
Vladimir Homutov
05d1464c68 Stream "connection" read/write methods. 2020-03-13 14:39:23 +03:00
Vladimir Homutov
21eaac9a3e Removed hardcoded CRYPTO and ACK frame sizes. 2020-03-12 14:23:27 +03:00
Vladimir Homutov
4f4f56f013 HTTP/QUIC interface reworked.
- events handling moved into src/event/ngx_event_quic.c
 - http invokes once ngx_quic_run() and passes stream callback
 (diff to original http_request.c is now minimal)

 - streams are stored in rbtree using ID as a key
 - when a new stream is registered, appropriate callback is called

 - ngx_quic_stream_t type represents STREAM and stored in c->qs
2020-03-12 16:54:43 +03:00
Vladimir Homutov
6bf6635d86 Initial parsing of STREAM frames. 2020-03-11 15:41:35 +03:00
Vladimir Homutov
0d10672137 Added support of multiple QUIC packets in single datagram.
- now NEW_CONNECTION_ID frames can be received and parsed

The packet structure is created in ngx_quic_input() and passed
to all handlers (initial, handshake and application data).

The UDP datagram buffer is saved as pkt->raw;
The QUIC packet is stored as pkt->data and pkt->len (instead of pkt->buf)
(pkt->len is adjusted after parsing headers to actual length)

The pkt->pos is removed, pkt->raw->pos is used instead.
2020-03-12 14:43:24 +03:00
Vladimir Homutov
0d1c27b580 Added more transport parameters.
Needed for client to start sending streams.
2020-03-11 15:43:23 +03:00
Sergey Kandaurov
9311e59443 Compatibility with BoringSSL revised QUIC encryption secret APIs.
See for details: https://boringssl.googlesource.com/boringssl/+/1e85905%5E!/
2020-03-11 21:53:02 +03:00
Sergey Kandaurov
df544ee47d Chacha20 header protection support with BoringSSL.
BoringSSL lacks EVP for Chacha20.  Here we use CRYPTO_chacha_20() instead.
2020-03-10 19:15:12 +03:00
Sergey Kandaurov
7e417544bb ChaCha20 / Poly1305 initial support. 2020-03-10 19:13:09 +03:00
Sergey Kandaurov
4b59999afe Using SSL cipher suite id to obtain cipher/digest, part 2.
Ciphers negotiation handling refactored into ngx_quic_ciphers().
2020-03-10 19:12:22 +03:00
Sergey Kandaurov
385408732e Fixed nonce in short packet protection. 2020-03-10 18:40:18 +03:00
Vladimir Homutov
c2afb5ec8a Generic payload handler for quic packets.
- added basic parsing of ACK, PING and PADDING frames on input
 - added preliminary parsing of SHORT headers

The ngx_quic_output() is now called after processing of each input packet.
Frames are added into output queue according to their level: inital packets
go ahead of handshake and application data, so they can be merged properly.

The payload handler is called from both new, handshake and applicataion data
handlers (latter is a stub).
2020-03-10 18:24:39 +03:00
Sergey Kandaurov
547a1a0159 Fixed header protection with negotiated cipher suite. 2020-03-05 20:05:40 +03:00
Sergey Kandaurov
ed0533c2c2 Initial packets are protected with AEAD_AES_128_GCM. 2020-03-05 19:49:49 +03:00
Sergey Kandaurov
b0f1302e7d Fixed write secret logging in set_encryption_secrets callback. 2020-03-05 18:01:18 +03:00
Vladimir Homutov
08691ef3d4 Fixed format specifiers. 2020-03-05 17:51:22 +03:00