xref: /openssl/doc/designs/quic-design/quic-tls.md (revision 88113f5d)
1QUIC-TLS Handshake Integration
2==============================
3
4QUIC reuses the TLS handshake for the establishment of keys. It does not use
5the standard TLS record layer and instead assumes responsibility for the
6confidentiality and integrity of QUIC packets itself. Only the TLS handshake is
7used. Application data is entirely protected by QUIC.
8
9QUIC_TLS Object
10---------------
11
12A QUIC-TLS handshake is managed by a QUIC_TLS object. This object provides
133 core functions to the rest of the QUIC implementation:
14
15```c
16QUIC_TLS *ossl_quic_tls_new(const QUIC_TLS_ARGS *args);
17```
18
19The `ossl_quic_tls_new` function instantiates a new `QUIC_TLS` object associated
20with the QUIC Connection and initialises it with a set of callbacks and other
21arguments provided in the `args` parameter. These callbacks are called at
22various key points during the handshake lifecycle such as when new keys are
23established, crypto frame data is ready to be sent or consumed, or when the
24handshake is complete.
25
26A key field of the `args` structure is the `SSL` object (`s`). This "inner"
27`SSL` object is initialised with an `SSL_CONNECTION` to represent the TLS
28handshake state. This is a different `SSL` object to the "user" visible `SSL`
29object which contains a `QUIC_CONNECTION`, i.e. the user visible `SSL` object
30contains a `QUIC_CONNECTION` which contains the inner `SSL` object which
31contains an `SSL_CONNECTION`.
32
33```c
34void ossl_quic_tls_free(QUIC_TLS *qtls);
35```
36
37When the QUIC Connection no longer needs the handshake object it can be freed
38via the `ossl_quic_tls_free` function.
39
40```c
41int ossl_quic_tls_tick(QUIC_TLS *qtls);
42```
43
44Finally the `ossl_quic_tls_tick` function is responsible for advancing the
45state of the QUIC-TLS handshake. On each call to `ossl_quic_tls_tick` newly
46received crypto frame data may be consumed, or new crypto frame data may be
47queued for sending, or one or more of the various callbacks may be invoked.
48
49QUIC_TLS_ARGS
50-------------
51
52A `QUIC_TLS_ARGS` object is passed to the `ossl_quic_tls_new` function by the
53OpenSSL QUIC implementation to supply a set of callbacks and other essential
54parameters. The `QUIC_TLS_ARGS` structure is as follows:
55
56```c
57typedef struct quic_tls_args_st {
58    /*
59     * The "inner" SSL object for the QUIC Connection. Contains an
60     * SSL_CONNECTION
61     */
62    SSL *s;
63
64    /*
65     * Called to send data on the crypto stream. We use a callback rather than
66     * passing the crypto stream QUIC_SSTREAM directly because this lets the CSM
67     * dynamically select the correct outgoing crypto stream based on the
68     * current EL.
69     */
70    int (*crypto_send_cb)(const unsigned char *buf, size_t buf_len,
71                          size_t *consumed, void *arg);
72    void *crypto_send_cb_arg;
73    int (*crypto_recv_cb)(unsigned char *buf, size_t buf_len,
74                          size_t *bytes_read, void *arg);
75    void *crypto_recv_cb_arg;
76
77    /* Called when a traffic secret is available for a given encryption level. */
78    int (*yield_secret_cb)(uint32_t enc_level, int direction /* 0=RX, 1=TX */,
79                           uint32_t suite_id, EVP_MD *md,
80                           const unsigned char *secret, size_t secret_len,
81                           void *arg);
82    void *yield_secret_cb_arg;
83
84    /*
85     * Called when we receive transport parameters from the peer.
86     *
87     * Note: These parameters are not authenticated until the handshake is
88     * marked as completed.
89     */
90    int (*got_transport_params_cb)(const unsigned char *params,
91                                   size_t params_len,
92                                   void *arg);
93    void *got_transport_params_cb_arg;
94
95    /*
96     * Called when the handshake has been completed as far as the handshake
97     * protocol is concerned, meaning that the connection has been
98     * authenticated.
99     */
100    int (*handshake_complete_cb)(void *arg);
101    void *handshake_complete_cb_arg;
102
103    /*
104     * Called when something has gone wrong with the connection as far as the
105     * handshake layer is concerned, meaning that it should be immediately torn
106     * down. Note that this may happen at any time, including after a connection
107     * has been fully established.
108     */
109    int (*alert_cb)(void *arg, unsigned char alert_code);
110    void *alert_cb_arg;
111
112    /*
113     * Transport parameters which client should send. Buffer lifetime must
114     * exceed the lifetime of the QUIC_TLS object.
115     */
116    const unsigned char *transport_params;
117    size_t transport_params_len;
118} QUIC_TLS_ARGS;
119```
120
121The `crypto_send_cb` and `crypto_recv_cb` callbacks will be called by the
122QUIC-TLS handshake when there is new CRYPTO frame data to be sent, or when it
123wants to consume queued CRYPTO frame data from the peer.
124
125When the TLS handshake generates secrets they will be communicated to the
126OpenSSL QUIC implementation via the `yield_secret_cb`, and when the handshake
127has successfully completed this will be communicated via `handshake_complete_cb`.
128
129In the event that an error occurs a normal TLS handshake would send a TLS alert
130record. QUIC handles this differently and so the QUIC_TLS object will intercept
131attempts to send an alert and will communicate this via the `alert_cb` callback.
132
133QUIC requires the use of a TLS extension in order to send and receive "transport
134parameters". These transport parameters are opaque to the `QUIC_TLS` object. It
135does not need to use them directly but instead simply includes them in an
136extension to be sent in the ClientHello and receives them back from the peer in
137the EncryptedExtensions message. The data to be sent is provided in the
138`transport_params` argument. When the peer's parameters are received the
139`got_transport_params_cb` callback is invoked.
140
141QUIC_TLS Implementation
142-----------------------
143
144The `QUIC_TLS` object utilises two main mechanisms for fulfilling its functions:
145
146* It registers itself as a custom TLS record layer
147* It supplies callbacks to register a custom TLS extension
148
149### Custom TLS Record Layer
150
151A TLS record layer is defined via an `OSSL_RECORD_METHOD` object. This object
152consists of a set of function pointers which need to be implemented by any
153record layer. Existing record layers include one for TLS, one for DTLS and one
154for KTLS.
155
156`QUIC_TLS` registers itself as a custom TLS record layer. A new internal
157function is used to provide the custom record method data and associate it with
158an `SSL_CONNECTION`:
159
160```C
161void ossl_ssl_set_custom_record_layer(SSL_CONNECTION *s,
162                                      const OSSL_RECORD_METHOD *meth,
163                                      void *rlarg);
164```
165
166The internal function `ssl_select_next_record_layer` which is used in the TLS
167implementation to work out which record method should be used next is modified
168to first check whether a custom record method has been specified and always use
169that one if so.
170
171The TLS record layer code is further modified to provide the following
172capabilities which are needed in order to support QUIC.
173
174The custom record layer will need a record layer specific argument (`rlarg`
175above). This is passed as part of a modified `new_record_layer` call.
176
177Existing TLS record layers use TLS keys and IVs that are calculated using a
178KDF from a higher level secret. Instead of this QUIC needs direct access to the
179higher level secret as well as the digest to be used in the KDF - so these
180values are now also passed through as part of the `new_record_layer` call.
181
182The most important function pointers in the `OSSL_RECORD_METHOD` for the
183`QUIC_TLS` object are:
184
185* `new_record_layer`
186
187Invoked every time a new record layer object is created by the TLS
188implementation. This occurs every time new keys are provisioned (once for the
189"read" side and once for the "write" side). This function is responsible for
190invoking the `yield_secret_cb` callback.
191
192* `write_records`
193
194Invoked every time the TLS implementation wants to send TLS handshake data. This
195is responsible for calling the `crypto_send_cb` callback. It also includes
196special processing in the event that the TLS implementation wants to send an
197alert. This manifests itself as a call to `write_records` indicating a type of
198`SSL3_RT_ALERT`. The `QUIC_TLS` implementation of `write_records` must parse the
199alert data supplied by the TLS implementation (always a 2 byte record payload)
200and pull out the alert description (a one byte integer) and invoke the
201`alert_cb` callback. Note that while the TLS RFC strictly allows the 2 byte
202alert record to be fragmented across two 1 byte records this is never done in
203practice by OpenSSL's TLS stack and the `write_records` implementation can make
204the optimising assumption that both bytes of an alert are always sent together.
205
206* `quic_read_record`
207
208Invoked when the TLS implementation wants to read more handshake data. This
209results in a call to `crypto_recv_cb`.
210
211This design does introduce an extra "copy" in the process when `crypto_recv_cb`
212is invoked. CRYPTO frame data will be queued within internal QUIC "Stream
213Receive Buffers" when it is received by the peer. However the TLS implementation
214expects to request data from the record layer, get a handle on that data, and
215then inform the record layer when it has finished using that data. The current
216design of the Stream Receive Buffers does not allow for this model. Therefore
217when `crypto_recv_cb` is invoked the data is copied into a QUIC_TLS object
218managed buffer. This is inefficient, so it is expected that a later phase of
219development will resolve this problem.
220
221### Custom TLS extension
222
223Libssl already has the ability for an application to supply a custom extension
224via the `SSL_CTX_add_custom_ext()` API. There is no equivalent
225`SSL_add_custom_ext()` and therefore an internal API is used to do this. This
226mechanism is used for supporting QUIC transport parameters. An extension
227type `TLSEXT_TYPE_quic_transport_parameters` with value 57 is used for this
228purpose.
229
230The custom extension API enables the caller to supply `add`, `free` and `parse`
231callbacks. The `add` callback simply adds the `transport_params` data from
232`QUIC_TLS_ARGS`. The `parse` callback invokes the `got_transport_params_cb`
233callback when the transport parameters have been received from the peer.
234
235### ALPN
236
237QUIC requires the use of ALPN (Application-Layer Protocol Negotiation). This is
238normally optional in OpenSSL but is mandatory for QUIC connections. Therefore
239a QUIC client must call one of `SSL_CTX_set_alpn_protos` or
240`SSL_set_alpn_protos` prior to initiating the handshake. If the ALPN data has
241not been set then the `QUIC_TLS` object immediately fails.
242
243### Other Implementation Details
244
245The `SSL_CONNECTION` used for the TLS handshake is held alongside the QUIC
246related data in the `SSL` object. Public API functions that are only relevant to
247TLS will modify this internal `SSL_CONNECTION` as appropriate. This enables the
248end application to configure the TLS connection parameters as it sees fit (e.g.
249setting ciphersuites, providing client certificates, etc). However there are
250certain settings that may be optional in a normal TLS connection but are
251mandatory for QUIC. Where possible these settings will be automatically
252configured just before the handshake starts.
253
254One of these settings is the minimum TLS protocol version. QUIC requires that
255TLSv1.3 is used as a minimum. Therefore the `QUIC_TLS` object automatically
256calls `SSL_set_min_proto_version()` and specifies `TLS1_3_VERSION` as the
257minimum version.
258
259Secondly, QUIC enforces that the TLS "middlebox" mode must not be used. For
260normal TLS this is "on" by default. Therefore the `QUIC_TLS` object will
261automatically clear the `SSL_OP_ENABLE_MIDDLEBOX_COMPAT` option if it is set.
262