Line data Source code
1 : #ifndef HEADER_fd_src_waltz_quic_tls_fd_quic_tls_h 2 : #define HEADER_fd_src_waltz_quic_tls_fd_quic_tls_h 3 : 4 : #include "../fd_quic_common.h" 5 : #include "../fd_quic_enum.h" 6 : #include "../../tls/fd_tls.h" 7 : #include "../templ/fd_quic_transport_params.h" 8 : 9 : /* QUIC-TLS 10 : 11 : This defines an API for QUIC-TLS 12 : 13 : General operation: 14 : // seed a CSPRNG 15 : static fd_chacha_rng_t _rng[1]; 16 : fd_chacha_rng_t * rng = fd_chacha_rng_join( 17 : fd_chacha_rng_new( _rng, FD_CHACHA_RNG_MODE_SHIFT ) ); 18 : uchar key[ FD_CHACHA_KEY_SZ ]; 19 : if( FD_UNLIKELY( !fd_rng_secure( key, sizeof(key) ) ) ) abort(); 20 : fd_chacha_rng_init( rng, key, FD_CHACHA_RNG_ALGO_CHACHA8 ); 21 : fd_memzero_explicit( key, sizeof(key) ); 22 : 23 : // set up a quic-tls config object 24 : fd_quic_tls_cfg_t quic_tls_cfg = { 25 : .secret_cb = my_secret_cb, // callback for communicating secrets 26 : 27 : .handshake_complete_cb = my_hs_complete, // called when handshake is complete 28 : 29 : .max_concur_handshakes = 1234, // number of handshakes this object can 30 : // manage concurrently 31 : 32 : .rng = rng, // required, see above 33 : }; 34 : 35 : // create a quic-tls object to manage handshakes: 36 : fd_quic_tls_t * quic_tls = fd_quic_tls_new( quic_tls_cfg ); 37 : 38 : // delete a quic-tls object when it's not needed anymore 39 : fd_quic_delete( quic_tls ); 40 : 41 : // create a client or a server handshake object 42 : // call upon a new connection to manage the connection TLS handshake 43 : fd_quic_tls_hs_t * hs = fd_quic_tls_hs_new( quic_tls, conn_id, conn_id_sz, is_server, transport_params, now ); 44 : 45 : // delete a handshake object 46 : // NULL is allowed here 47 : fd_quic_tls_hs_delete( hs ); 48 : 49 : // call fd_quic_tls_provide_data whenever the peer sends TLS 50 : // handshake data. The peer bootstraps the conversation with a 51 : // zero byte input. 52 : 53 : */ 54 : 55 : /* each TLS handshake requires a number of fd_quic_tls_hs_data structures */ 56 403524 : #define FD_QUIC_TLS_HS_DATA_CNT 16u 57 : 58 : /* alignment of hs_data 59 : must be a power of 2 */ 60 42576 : #define FD_QUIC_TLS_HS_DATA_ALIGN 32u 61 : 62 : /* number of bytes allocated for queued handshake data 63 : must be a multiple of FD_QUIC_TLS_HS_DATA_ALIGN */ 64 85152 : #define FD_QUIC_TLS_HS_DATA_SZ (2048UL) 65 : 66 : /* callback function prototypes */ 67 : 68 : typedef void 69 : (* fd_quic_tls_cb_secret_t)( fd_quic_tls_hs_t * hs, 70 : void * context, 71 : fd_quic_tls_secret_t const * secret ); 72 : 73 : typedef void 74 : (* fd_quic_tls_cb_handshake_complete_t)( fd_quic_tls_hs_t * hs, 75 : void * context ); 76 : 77 : typedef void 78 : (* fd_quic_tls_cb_peer_params_t)( void * context, 79 : uchar const * quic_tp, 80 : ulong quic_tp_sz ); 81 : 82 : struct fd_quic_tls_secret { 83 : uint enc_level; 84 : uchar read_secret [ FD_QUIC_SECRET_SZ ]; 85 : uchar write_secret[ FD_QUIC_SECRET_SZ ]; 86 : }; 87 : 88 : struct fd_quic_tls_cfg { 89 : // callbacks ../crypto/fd_quic_crypto_suites 90 : fd_quic_tls_cb_secret_t secret_cb; 91 : fd_quic_tls_cb_handshake_complete_t handshake_complete_cb; 92 : fd_quic_tls_cb_peer_params_t peer_params_cb; 93 : 94 : ulong max_concur_handshakes; 95 : 96 : /* Signing callback for TLS 1.3 CertificateVerify. Context of the 97 : signer must outlive the tls object. */ 98 : fd_tls_sign_t signer; 99 : 100 : /* Ed25519 public key */ 101 : uchar const * cert_public_key; 102 : 103 : /* rng is a seeded CSPRNG used to generate the TLS random of every 104 : handshake. caller-managed, outlives quic_tls. */ 105 : fd_chacha_rng_t * rng; 106 : 107 : /* alpn: either "solana-tpu" or "alpenglow-v1" */ 108 : uchar const * alpn; 109 : ulong alpn_sz; 110 : 111 : /* req_client_cert: see fd_tls_t */ 112 : int req_client_cert; 113 : }; 114 : 115 : /* structure for organising handshake data */ 116 : struct fd_quic_tls_hs_data { 117 : uchar const * data; 118 : uint data_sz; 119 : uint free_data_sz; /* internal use */ 120 : uint offset; 121 : uint enc_level; 122 : 123 : /* internal use */ 124 : ushort next_idx; /* next in linked list, ~0 for end */ 125 : }; 126 : 127 : struct fd_quic_tls { 128 : /* callbacks */ 129 : fd_quic_tls_cb_secret_t secret_cb; 130 : fd_quic_tls_cb_handshake_complete_t handshake_complete_cb; 131 : fd_quic_tls_cb_peer_params_t peer_params_cb; 132 : 133 : /* ssl related */ 134 : fd_tls_t tls; 135 : }; 136 : 137 620130 : #define FD_QUIC_TLS_HS_DATA_UNUSED ((ushort)~0u) 138 : 139 : struct fd_quic_tls_hs { 140 : /* TLS handshake handles are deliberately placed at the start. 141 : Allows for type punning between fd_quic_tls_hs_t and 142 : fd_tls_estate_{srv,cli}_t. DO NOT MOVE. 143 : Type of handshake object depends on is_server. */ 144 : fd_tls_estate_t hs; 145 : 146 : fd_quic_tls_t * quic_tls; 147 : 148 : int is_server; 149 : int is_hs_complete; 150 : 151 : /* user defined context supplied in callbacks */ 152 : void * context; 153 : 154 : ulong next; /* alloc pool/cache dlist */ 155 : ulong prev; /* cache dlist */ 156 : long birthtime; /* allocation time, used for cache eviction sanity check */ 157 : 158 : /* handshake data 159 : this is data that must be sent to the peer 160 : it consists of an arbitrary list of tuples of: 161 : < "encryption level", array of bytes > 162 : these will be encapsulated and sent in order */ 163 : fd_quic_tls_hs_data_t hs_data[ FD_QUIC_TLS_HS_DATA_CNT ]; 164 : 165 : /* head of hs_data_t free list */ 166 : ushort hs_data_free_idx; 167 : 168 : /* head/tail of hs_data_t pending (to be sent) */ 169 : ushort hs_data_pend_idx[4]; 170 : ushort hs_data_pend_end_idx[4]; 171 : 172 : /* handshake data buffer 173 : allocated in arbitrary chunks 174 : and shared between encryption levels */ 175 : uchar hs_data_buf[ FD_QUIC_TLS_HS_DATA_SZ ]; 176 : uint hs_data_buf_ptr; /* ptr is first unused byte in hs_data_buf */ 177 : uint hs_data_offset[ 4 ]; /* one offset per encoding level */ 178 : 179 : /* Handshake message receive buffer 180 : 181 : rx_hs_buf buffers messages of one encryption level (rx_enc_level). 182 : rx_off is the number of bytes processed by fd_tls. rx_sz is the 183 : number of contiguous bytes received from the peer. */ 184 : 185 : ushort rx_off; 186 : ushort rx_sz; 187 : uchar rx_enc_level; 188 : 189 42489 : # define FD_QUIC_TLS_RX_DATA_SZ (2048UL) 190 : uchar rx_hs_buf[ FD_QUIC_TLS_RX_DATA_SZ ]; 191 : 192 : /* TLS alert code */ 193 : uint alert; 194 : 195 : /* our own QUIC transport params */ 196 : fd_quic_transport_params_t self_transport_params; 197 : 198 : }; 199 : 200 : /* fd_quic_tls_new formats an unused memory region for use as an 201 : fd_quic_tls_t object and joins the caller to it */ 202 : 203 : fd_quic_tls_t * 204 : fd_quic_tls_new( fd_quic_tls_t * mem, 205 : fd_quic_tls_cfg_t * cfg ); 206 : 207 : /* fd_quic_delete unformats a memory region used as an fd_quic_tls_t. 208 : Returns the given pointer on success and NULL if used obviously in error. 209 : Deletes any fd_tls resources. */ 210 : 211 : void * 212 : fd_quic_tls_delete( fd_quic_tls_t * self ); 213 : 214 : fd_quic_tls_hs_t * 215 : fd_quic_tls_hs_new( fd_quic_tls_hs_t * self, 216 : fd_quic_tls_t * quic_tls, 217 : void * context, 218 : int is_server, 219 : fd_quic_transport_params_t const * self_transport_params, 220 : long now ); 221 : 222 : void 223 : fd_quic_tls_hs_delete( fd_quic_tls_hs_t * hs ); 224 : 225 : /* fd_quic_tls_process processes any available TLS handshake messages 226 : from previously received CRYPTO frames. Returns FD_QUIC_SUCCESS if 227 : any number of messages were processed (including no messages in there 228 : is not enough data). Returns FD_QUIC_FAILED if the TLS handshake 229 : failed (not recoverable). */ 230 : 231 : int 232 : fd_quic_tls_process( fd_quic_tls_hs_t * self ); 233 : 234 : 235 : /* fd_quic_tls_get_hs_data 236 : 237 : get oldest queued handshake data from the queue of pending data to sent to peer 238 : 239 : returns 240 : NULL there is no data available 241 : hd_data a pointer to the fd_quic_tls_hs_data_t structure at the head of the queue 242 : 243 : the hd_data and data therein are invalidated by the following 244 : fd_quic_tls_pop_hs_data 245 : fd_quic_tls_hs_delete 246 : 247 : args 248 : self the handshake in question (fine if NULL) 249 : enc_level a pointer for receiving the encryption level 250 : data a pointer for receiving the pointer to the data buffer 251 : data_sz a pointer for receiving the data size */ 252 : fd_quic_tls_hs_data_t * 253 : fd_quic_tls_get_hs_data( fd_quic_tls_hs_t * self, uint enc_level ); 254 : 255 : 256 : /* fd_quic_tls_get_next_hs_data 257 : 258 : get the next unit of handshake data from the queue 259 : 260 : returns NULL if no more available */ 261 : fd_quic_tls_hs_data_t * 262 : fd_quic_tls_get_next_hs_data( fd_quic_tls_hs_t * self, fd_quic_tls_hs_data_t * hs ); 263 : 264 : 265 : /* fd_quic_tls_pop_hs_data 266 : 267 : remove handshake data from head of queue and free associated resources */ 268 : void 269 : fd_quic_tls_pop_hs_data( fd_quic_tls_hs_t * self, uint enc_level ); 270 : 271 : 272 : /* fd_quic_tls_clear_hs_data 273 : 274 : clear all handshake data from a given encryption level. */ 275 : void 276 : fd_quic_tls_clear_hs_data( fd_quic_tls_hs_t * self, uint enc_level ); 277 : 278 : 279 : #endif /* HEADER_fd_src_waltz_quic_tls_fd_quic_tls_h */