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