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