Line data Source code
1 : #include "fd_quic_tls.h"
2 : #include "../../../ballet/ed25519/fd_x25519.h"
3 : #include "../../../ballet/x509/fd_x509_mock.h"
4 :
5 : #include <errno.h>
6 : #include <stdlib.h>
7 : #include <string.h>
8 :
9 : /* fd_tls callbacks provided by fd_quic *******************************/
10 :
11 : /* fd_quic_tls_sendmsg is called by fd_tls when fd_quic should send a
12 : CRYPTO frame to the peer. Currently, we can assume that the
13 : encryption_level will never decrease (INITIAL => HANDSHAKE => APP) */
14 :
15 : int
16 : fd_quic_tls_sendmsg( void const * handshake,
17 : void const * record,
18 : ulong record_sz,
19 : uint encryption_level,
20 : int flush );
21 :
22 : /* fd_quic_tls_secrets is called by fd_tls when new encryption keys
23 : become available. Currently, this is called at most two times per
24 : connection: For the handshake secrets, and for the initial app-level
25 : secrets. */
26 :
27 : void
28 : fd_quic_tls_secrets( void const * handshake,
29 : void const * recv_secret,
30 : void const * send_secret,
31 : uint encryption_level );
32 :
33 : /* fd_quic_tls_rand is the RNG provided to fd_tls. Note: This is
34 : a layering violation ... The user should pass the CSPRNG handle to
35 : both fd_quic and fd_tls. Currently, implemented via the getrandom()
36 : syscall ... Inefficient! */
37 :
38 : void *
39 : fd_quic_tls_rand( void * ctx,
40 : void * buf,
41 : ulong bufsz );
42 :
43 : /* fd_quic_tls_tp_self is called by fd_tls to retrieve fd_quic's QUIC
44 : transport parameters. */
45 :
46 : ulong
47 : fd_quic_tls_tp_self( void * handshake,
48 : uchar * quic_tp,
49 : ulong quic_tp_bufsz );
50 :
51 : /* fd_quic_tls_tp_self is called by fd_tls to inform fd_quic of the
52 : peer's QUIC transport parameters. */
53 :
54 : void
55 : fd_quic_tls_tp_peer( void * handshake,
56 : uchar const * quic_tp,
57 : ulong quic_tp_sz );
58 :
59 : /* fd_quic_tls lifecycle API ******************************************/
60 :
61 : static void
62 : fd_quic_tls_init( fd_tls_t * tls,
63 : fd_tls_sign_t signer,
64 : uchar const cert_public_key[ static 32 ] );
65 :
66 : fd_quic_tls_t *
67 : fd_quic_tls_new( fd_quic_tls_t * self,
68 3411 : fd_quic_tls_cfg_t * cfg ) {
69 :
70 3411 : if( FD_UNLIKELY( !self ) ) {
71 0 : FD_LOG_WARNING(( "NULL mem" ));
72 0 : return NULL;
73 0 : }
74 3411 : if( FD_UNLIKELY( !cfg ) ) {
75 0 : FD_LOG_WARNING(( "NULL cfg" ));
76 0 : return NULL;
77 0 : }
78 3411 : if( FD_UNLIKELY( (!cfg->secret_cb ) |
79 3411 : (!cfg->handshake_complete_cb) |
80 3411 : (!cfg->peer_params_cb ) ) ) {
81 0 : FD_LOG_WARNING(( "Missing callbacks" ));
82 0 : return NULL;
83 0 : }
84 :
85 3411 : self->secret_cb = cfg->secret_cb;
86 3411 : self->handshake_complete_cb = cfg->handshake_complete_cb;
87 3411 : self->peer_params_cb = cfg->peer_params_cb;
88 :
89 : /* Initialize fd_tls */
90 3411 : fd_quic_tls_init( &self->tls, cfg->signer, cfg->cert_public_key );
91 :
92 3411 : return self;
93 3411 : }
94 :
95 : /* fd_quic_tls_init is called as part of fd_quic_tls_new. It sets up
96 : the embedded fd_tls instance. */
97 :
98 : static void
99 : fd_quic_tls_init( fd_tls_t * tls,
100 : fd_tls_sign_t signer,
101 3411 : uchar const cert_public_key[ static 32 ] ) {
102 3411 : tls = fd_tls_new( tls );
103 3411 : *tls = (fd_tls_t) {
104 3411 : .quic = 1,
105 3411 : .rand = {
106 3411 : .ctx = NULL,
107 3411 : .rand_fn = fd_quic_tls_rand
108 3411 : },
109 3411 : .sign = signer,
110 3411 : .secrets_fn = fd_quic_tls_secrets,
111 3411 : .sendmsg_fn = fd_quic_tls_sendmsg,
112 :
113 3411 : .quic_tp_self_fn = fd_quic_tls_tp_self,
114 3411 : .quic_tp_peer_fn = fd_quic_tls_tp_peer,
115 3411 : };
116 :
117 : /* Generate X25519 key */
118 3411 : if( FD_UNLIKELY( !fd_rng_secure( tls->kex_private_key, 32UL ) ) )
119 0 : FD_LOG_ERR(( "fd_rng_secure failed: %s", fd_io_strerror( errno ) ));
120 3411 : fd_x25519_public( tls->kex_public_key, tls->kex_private_key );
121 :
122 : /* Set up Ed25519 key */
123 3411 : fd_memcpy( tls->cert_public_key, cert_public_key, 32UL );
124 :
125 : /* Generate X.509 cert */
126 3411 : fd_x509_mock_cert( tls->cert_x509, tls->cert_public_key );
127 3411 : tls->cert_x509_sz = FD_X509_MOCK_CERT_SZ;
128 :
129 : /* Set ALPN protocol ID
130 : (Technically, don't need to copy the length prefix but we'll do
131 : so anyways.) */
132 3411 : tls->alpn[ 0 ] = 0x0a;
133 3411 : memcpy( tls->alpn+1, "solana-tpu", 11UL );
134 3411 : tls->alpn_sz = 11UL;
135 3411 : }
136 :
137 : void *
138 3339 : fd_quic_tls_delete( fd_quic_tls_t * self ) {
139 3339 : if( FD_UNLIKELY( !self ) ) {
140 0 : FD_LOG_WARNING(( "NULL self" ));
141 0 : return NULL;
142 0 : }
143 3339 : return self;
144 3339 : }
145 :
146 : fd_quic_tls_hs_t *
147 : fd_quic_tls_hs_new( fd_quic_tls_hs_t * self,
148 : fd_quic_tls_t * quic_tls,
149 : void * context,
150 : int is_server,
151 : fd_quic_transport_params_t const * self_transport_params,
152 12261 : long now ) {
153 : // clear the handshake bits
154 12261 : fd_memset( self, 0, sizeof(fd_quic_tls_hs_t) );
155 :
156 : // set properties on self
157 12261 : self->quic_tls = quic_tls;
158 12261 : self->is_server = is_server;
159 12261 : self->context = context;
160 :
161 : /* initialize handshake data */
162 :
163 : /* init free list */
164 12261 : self->hs_data_free_idx = 0u; /* head points at first */
165 208437 : for( ushort j = 0u; j < FD_QUIC_TLS_HS_DATA_CNT; ++j ) {
166 196176 : if( j < FD_QUIC_TLS_HS_DATA_CNT-1u ) {
167 183915 : self->hs_data[j].next_idx = (ushort)(j+1u); /* each point to next */
168 183915 : } else {
169 12261 : self->hs_data[j].next_idx = FD_QUIC_TLS_HS_DATA_UNUSED ;
170 12261 : }
171 196176 : }
172 :
173 : /* no data pending */
174 61305 : for( unsigned j = 0; j < 4; ++j ) {
175 49044 : self->hs_data_pend_idx[j] = FD_QUIC_TLS_HS_DATA_UNUSED;
176 49044 : self->hs_data_pend_end_idx[j] = FD_QUIC_TLS_HS_DATA_UNUSED;
177 49044 : }
178 :
179 : /* clear hs_data_buf */
180 12261 : self->hs_data_buf_ptr = 0;
181 :
182 : /* all handshake offsets start at zero */
183 12261 : fd_memset( self->hs_data_offset, 0, sizeof( self->hs_data_offset ) );
184 :
185 : /* Set QUIC transport params */
186 12261 : self->self_transport_params = *self_transport_params;
187 :
188 12261 : if( is_server ) {
189 6156 : fd_tls_estate_srv_new( &self->hs.srv );
190 6156 : } else {
191 6105 : fd_tls_estate_cli_new( &self->hs.cli );
192 6105 : long res = fd_tls_client_handshake( &quic_tls->tls, &self->hs.cli, NULL, 0UL, 0 );
193 6105 : if( FD_UNLIKELY( res<0L ) ) {
194 0 : self->alert = (uint)-res;
195 0 : }
196 6105 : }
197 :
198 12261 : self->birthtime = now;
199 :
200 12261 : return self;
201 12261 : }
202 :
203 : void
204 12258 : fd_quic_tls_hs_delete( fd_quic_tls_hs_t * self ) {
205 12258 : if( !self ) return;
206 :
207 12258 : if( self->is_server )
208 6153 : fd_tls_estate_srv_delete( &self->hs.srv );
209 6105 : else
210 6105 : fd_tls_estate_cli_delete( &self->hs.cli );
211 12258 : }
212 :
213 : int
214 42510 : fd_quic_tls_process( fd_quic_tls_hs_t * self ) {
215 :
216 42510 : if( FD_UNLIKELY( self->hs.base.state==FD_TLS_HS_FAIL ) ) return FD_QUIC_FAILED;
217 42510 : if( self->hs.base.state==FD_TLS_HS_CONNECTED ) return FD_QUIC_SUCCESS;
218 :
219 : /* Process all fully received messages */
220 :
221 42507 : uint enc_level = self->rx_enc_level;
222 85011 : for(;;) {
223 85011 : uchar const * buf = self->rx_hs_buf;
224 85011 : ulong off = self->rx_off;
225 85011 : ulong avail = self->rx_sz - off;
226 85011 : if( avail<4 ) break;
227 :
228 : /* Peek the message size from fd_tls_msg_hdr_t
229 : ?? AA BB CC => 0xCCBBAA?? => 0x??AABBCC => 0x00AABBCC */
230 42507 : uint msg_sz = fd_uint_bswap( FD_LOAD( uint, buf+off ) ) & 0xFFFFFFU;
231 42507 : if( avail<msg_sz+4 ) break;
232 :
233 42507 : long res = fd_tls_handshake( &self->quic_tls->tls, &self->hs, buf+off, avail, enc_level );
234 :
235 42507 : if( FD_UNLIKELY( res<0L ) ) {
236 3 : int alert = (int)-res;
237 3 : self->alert = (uint)alert;
238 3 : return FD_QUIC_FAILED;
239 3 : }
240 42504 : if( FD_UNLIKELY( res==0UL ) ) {
241 0 : FD_LOG_WARNING(( "preventing deadlock" ));
242 0 : return FD_QUIC_FAILED;
243 0 : }
244 :
245 42504 : self->rx_off = (ushort)( off+(ulong)res );
246 42504 : }
247 :
248 42504 : switch( self->hs.base.state ) {
249 12144 : case FD_TLS_HS_CONNECTED:
250 : /* handshake completed */
251 12144 : self->quic_tls->handshake_complete_cb( self, self->context );
252 12144 : return FD_QUIC_SUCCESS;
253 0 : case FD_TLS_HS_FAIL:
254 : /* handshake permanently failed */
255 0 : return FD_QUIC_FAILED;
256 30360 : default:
257 : /* handshake not yet complete */
258 30360 : return FD_QUIC_SUCCESS;
259 42504 : }
260 42504 : }
261 :
262 : /* internal callbacks */
263 :
264 : int
265 : fd_quic_tls_sendmsg( void const * handshake,
266 : void const * data,
267 : ulong data_sz,
268 : uint enc_level,
269 42537 : int flush FD_PARAM_UNUSED ) {
270 :
271 42537 : uint buf_sz = FD_QUIC_TLS_HS_DATA_SZ;
272 42537 : if( data_sz > buf_sz ) {
273 0 : return 0;
274 0 : }
275 :
276 : /* Safe because the fd_tls_estate_{srv,cli}_t object is the first
277 : element of fd_quic_tls_hs_t */
278 42537 : fd_quic_tls_hs_t * hs = (fd_quic_tls_hs_t *)handshake;
279 :
280 : /* add handshake data to handshake for retrieval by user */
281 :
282 : /* find free handshake data */
283 42537 : ushort hs_data_idx = hs->hs_data_free_idx;
284 42537 : if( hs_data_idx == FD_QUIC_TLS_HS_DATA_UNUSED ) {
285 : /* no free structures left. fail */
286 0 : return 0;
287 0 : }
288 :
289 : /* allocate enough space from hs data buffer */
290 42537 : uint ptr = hs->hs_data_buf_ptr;
291 42537 : uint alloc_data_sz = fd_uint_align_up( (uint)data_sz, FD_QUIC_TLS_HS_DATA_ALIGN );
292 42537 : if( ptr + alloc_data_sz > FD_QUIC_TLS_HS_DATA_SZ ) {
293 : /* not enough space */
294 0 : return 0;
295 0 : }
296 :
297 : /* success */
298 :
299 42537 : fd_quic_tls_hs_data_t * hs_data = &hs->hs_data[hs_data_idx];
300 42537 : uchar * buf = &hs->hs_data_buf[ptr];
301 :
302 : /* update free list */
303 42537 : hs->hs_data_free_idx = hs_data->next_idx;
304 :
305 : /* write back new buf ptr */
306 42537 : hs->hs_data_buf_ptr = ptr + alloc_data_sz;
307 :
308 : /* copy data into buffer, and update metadata in hs_data */
309 42537 : fd_memcpy( buf, data, data_sz );
310 42537 : hs_data->enc_level = enc_level;
311 42537 : hs_data->data = buf;
312 42537 : hs_data->data_sz = (uint)data_sz;
313 42537 : hs_data->offset = hs->hs_data_offset[enc_level];
314 :
315 : /* offset adjusted ready for more data */
316 42537 : hs->hs_data_offset[enc_level] += (uint)data_sz;
317 :
318 : /* add to end of pending list */
319 42537 : hs_data->next_idx = FD_QUIC_TLS_HS_DATA_UNUSED;
320 42537 : ulong pend_end_idx = hs->hs_data_pend_end_idx[enc_level];
321 42537 : if( pend_end_idx == FD_QUIC_TLS_HS_DATA_UNUSED ) {
322 : /* pending list is empty */
323 24321 : hs->hs_data_pend_end_idx[enc_level] = hs->hs_data_pend_idx[enc_level] = hs_data_idx;
324 24321 : } else {
325 : /* last element must point to next */
326 18216 : hs->hs_data[pend_end_idx].next_idx = hs_data_idx;
327 18216 : hs->hs_data_pend_end_idx[enc_level] = hs_data_idx;
328 18216 : }
329 :
330 42537 : return 1;
331 42537 : }
332 :
333 : void
334 : fd_quic_tls_secrets( void const * handshake,
335 : void const * recv_secret,
336 : void const * send_secret,
337 24288 : uint enc_level ) {
338 :
339 24288 : fd_quic_tls_hs_t * hs = (fd_quic_tls_hs_t *)handshake;
340 :
341 24288 : fd_quic_tls_secret_t secret = { .enc_level = enc_level };
342 24288 : memcpy( secret.read_secret, recv_secret, 32UL );
343 24288 : memcpy( secret.write_secret, send_secret, 32UL );
344 :
345 24288 : hs->quic_tls->secret_cb( hs, hs->context, &secret );
346 24288 : }
347 :
348 : fd_quic_tls_hs_data_t *
349 : fd_quic_tls_get_hs_data( fd_quic_tls_hs_t * self,
350 19879345 : uint enc_level ) {
351 19879345 : if( !self ) return NULL;
352 :
353 250899 : uint idx = self->hs_data_pend_idx[enc_level];
354 250899 : if( idx == FD_QUIC_TLS_HS_DATA_UNUSED ) return NULL;
355 :
356 127407 : return &self->hs_data[idx];
357 250899 : }
358 :
359 : fd_quic_tls_hs_data_t *
360 121158 : fd_quic_tls_get_next_hs_data( fd_quic_tls_hs_t * self, fd_quic_tls_hs_data_t * hs ) {
361 121158 : ushort idx = hs->next_idx;
362 121158 : if( idx == (ushort)(~0u) ) return NULL;
363 54477 : return self->hs_data + idx;
364 121158 : }
365 :
366 : void
367 42504 : fd_quic_tls_pop_hs_data( fd_quic_tls_hs_t * self, uint enc_level ) {
368 42504 : ushort idx = self->hs_data_pend_idx[enc_level];
369 42504 : if( idx == FD_QUIC_TLS_HS_DATA_UNUSED ) return;
370 :
371 42504 : fd_quic_tls_hs_data_t * hs_data = &self->hs_data[idx];
372 :
373 : /* pop from pending list */
374 42504 : self->hs_data_pend_idx[enc_level] = hs_data->next_idx;
375 :
376 : /* if idx is the last, update last */
377 42504 : if( hs_data->next_idx == FD_QUIC_TLS_HS_DATA_UNUSED ) {
378 24288 : self->hs_data_pend_end_idx[enc_level] = FD_QUIC_TLS_HS_DATA_UNUSED;
379 24288 : }
380 42504 : }
381 :
382 : void
383 12138 : fd_quic_tls_clear_hs_data( fd_quic_tls_hs_t * self, uint enc_level ) {
384 12138 : self->hs_data_pend_idx[enc_level] = FD_QUIC_TLS_HS_DATA_UNUSED;
385 12138 : self->hs_data_pend_end_idx[enc_level] = FD_QUIC_TLS_HS_DATA_UNUSED;
386 12138 : }
387 :
388 : void *
389 : fd_quic_tls_rand( void * ctx,
390 : void * buf,
391 12177 : ulong bufsz ) {
392 12177 : (void)ctx;
393 12177 : FD_TEST( fd_rng_secure( buf, bufsz ) );
394 12177 : return buf;
395 12177 : }
396 :
397 : ulong
398 : fd_quic_tls_tp_self( void * const handshake,
399 : uchar * const quic_tp,
400 12180 : ulong const quic_tp_bufsz ) {
401 12180 : fd_quic_tls_hs_t * hs = (fd_quic_tls_hs_t *)handshake;
402 :
403 12180 : ulong encoded_sz = fd_quic_encode_transport_params( quic_tp, quic_tp_bufsz, &hs->self_transport_params );
404 12180 : if( FD_UNLIKELY( encoded_sz==FD_QUIC_ENCODE_FAIL ) ) {
405 0 : FD_LOG_WARNING(( "fd_quic_encode_transport_params failed" ));
406 0 : return 0UL;
407 0 : }
408 :
409 12180 : return encoded_sz;
410 12180 : }
411 :
412 : void
413 : fd_quic_tls_tp_peer( void * handshake,
414 : uchar const * quic_tp,
415 12147 : ulong quic_tp_sz ) {
416 : /* Callback issued by fd_tls. Bubble up callback to fd_quic_tls. */
417 :
418 12147 : fd_quic_tls_hs_t * hs = (fd_quic_tls_hs_t *)handshake;
419 12147 : fd_quic_tls_t * quic_tls = hs->quic_tls;
420 :
421 12147 : quic_tls->peer_params_cb( hs->context, quic_tp, quic_tp_sz );
422 12147 : }
|