Line data Source code
1 : #include "fd_tls.h"
2 : #include "fd_tls_proto.h"
3 : #include "../../ballet/ed25519/fd_ed25519.h"
4 : #include "../../ballet/ed25519/fd_x25519.h"
5 : #include "../../ballet/hmac/fd_hmac.h"
6 :
7 : #include <assert.h>
8 :
9 : /* Pre-generated keys */
10 :
11 : static char const fd_tls13_cli_sign_prefix[ 98 ] =
12 : " " /* 32 spaces */
13 : " " /* 32 spaces */
14 : "TLS 1.3, client CertificateVerify";
15 :
16 : static char const fd_tls13_srv_sign_prefix[ 98 ] =
17 : " " /* 32 spaces */
18 : " " /* 32 spaces */
19 : "TLS 1.3, server CertificateVerify";
20 :
21 : //uchar empty_hash[ 32 ];
22 : //fd_sha256_hash( empty_hash, NULL, 0UL );
23 : static uchar const empty_hash[ 32 ] =
24 : { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
25 : 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
26 : 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
27 : 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 };
28 :
29 : //static uchar const psk[ 32 ] = {0};
30 : //uchar early_secret[ 32 ];
31 : //fd_hmac_sha256( /* data */ psk, 32UL,
32 : // /* salt */ NULL, 0UL,
33 : // early_secret );
34 : //static uchar const early_secret[ 32 ] =
35 : // { 0x33, 0xad, 0x0a, 0x1c, 0x60, 0x7e, 0xc0, 0x3b,
36 : // 0x09, 0xe6, 0xcd, 0x98, 0x93, 0x68, 0x0c, 0xe2,
37 : // 0x10, 0xad, 0xf3, 0x00, 0xaa, 0x1f, 0x26, 0x60,
38 : // 0xe1, 0xb2, 0x2e, 0x10, 0xf1, 0x70, 0xf9, 0x2a };
39 :
40 : //uchar handshake_derived[ 32 ];
41 : //fd_tls_hkdf_expand_label( handshake_derived,
42 : // early_secret,
43 : // "derived", 7UL,
44 : // empty_hash, 32UL );
45 : static uchar const handshake_derived[ 32 ] =
46 : { 0x6f, 0x26, 0x15, 0xa1, 0x08, 0xc7, 0x02, 0xc5,
47 : 0x67, 0x8f, 0x54, 0xfc, 0x9d, 0xba, 0xb6, 0x97,
48 : 0x16, 0xc0, 0x76, 0x18, 0x9c, 0x48, 0x25, 0x0c,
49 : 0xeb, 0xea, 0xc3, 0x57, 0x6c, 0x36, 0x11, 0xba };
50 :
51 : /* fd_tls_t boilerplate */
52 :
53 : ulong
54 0 : fd_tls_align( void ) {
55 0 : return alignof(fd_tls_t);
56 0 : }
57 :
58 : ulong
59 0 : fd_tls_footprint( void ) {
60 0 : return sizeof(fd_tls_t);
61 0 : }
62 :
63 : void *
64 3342 : fd_tls_new( void * mem ) {
65 :
66 3342 : if( FD_UNLIKELY( !mem ) ) {
67 0 : FD_LOG_WARNING(( "NULL mem" ));
68 0 : return NULL;
69 0 : }
70 :
71 3342 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_tls_align() ) ) ) {
72 0 : FD_LOG_WARNING(( "unaligned mem" ));
73 0 : return NULL;
74 0 : }
75 :
76 3342 : ulong fp = fd_tls_footprint();
77 3342 : memset( mem, 0, fp );
78 3342 : return mem;
79 3342 : }
80 :
81 : fd_tls_t *
82 18 : fd_tls_join( void * mem ) {
83 18 : return (fd_tls_t *)mem;
84 18 : }
85 :
86 : void *
87 18 : fd_tls_leave( fd_tls_t * server ) {
88 18 : return (void *)server;
89 18 : }
90 :
91 : void *
92 18 : fd_tls_delete( void * mem ) {
93 18 : return mem;
94 18 : }
95 :
96 : /* TODO create internal state machine and integrate Tango for
97 : accelerating cryptographic computations (e.g. FPGA sigverify) */
98 :
99 : fd_tls_estate_srv_t *
100 6390 : fd_tls_estate_srv_new( void * mem ) {
101 :
102 6390 : fd_tls_estate_srv_t * hs = mem;
103 :
104 6390 : memset( hs, 0, sizeof(fd_tls_estate_srv_t) );
105 6390 : hs->base.state = FD_TLS_HS_START;
106 6390 : hs->base.server = 1;
107 :
108 6390 : return hs;
109 6390 : }
110 :
111 : fd_tls_estate_cli_t *
112 6024 : fd_tls_estate_cli_new( void * mem ) {
113 :
114 6024 : fd_tls_estate_cli_t * hs = mem;
115 :
116 6024 : memset( hs, 0, sizeof(fd_tls_estate_cli_t) );
117 6024 : hs->base.state = FD_TLS_HS_START;
118 :
119 6024 : return hs;
120 6024 : }
121 :
122 : void *
123 : fd_tls_hkdf_expand_label( uchar * out,
124 : ulong out_sz,
125 : uchar const secret[ 32 ],
126 : char const * label,
127 : ulong label_sz,
128 : uchar const * context,
129 327996 : ulong context_sz ) {
130 :
131 327996 : # define LABEL_BUFSZ (64UL)
132 327996 : FD_TEST( label_sz <=LABEL_BUFSZ );
133 327996 : FD_TEST( context_sz<=LABEL_BUFSZ );
134 327996 : FD_TEST( out_sz <=32UL );
135 :
136 : /* Create HKDF info */
137 327996 : uchar info[ 2+1+6+LABEL_BUFSZ+1+LABEL_BUFSZ+1 ];
138 327996 : ulong info_sz = 0UL;
139 :
140 : /* Length of hash output */
141 327996 : info[0]=0; info[1]=(uchar)out_sz;
142 327996 : info_sz += 2UL;
143 :
144 : /* Length prefix of label */
145 327996 : info[ info_sz ] = (uchar)( 6UL + label_sz );
146 327996 : info_sz += 1UL;
147 :
148 : /* Label */
149 327996 : memcpy( info+info_sz, "tls13 ", 6UL );
150 327996 : info_sz += 6UL;
151 327996 : memcpy( info+info_sz, label, label_sz );
152 327996 : info_sz += label_sz;
153 :
154 : /* Length prefix of context */
155 327996 : info[ info_sz ] = (uchar)( context_sz );
156 327996 : info_sz += 1UL;
157 :
158 : /* Context */
159 327996 : fd_memcpy( info+info_sz, context, context_sz );
160 327996 : info_sz += context_sz;
161 :
162 : /* HKDF-Expand suffix */
163 327996 : info[ info_sz ] = 0x01;
164 327996 : info_sz += 1UL;
165 :
166 : /* Compute result of HKDF-Expand-Label */
167 327996 : uchar hash[ 32 ];
168 327996 : fd_hmac_sha256( info, info_sz, secret, 32UL, hash );
169 327996 : fd_memcpy( out, hash, out_sz );
170 327996 : return out;
171 327996 : # undef LABEL_BUFSZ
172 327996 : }
173 :
174 : static int
175 : fd_tls_has_alpn( uchar const * list,
176 : ulong const list_sz,
177 : uchar const * target,
178 6015 : ulong const target_sz ) {
179 6015 : if( FD_UNLIKELY( target_sz<=1UL ) ) return 0;
180 :
181 6015 : uchar const * list_end = list + list_sz;
182 6015 : while( list < list_end ) {
183 6015 : ulong ele_sz = list[0];
184 6015 : list += 1UL;
185 6015 : uchar const * ele = list;
186 6015 : if( FD_UNLIKELY( (long)ele_sz > list_end-list ) ) return -1;
187 6015 : list += ele_sz;
188 :
189 6015 : if( ele_sz==target_sz-1UL )
190 6015 : if( 0==memcmp( ele, target+1UL, ele_sz ) )
191 6015 : return 1;
192 6015 : }
193 0 : return 0;
194 6015 : }
195 :
196 : /* fd_tls_alert is a convenience function for setting a handshake
197 : failure alert and reason code. */
198 :
199 : static inline long __attribute__((warn_unused_result))
200 : fd_tls_alert( fd_tls_estate_base_t * hs,
201 : uint alert,
202 6 : ushort reason ) {
203 6 : hs->reason = reason;
204 6 : return -(long)alert;
205 6 : }
206 :
207 : /* fd_tls_send_cert_verify generates and sends a CertificateVerify
208 : message. Returns 0L on success and negated TLS alert number on
209 : failure. this is the local client or server object. hs is the
210 : local handshake object. transcript is the SHA state of the
211 : transcript hasher immediately preceding the CertificateVerify (where
212 : last entry is Certificate). is_client is 1 if the local role is a
213 : client, 0 otherwise. */
214 :
215 : static long
216 : fd_tls_send_cert_verify( fd_tls_t const * this,
217 : fd_tls_estate_base_t * hs,
218 : fd_sha256_t * transcript,
219 6018 : int is_client ) {
220 :
221 : /* Export current transcript hash
222 : And create message to be signed */
223 :
224 6018 : uchar sign_msg[ 130 ];
225 6018 : fd_memcpy( sign_msg,
226 6018 : is_client ? fd_tls13_cli_sign_prefix : fd_tls13_srv_sign_prefix,
227 6018 : 98UL );
228 :
229 6018 : fd_sha256_t transcript_clone = *transcript;
230 6018 : fd_sha256_fini( &transcript_clone, sign_msg+98 );
231 :
232 : /* Sign certificate */
233 :
234 6018 : uchar cert_verify_sig[ 64UL ];
235 6018 : fd_tls_sign( &this->sign, cert_verify_sig, sign_msg );
236 :
237 : /* Create CertificateVerify message */
238 :
239 6018 : # define MSG_BUFSZ (512UL)
240 6018 : uchar msg_buf[ MSG_BUFSZ ];
241 :
242 6018 : ulong cv_sz;
243 :
244 6018 : do {
245 6018 : uchar * wire = msg_buf;
246 6018 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
247 :
248 : /* Leave space for message header */
249 :
250 6018 : void * hdr_ptr = wire;
251 6018 : wire += sizeof(fd_tls_msg_hdr_t);
252 6018 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_CERT_VERIFY };
253 :
254 : /* Construct CertificateVerify */
255 :
256 6018 : fd_tls_cert_verify_t cv = {
257 6018 : .sig_alg = FD_TLS_SIGNATURE_ED25519
258 6018 : };
259 6018 : fd_memcpy( cv.sig, cert_verify_sig, 64UL );
260 :
261 : /* Encode CertificateVerify */
262 :
263 6018 : long encode_res = fd_tls_encode_cert_verify( &cv, wire, (ulong)(wire_end-wire) );
264 6018 : if( FD_UNLIKELY( encode_res<0L ) )
265 0 : return fd_tls_alert( hs, (uint)(-encode_res), FD_TLS_REASON_CV_ENCODE );
266 6018 : wire += (ulong)encode_res;
267 :
268 6018 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
269 6018 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
270 6018 : cv_sz = (ulong)(wire - msg_buf);
271 6018 : } while(0);
272 :
273 : /* Send CertificateVerify message */
274 :
275 6018 : if( FD_UNLIKELY( !this->sendmsg_fn(
276 6018 : hs,
277 6018 : msg_buf, cv_sz,
278 6018 : FD_TLS_LEVEL_HANDSHAKE,
279 6018 : /* flush */ 0 ) ) )
280 0 : return fd_tls_alert( hs, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
281 :
282 : /* Record CertificateVerify in transcript hash */
283 :
284 6018 : fd_sha256_append( transcript, msg_buf, cv_sz );
285 :
286 6018 : # undef MSG_BUFSZ
287 6018 : return 0L;
288 6018 : }
289 :
290 : static long fd_tls_server_hs_start ( fd_tls_t const *, fd_tls_estate_srv_t *, uchar const *, ulong, uint );
291 : static long fd_tls_server_hs_wait_finished( fd_tls_t const *, fd_tls_estate_srv_t *, uchar const *, ulong, uint );
292 :
293 : long
294 : fd_tls_server_handshake( fd_tls_t const * server,
295 : fd_tls_estate_srv_t * handshake,
296 : void const * msg,
297 : ulong msg_sz,
298 12039 : uint encryption_level ) {
299 12039 : switch( handshake->base.state ) {
300 6021 : case FD_TLS_HS_START:
301 6021 : return fd_tls_server_hs_start ( server, handshake, msg, msg_sz, encryption_level );
302 6018 : case FD_TLS_HS_WAIT_FINISHED:
303 6018 : return fd_tls_server_hs_wait_finished( server, handshake, msg, msg_sz, encryption_level );
304 0 : default:
305 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_ILLEGAL_STATE );
306 12039 : }
307 12039 : }
308 :
309 : /* fd_tls_server_hs_start is invoked in response to the initial
310 : ClientHello. We send back several messages in response, including
311 : - the ServerHello, completing cryptographic negotiation
312 : - EncryptedExtensions, for further handshake data
313 : - Finished, completing the server's handshake message sequence */
314 :
315 : static long
316 : fd_tls_server_hs_start( fd_tls_t const * const server,
317 : fd_tls_estate_srv_t * const handshake,
318 : uchar const * const record,
319 : ulong record_sz,
320 6021 : uint encryption_level ) {
321 :
322 : /* Request QUIC transport params */
323 6021 : uchar quic_tp[ FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ];
324 6021 : long quic_tp_sz = -1L;
325 6021 : if( server->quic )
326 6015 : quic_tp_sz = (long)server->quic_tp_self_fn( handshake, quic_tp, FD_TLS_EXT_QUIC_PARAMS_SZ_MAX );
327 6021 : if( FD_UNLIKELY( quic_tp_sz > (long)FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
328 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_QUIC_TP_OVERSZ );
329 :
330 6021 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_INITIAL ) )
331 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
332 :
333 : /* Message buffer */
334 18054 : # define MSG_BUFSZ 512UL
335 6021 : uchar msg_buf[ MSG_BUFSZ ];
336 :
337 : /* Transcript hasher */
338 6021 : fd_sha256_t transcript; fd_sha256_init( &transcript );
339 :
340 : /* Read client hello ************************************************/
341 :
342 6021 : fd_tls_client_hello_t ch = {0};
343 :
344 6021 : ulong read_sz;
345 6021 : do {
346 6021 : uchar const * wire = record;
347 6021 : uchar const * const wire_end = record + record_sz;
348 :
349 : /* Decode message header */
350 :
351 6021 : fd_tls_msg_hdr_t msg_hdr = {0};
352 6021 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
353 6021 : if( FD_UNLIKELY( decode_res<0L ) )
354 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CH_PARSE );
355 6021 : wire += (ulong)decode_res;
356 :
357 6021 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CLIENT_HELLO ) )
358 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CH_EXPECTED );
359 :
360 : /* Decode Client Hello */
361 :
362 6021 : decode_res = fd_tls_decode_client_hello( &ch, wire, (ulong)(wire_end-wire) );
363 6021 : if( FD_UNLIKELY( decode_res<0L ) )
364 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CH_PARSE );
365 6021 : wire += (ulong)decode_res;
366 :
367 6021 : read_sz = (ulong)(wire - record);
368 6021 : } while(0);
369 :
370 : /* Check for cryptographic compatibility */
371 :
372 6021 : if( FD_UNLIKELY( ( !ch.supported_versions.tls13 )
373 6021 : | ( !ch.supported_groups.x25519 )
374 6021 : | ( !ch.signature_algorithms.ed25519 )
375 6021 : | ( !ch.cipher_suites.aes_128_gcm_sha256 ) ) )
376 3 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CH_CRYPTO_NEG );
377 :
378 : /* Remember client random for SSLKEYLOGFILE */
379 6018 : fd_memcpy( handshake->base.client_random, ch.random, 32UL );
380 :
381 : /* Detect QUIC */
382 :
383 6018 : if( server->quic ) {
384 : /* QUIC transport parameters are mandatory in QUIC mode */
385 6015 : if( FD_UNLIKELY( !ch.quic_tp.buf ) )
386 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_CH_NO_QUIC );
387 :
388 : /* Inform user of peer's QUIC transport parameters */
389 6015 : server->quic_tp_peer_fn( handshake, ch.quic_tp.buf, ch.quic_tp.bufsz );
390 6015 : }
391 :
392 : /* Reject connection if ALPN not advertised */
393 :
394 6018 : if( server->alpn[0] ) {
395 6015 : if( FD_UNLIKELY( !ch.alpn.bufsz ) )
396 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_NO_APPLICATION_PROTOCOL, FD_TLS_REASON_NO_ALPN );
397 6015 : int ok = fd_tls_has_alpn( ch.alpn.buf, ch.alpn.bufsz, server->alpn, server->alpn_sz );
398 6015 : if( FD_UNLIKELY( ok==-1 ) )
399 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_ALPN_PARSE );
400 6015 : if( FD_UNLIKELY( ok==0 ) )
401 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_NO_APPLICATION_PROTOCOL, FD_TLS_REASON_ALPN_NEG );
402 6015 : }
403 :
404 : /* Record client hello in transcript hash */
405 :
406 6018 : fd_sha256_append( &transcript, record, read_sz );
407 :
408 : /* Respond with server hello ****************************************/
409 :
410 : /* Create server random */
411 :
412 6018 : uchar server_random[ 32 ];
413 6018 : if( FD_UNLIKELY( !fd_tls_rand( &server->rand, server_random, 32UL ) ) )
414 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_RAND_FAIL );
415 :
416 : /* Create server hello message */
417 :
418 6018 : ulong server_hello_sz;
419 :
420 6018 : do {
421 6018 : uchar * wire = msg_buf;
422 6018 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
423 :
424 : /* Leave space for message header */
425 :
426 6018 : void * hdr_ptr = wire;
427 6018 : wire += sizeof(fd_tls_msg_hdr_t);
428 6018 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_SERVER_HELLO };
429 :
430 : /* Construct server hello */
431 :
432 6018 : fd_tls_server_hello_t sh = {
433 6018 : .cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256,
434 6018 : .key_share = { .has_x25519 = 1 },
435 6018 : .session_id = ch.session_id,
436 6018 : };
437 6018 : memcpy( sh.random, server_random, 32UL );
438 6018 : memcpy( sh.key_share.x25519, server->kex_public_key, 32UL );
439 :
440 : /* Encode server hello */
441 :
442 6018 : long encode_res = fd_tls_encode_server_hello( &sh, wire, (ulong)(wire_end-wire) );
443 6018 : if( FD_UNLIKELY( encode_res<0L ) )
444 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_SH_ENCODE );
445 6018 : wire += (ulong)encode_res;
446 :
447 6018 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
448 6018 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
449 6018 : server_hello_sz = (ulong)(wire - msg_buf);
450 6018 : } while(0);
451 :
452 : /* Call back with server hello */
453 :
454 6018 : if( FD_UNLIKELY( !server->sendmsg_fn(
455 6018 : handshake,
456 6018 : msg_buf, server_hello_sz,
457 6018 : FD_TLS_LEVEL_INITIAL,
458 6018 : /* flush */ 1 ) ) )
459 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
460 :
461 : /* Record server hello in transcript hash */
462 :
463 6018 : fd_sha256_append( &transcript, msg_buf, server_hello_sz );
464 :
465 : /* Derive handshake secrets *****************************************/
466 :
467 : /* Export handshake transcript hash */
468 :
469 6018 : fd_sha256_t transcript_clone = transcript;
470 6018 : uchar transcript_hash[ 32 ];
471 6018 : fd_sha256_fini( &transcript_clone, transcript_hash );
472 :
473 : /* Derive ECDH input key material */
474 :
475 6018 : uchar _ecdh_ikm[ 32 ];
476 6018 : void * ecdh_ikm = fd_x25519_exchange( _ecdh_ikm,
477 6018 : server->kex_private_key,
478 6018 : ch.key_share.x25519 );
479 6018 : if( FD_UNLIKELY( !ecdh_ikm ) )
480 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_X25519_FAIL );
481 :
482 : /* Derive main handshake secret */
483 :
484 6018 : uchar handshake_secret[ 32 ];
485 6018 : fd_hmac_sha256( /* data */ ecdh_ikm, 32UL,
486 6018 : /* salt */ handshake_derived, 32UL,
487 6018 : /* out */ handshake_secret );
488 :
489 : /* Derive client/server handshake secrets */
490 :
491 6018 : uchar client_hs_secret[ 32UL ];
492 6018 : fd_tls_hkdf_expand_label( client_hs_secret, 32UL,
493 6018 : handshake_secret,
494 6018 : "c hs traffic", 12UL,
495 6018 : transcript_hash, 32UL );
496 6018 : memcpy( handshake->client_hs_secret, client_hs_secret, 32UL );
497 :
498 6018 : uchar server_hs_secret[ 32UL ];
499 6018 : fd_tls_hkdf_expand_label( server_hs_secret, 32UL,
500 6018 : handshake_secret,
501 6018 : "s hs traffic", 12UL,
502 6018 : transcript_hash, 32UL );
503 :
504 : /* Call back with handshake secrets */
505 :
506 6018 : server->secrets_fn( handshake,
507 6018 : /* read secret */ client_hs_secret,
508 6018 : /* write secret */ server_hs_secret,
509 6018 : FD_TLS_LEVEL_HANDSHAKE );
510 :
511 : /* Derive master secret */
512 :
513 6018 : uchar master_derive[ 32 ];
514 6018 : fd_tls_hkdf_expand_label( master_derive, 32UL,
515 6018 : handshake_secret,
516 6018 : "derived", 7UL,
517 6018 : empty_hash, 32UL );
518 :
519 6018 : static uchar const zeros[ 32 ] = {0};
520 6018 : uchar master_secret[ 32 ];
521 6018 : fd_hmac_sha256( /* data */ zeros, 32UL,
522 6018 : /* salt */ master_derive, 32UL,
523 6018 : /* out */ master_secret );
524 :
525 : /* Send EncryptedExtensions (EE) message ****************************/
526 :
527 6018 : ulong server_ee_sz;
528 :
529 6018 : do {
530 6018 : uchar * wire = msg_buf;
531 6018 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
532 :
533 : /* Leave space for message header */
534 :
535 6018 : void * hdr_ptr = wire;
536 6018 : wire += sizeof(fd_tls_msg_hdr_t);
537 6018 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_ENCRYPTED_EXT };
538 :
539 6018 : ushort * ext_sz_ptr = (ushort *)wire;
540 6018 : wire += sizeof(ushort);
541 :
542 : /* Construct encrypted extensions */
543 :
544 6018 : fd_tls_enc_ext_t ee = {
545 6018 : .quic_tp = {
546 6018 : .buf = (quic_tp_sz>=0L) ? quic_tp : NULL,
547 6018 : .bufsz = (ushort)quic_tp_sz,
548 6018 : },
549 6018 : .alpn = {
550 6018 : .buf = server->alpn,
551 6018 : .bufsz = server->alpn_sz,
552 6018 : }
553 6018 : };
554 :
555 : /* Negotiate raw public keys if available */
556 :
557 6018 : if( ch.server_cert_types.raw_pubkey ) {
558 6018 : handshake->server_cert_rpk = 1;
559 6018 : ee.server_cert.cert_type = FD_TLS_CERTTYPE_RAW_PUBKEY;
560 6018 : } else if( !server->cert_x509_sz ) {
561 : /* If server lacks an X.509 certificate and client does not support
562 : raw public keys, abort early. */
563 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_NO_X509 );
564 0 : }
565 :
566 6018 : if( ch.client_cert_types.raw_pubkey ) {
567 6018 : handshake->client_cert_rpk = 1;
568 6018 : ee.client_cert.cert_type = FD_TLS_CERTTYPE_RAW_PUBKEY;
569 6018 : }
570 :
571 : /* Encode encrypted extensions */
572 :
573 6018 : long encode_res = fd_tls_encode_enc_ext( &ee, wire, (ulong)(wire_end-wire) );
574 6018 : if( FD_UNLIKELY( encode_res<0L ) )
575 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_EE_ENCODE );
576 6018 : wire += (ulong)encode_res;
577 :
578 6018 : *ext_sz_ptr = (ushort)fd_ushort_bswap( (ushort)encode_res );
579 6018 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res + (uint)sizeof(ushort) );
580 6018 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, 4UL );
581 6018 : server_ee_sz = (ulong)(wire - msg_buf);
582 6018 : } while(0);
583 :
584 : /* Call back with EE */
585 :
586 6018 : if( FD_UNLIKELY( !server->sendmsg_fn(
587 6018 : handshake,
588 6018 : msg_buf, server_ee_sz,
589 6018 : FD_TLS_LEVEL_HANDSHAKE,
590 6018 : /* flush */ 0 ) ) )
591 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
592 :
593 : /* Record EE in transcript hash */
594 :
595 6018 : fd_sha256_append( &transcript, msg_buf, server_ee_sz );
596 :
597 : /* Send Certificate *************************************************/
598 :
599 6018 : ulong cert_msg_sz;
600 6018 : if( ch.server_cert_types.raw_pubkey ) {
601 6018 : long sz = fd_tls_encode_raw_public_key( server->cert_public_key, msg_buf, MSG_BUFSZ );
602 6018 : FD_TEST( sz>=0L );
603 6018 : cert_msg_sz = (ulong)sz;
604 6018 : } else {
605 0 : long sz = fd_tls_encode_cert_x509( server->cert_x509, server->cert_x509_sz, msg_buf, MSG_BUFSZ );
606 0 : FD_TEST( sz>=0L );
607 0 : cert_msg_sz = (ulong)sz;
608 0 : }
609 :
610 : /* Send certificate message */
611 :
612 6018 : if( FD_UNLIKELY( !server->sendmsg_fn(
613 6018 : handshake,
614 6018 : msg_buf, cert_msg_sz,
615 6018 : FD_TLS_LEVEL_HANDSHAKE,
616 6018 : /* flush */ 0 ) ) )
617 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
618 :
619 : /* Record Certificate message in transcript hash */
620 :
621 6018 : fd_sha256_append( &transcript, msg_buf, cert_msg_sz );
622 :
623 : /* Send CertificateVerify *******************************************/
624 :
625 6018 : long cvfy_res = fd_tls_send_cert_verify( server, &handshake->base, &transcript, 0 );
626 6018 : if( FD_UNLIKELY( !!cvfy_res ) ) return cvfy_res;
627 : /* CertificateVerify already included in transcript hash */
628 :
629 : /* Send Finished ****************************************************/
630 :
631 : /* Create static size message layout */
632 :
633 6018 : struct __attribute__((packed)) {
634 6018 : fd_tls_msg_hdr_t hdr;
635 6018 : fd_tls_finished_t fin;
636 6018 : } fin_rec;
637 6018 : fin_rec.hdr = (fd_tls_msg_hdr_t){
638 6018 : .type = FD_TLS_MSG_FINISHED,
639 6018 : .sz = fd_uint_to_tls_u24( 0x20 )
640 6018 : };
641 6018 : fd_tls_msg_hdr_bswap( &fin_rec.hdr );
642 6018 : fd_tls_finished_bswap( &fin_rec.fin );
643 :
644 : /* Export transcript hash ClientHello..CertificateVerify */
645 :
646 6018 : transcript_clone = transcript;
647 6018 : fd_sha256_fini( &transcript_clone, transcript_hash );
648 :
649 : /* Derive "Finished" key */
650 :
651 6018 : uchar finished_key[ 32 ];
652 6018 : fd_tls_hkdf_expand_label( finished_key, 32UL,
653 6018 : server_hs_secret,
654 6018 : "finished", 8UL,
655 6018 : NULL, 0UL );
656 :
657 : /* Derive "Finished" verify data */
658 :
659 6018 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
660 6018 : /* salt */ finished_key, 32UL,
661 6018 : /* out */ fin_rec.fin.verify );
662 :
663 : /* Send Finished message */
664 :
665 6018 : if( FD_UNLIKELY( !server->sendmsg_fn(
666 6018 : handshake,
667 6018 : &fin_rec, sizeof(fin_rec),
668 6018 : FD_TLS_LEVEL_HANDSHAKE,
669 6018 : /* flush */ 1 ) ) )
670 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
671 :
672 : /* Record Finished in transcript hash */
673 :
674 6018 : fd_sha256_append( &transcript, &fin_rec, sizeof(fin_rec) );
675 :
676 : /* Derive application secrets ***************************************/
677 :
678 : /* Export transcript hash ClientHello..ServerFinished */
679 :
680 6018 : transcript_clone = transcript;
681 6018 : fd_sha256_fini( &transcript_clone, transcript_hash );
682 :
683 : /* Derive client/server application secrets */
684 :
685 6018 : uchar client_app_secret[ 32UL ];
686 6018 : fd_tls_hkdf_expand_label( client_app_secret, 32UL,
687 6018 : master_secret,
688 6018 : "c ap traffic", 12UL,
689 6018 : transcript_hash, 32UL );
690 :
691 6018 : uchar server_app_secret[ 32UL ];
692 6018 : fd_tls_hkdf_expand_label( server_app_secret, 32UL,
693 6018 : master_secret,
694 6018 : "s ap traffic", 12UL,
695 6018 : transcript_hash, 32UL );
696 :
697 : /* Call back with application secrets */
698 :
699 6018 : server->secrets_fn( handshake,
700 6018 : /* read secret */ client_app_secret,
701 6018 : /* write secret */ server_app_secret,
702 6018 : FD_TLS_LEVEL_APPLICATION );
703 :
704 : /* Finish up ********************************************************/
705 :
706 : /* Store transcript hash state */
707 :
708 6018 : fd_tls_transcript_store( &handshake->transcript, &transcript );
709 :
710 : /* Done */
711 :
712 6018 : handshake->base.state = FD_TLS_HS_WAIT_FINISHED;
713 :
714 6018 : # undef MSG_BUFSZ
715 6018 : return (long)read_sz;
716 6018 : }
717 :
718 : static long
719 : fd_tls_handle_cert_chain( fd_tls_estate_base_t * const base,
720 : uchar const * const cert_chain,
721 : ulong const cert_chain_sz,
722 : uchar const * const expected_pubkey,
723 : uchar * const out_pubkey,
724 6018 : int const is_rpk ) {
725 :
726 6018 : fd_tls_extract_cert_pubkey_res_t extract =
727 6018 : fd_tls_extract_cert_pubkey( cert_chain, cert_chain_sz, fd_uint_if( is_rpk, FD_TLS_CERTTYPE_RAW_PUBKEY, FD_TLS_CERTTYPE_X509 ) );
728 :
729 6018 : if( FD_UNLIKELY( !extract.pubkey ) )
730 0 : return fd_tls_alert( base, extract.alert, extract.reason );
731 :
732 6018 : if( expected_pubkey )
733 0 : if( FD_UNLIKELY( 0!=memcmp( extract.pubkey, expected_pubkey, 32UL ) ) )
734 0 : return fd_tls_alert( base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_WRONG_PUBKEY );
735 6018 : if( out_pubkey )
736 6018 : fd_memcpy( out_pubkey, extract.pubkey, 32UL );
737 :
738 : /* Skip extensions */
739 : /* Skip remaining certificate chain */
740 :
741 6018 : return (long)cert_chain_sz;
742 6018 : }
743 :
744 : static long
745 : fd_tls_handle_cert_verify( fd_tls_estate_base_t * hs,
746 : fd_sha256_t const * transcript,
747 : uchar const * record,
748 : ulong record_sz,
749 : uchar const pubkey[ static 32 ],
750 6018 : int is_client ) {
751 :
752 : /* Read CertificateVerify *******************************************/
753 :
754 6018 : fd_tls_cert_verify_t vfy[1] = {{0}};
755 :
756 6018 : ulong read_sz;
757 6018 : do {
758 6018 : uchar const * wire = record;
759 6018 : uchar const * const wire_end = record + record_sz;
760 :
761 : /* Decode message header */
762 :
763 6018 : fd_tls_msg_hdr_t msg_hdr = {0};
764 6018 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
765 6018 : if( FD_UNLIKELY( ( decode_res<0L ) |
766 6018 : ( fd_tls_u24_to_uint( msg_hdr.sz ) != 0x44UL ) ) )
767 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CV_PARSE );
768 6018 : wire += (ulong)decode_res;
769 :
770 6018 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CERT_VERIFY ) )
771 0 : return fd_tls_alert( hs, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CV_EXPECTED );
772 :
773 : /* Decode CertificateVerify */
774 :
775 6018 : decode_res = fd_tls_decode_cert_verify( vfy, wire, (ulong)(wire_end-wire) );
776 6018 : if( FD_UNLIKELY( decode_res<0L ) )
777 0 : return fd_tls_alert( hs, (uint)(-decode_res), FD_TLS_REASON_CV_PARSE );
778 6018 : wire += (ulong)decode_res;
779 :
780 6018 : read_sz = (ulong)(wire - record);
781 6018 : } while(0);
782 :
783 6018 : if( FD_UNLIKELY( vfy->sig_alg != FD_TLS_SIGNATURE_ED25519 ) )
784 0 : return fd_tls_alert( hs, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CV_SIGALG );
785 :
786 : /* Verify signature *************************************************/
787 :
788 : /* Export transcript hash ClientHello..server Certificate
789 : And recover message that was signed */
790 :
791 6018 : uchar sign_msg[ 130 ];
792 6018 : fd_memcpy( sign_msg,
793 6018 : is_client ? fd_tls13_cli_sign_prefix : fd_tls13_srv_sign_prefix,
794 6018 : 98UL );
795 :
796 6018 : fd_sha256_t transcript_clone = *transcript;
797 6018 : fd_sha256_fini( &transcript_clone, sign_msg+98 );
798 :
799 : /* Verify certificate signature
800 : > If the verification fails, the receiver MUST terminate the handshake
801 : > with a "decrypt_error" alert. */
802 :
803 6018 : fd_sha512_t sha512[1];
804 6018 : int sig_err = fd_ed25519_verify( sign_msg, 130UL, vfy->sig, pubkey, sha512 );
805 6018 : if( FD_UNLIKELY( sig_err != FD_ED25519_SUCCESS ) )
806 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_ED25519_FAIL );
807 :
808 6018 : return (long)read_sz;
809 6018 : }
810 :
811 : static long
812 : fd_tls_server_hs_wait_finished( fd_tls_t const * server,
813 : fd_tls_estate_srv_t * handshake,
814 : uchar const * const record,
815 : ulong record_sz,
816 6018 : uint encryption_level ) {
817 :
818 6018 : (void)server;
819 :
820 6018 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
821 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
822 :
823 : /* Restore state ****************************************************/
824 :
825 6018 : fd_sha256_t transcript;
826 6018 : fd_tls_transcript_load( &handshake->transcript, &transcript );
827 :
828 : /* Decode incoming client "Finished" message ************************/
829 :
830 6018 : fd_tls_finished_t finished = {0};
831 :
832 6018 : ulong read_sz;
833 6018 : do {
834 6018 : uchar const * wire = record;
835 6018 : uchar const * const wire_end = record + record_sz;
836 :
837 : /* Decode message header */
838 :
839 6018 : fd_tls_msg_hdr_t msg_hdr = {0};
840 6018 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
841 6018 : if( FD_UNLIKELY( decode_res<0L ) )
842 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_FINI_PARSE );
843 6018 : wire += (ulong)decode_res;
844 :
845 6018 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_FINISHED ) )
846 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_FINI_EXPECTED );
847 :
848 : /* Decode server Finished */
849 :
850 6018 : decode_res = fd_tls_decode_finished( &finished, wire, (ulong)(wire_end-wire) );
851 6018 : if( FD_UNLIKELY( decode_res<0L ) )
852 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_FINI_PARSE );
853 6018 : wire += (ulong)decode_res;
854 :
855 6018 : read_sz = (ulong)(wire - record);
856 6018 : } while(0);
857 :
858 : /* Check "Finished" verify data *************************************/
859 :
860 : /* Export transcript hash */
861 :
862 6018 : uchar transcript_hash[ 32 ];
863 6018 : fd_sha256_fini( &transcript, transcript_hash );
864 :
865 : /* Derive "Finished" key */
866 :
867 6018 : uchar finished_key[ 32 ];
868 6018 : fd_tls_hkdf_expand_label( finished_key, 32UL,
869 6018 : handshake->client_hs_secret,
870 6018 : "finished", 8UL,
871 6018 : NULL, 0UL );
872 :
873 : /* Derive "Finished" verify data */
874 :
875 6018 : uchar finished_expected[ 32 ];
876 6018 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
877 6018 : /* salt */ finished_key, 32UL,
878 6018 : /* out */ finished_expected );
879 :
880 : /* Verify that client and server's transcripts match */
881 :
882 6018 : int match = 0;
883 198594 : for( ulong i=0; i<32UL; i++ )
884 192576 : match |= finished.verify[i] ^ finished_expected[i];
885 6018 : if( FD_UNLIKELY( match!=0 ) )
886 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_FINI_FAIL );
887 :
888 : /* Done */
889 :
890 6018 : handshake->base.state = FD_TLS_HS_CONNECTED;
891 6018 : return (long)read_sz;
892 6018 : }
893 :
894 : static long fd_tls_client_hs_start ( fd_tls_t const *, fd_tls_estate_cli_t * );
895 : static long fd_tls_client_hs_wait_sh ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
896 : static long fd_tls_client_hs_wait_ee ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
897 : static long fd_tls_client_hs_wait_cert_cr ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
898 : static long fd_tls_client_hs_wait_cert ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
899 : static long fd_tls_client_hs_wait_cert_verify( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
900 : static long fd_tls_client_hs_wait_finished ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
901 :
902 : long
903 : fd_tls_client_handshake( fd_tls_t const * client,
904 : fd_tls_estate_cli_t * handshake,
905 : void const * record,
906 : ulong record_sz,
907 36114 : uint encryption_level ) {
908 36114 : switch( handshake->base.state ) {
909 6021 : case FD_TLS_HS_START:
910 : /* Record argument is ignored, since ClientHello is always the first message */
911 6021 : (void)record; (void)record_sz; (void)encryption_level;
912 6021 : return fd_tls_client_hs_start( client, handshake );
913 6021 : case FD_TLS_HS_WAIT_SH:
914 : /* Incoming ServerHello */
915 6021 : return fd_tls_client_hs_wait_sh( client, handshake, record, record_sz, encryption_level );
916 6018 : case FD_TLS_HS_WAIT_EE:
917 : /* Incoming EncryptedExtensions */
918 6018 : return fd_tls_client_hs_wait_ee( client, handshake, record, record_sz, encryption_level );
919 6018 : case FD_TLS_HS_WAIT_CERT_CR:
920 : /* Incoming CertificateRequest or Certificate */
921 6018 : return fd_tls_client_hs_wait_cert_cr( client, handshake, record, record_sz, encryption_level );
922 0 : case FD_TLS_HS_WAIT_CERT:
923 : /* Incoming Certificate */
924 0 : return fd_tls_client_hs_wait_cert( client, handshake, record, record_sz, encryption_level );
925 6018 : case FD_TLS_HS_WAIT_CV:
926 : /* Incoming CertificateVerify */
927 6018 : return fd_tls_client_hs_wait_cert_verify( client, handshake, record, record_sz, encryption_level );
928 6018 : case FD_TLS_HS_WAIT_FINISHED:
929 : /* Incoming Server Finished */
930 6018 : return fd_tls_client_hs_wait_finished( client, handshake, record, record_sz, encryption_level );
931 0 : default:
932 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_ILLEGAL_STATE );
933 36114 : }
934 36114 : }
935 :
936 : static long
937 : fd_tls_client_hs_start( fd_tls_t const * const client,
938 6021 : fd_tls_estate_cli_t * const handshake ) {
939 :
940 : /* Request QUIC transport params */
941 6021 : uchar quic_tp[ FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ];
942 6021 : long quic_tp_sz = -1L;
943 6021 : if( client->quic )
944 6015 : quic_tp_sz = (long)client->quic_tp_self_fn( handshake, quic_tp, FD_TLS_EXT_QUIC_PARAMS_SZ_MAX );
945 6021 : if( FD_UNLIKELY( quic_tp_sz > (long)FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
946 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_QUIC_TP_OVERSZ );
947 :
948 : /* Message buffer */
949 6021 : # define MSG_BUFSZ 512UL
950 6021 : uchar msg_buf[ MSG_BUFSZ ];
951 :
952 : /* Transcript hasher */
953 6021 : fd_sha256_init( &handshake->transcript );
954 :
955 : /* Send ClientHello *************************************************/
956 :
957 : /* Create client random */
958 :
959 6021 : uchar client_random[ 32 ];
960 6021 : if( FD_UNLIKELY( !fd_tls_rand( &client->rand, client_random, 32UL ) ) )
961 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_RAND_FAIL );
962 :
963 : /* Remember client random for SSLKEYLOGFILE */
964 6021 : fd_memcpy( handshake->base.client_random, client_random, 32UL );
965 :
966 : /* Create client hello message */
967 :
968 6021 : ulong client_hello_sz;
969 :
970 6021 : do {
971 6021 : uchar * wire = msg_buf;
972 6021 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
973 :
974 : /* Leave space for message header */
975 :
976 6021 : void * hdr_ptr = wire;
977 6021 : wire += sizeof(fd_tls_msg_hdr_t);
978 6021 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_CLIENT_HELLO };
979 :
980 : /* Construct client hello */
981 :
982 6021 : fd_tls_client_hello_t ch = {
983 6021 : .supported_versions = { .tls13=1 },
984 6021 : .supported_groups = { .x25519=1 },
985 6021 : .signature_algorithms = { .ed25519=1 },
986 6021 : .cipher_suites = { .aes_128_gcm_sha256=1 },
987 6021 : .key_share = { .has_x25519=1 },
988 6021 : .server_cert_types = { .x509=!!client->cert_x509_sz, .raw_pubkey=1 },
989 6021 : .client_cert_types = { .x509=!!client->cert_x509_sz, .raw_pubkey=1 },
990 6021 : .quic_tp = {
991 6021 : .buf = (quic_tp_sz>=0L) ? quic_tp : NULL,
992 6021 : .bufsz = (quic_tp_sz>=0L) ? (ushort)quic_tp_sz : 0,
993 6021 : },
994 6021 : .alpn = {
995 6021 : .buf = client->alpn,
996 6021 : .bufsz = client->alpn_sz,
997 6021 : }
998 6021 : };
999 6021 : memcpy( ch.random, client_random, 32UL );
1000 6021 : memcpy( ch.key_share.x25519, client->kex_public_key, 32UL );
1001 :
1002 : /* Encode client hello */
1003 :
1004 6021 : long encode_res = fd_tls_encode_client_hello( &ch, wire, (ulong)(wire_end-wire) );
1005 6021 : if( FD_UNLIKELY( encode_res<0L ) )
1006 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_CH_ENCODE );
1007 6021 : wire += (ulong)encode_res;
1008 :
1009 6021 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
1010 6021 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
1011 6021 : client_hello_sz = (ulong)(wire - msg_buf);
1012 6021 : } while(0);
1013 :
1014 : /* Call back with client hello */
1015 :
1016 6021 : if( FD_UNLIKELY( !client->sendmsg_fn(
1017 6021 : handshake,
1018 6021 : msg_buf, client_hello_sz,
1019 6021 : FD_TLS_LEVEL_INITIAL,
1020 6021 : /* flush */ 1 ) ) )
1021 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
1022 :
1023 : /* Record client hello in transcript hash */
1024 :
1025 6021 : fd_sha256_append( &handshake->transcript, msg_buf, client_hello_sz );
1026 :
1027 : /* Finish up ********************************************************/
1028 :
1029 6021 : handshake->base.state = FD_TLS_HS_WAIT_SH;
1030 :
1031 6021 : # undef MSG_BUFSZ
1032 6021 : return 0L;
1033 6021 : }
1034 :
1035 : static long
1036 : fd_tls_client_hs_wait_sh( fd_tls_t const * const client,
1037 : fd_tls_estate_cli_t * const handshake,
1038 : uchar const * const record,
1039 : ulong const record_sz,
1040 6021 : uint const encryption_level ) {
1041 :
1042 6021 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_INITIAL ) )
1043 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
1044 :
1045 : /* Read server hello ************************************************/
1046 :
1047 6021 : fd_tls_server_hello_t sh[1] = {0};
1048 :
1049 6021 : ulong read_sz;
1050 6021 : do {
1051 6021 : uchar const * wire = record;
1052 6021 : uchar const * const wire_end = record + record_sz;
1053 :
1054 : /* Decode message header */
1055 :
1056 6021 : fd_tls_msg_hdr_t msg_hdr = {0};
1057 6021 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1058 6021 : if( FD_UNLIKELY( decode_res<0L ) )
1059 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_SH_PARSE );
1060 6021 : wire += (ulong)decode_res;
1061 :
1062 6021 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_SERVER_HELLO ) )
1063 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_SH_EXPECTED );
1064 :
1065 : /* Decode Server Hello */
1066 :
1067 6021 : decode_res = fd_tls_decode_server_hello( sh, wire, (ulong)(wire_end-wire) );
1068 6021 : if( FD_UNLIKELY( decode_res<0L ) )
1069 3 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_SH_PARSE );
1070 6018 : wire += (ulong)decode_res;
1071 :
1072 6018 : read_sz = (ulong)(wire - record);
1073 6018 : } while(0);
1074 :
1075 : /* Record server hello in transcript hash */
1076 :
1077 6018 : fd_sha256_append( &handshake->transcript, record, read_sz );
1078 :
1079 : /* TODO: For now, cryptographic parameters are hardcoded in the
1080 : decoder. Thus, we skip checks. */
1081 :
1082 : /* Derive handshake secrets *****************************************/
1083 :
1084 : /* TODO: This code is duplicated server-side */
1085 :
1086 : /* Export handshake transcript hash */
1087 :
1088 6018 : fd_sha256_t transcript_clone = handshake->transcript;
1089 6018 : uchar transcript_hash[ 32 ];
1090 6018 : fd_sha256_fini( &transcript_clone, transcript_hash );
1091 :
1092 : /* Derive ECDH input key material */
1093 :
1094 6018 : uchar _ecdh_ikm[ 32 ];
1095 6018 : void * ecdh_ikm = fd_x25519_exchange( _ecdh_ikm,
1096 6018 : client->kex_private_key,
1097 6018 : sh->key_share.x25519 );
1098 6018 : if( FD_UNLIKELY( !ecdh_ikm ) )
1099 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_X25519_FAIL );
1100 :
1101 : /* Derive main handshake secret */
1102 :
1103 6018 : uchar handshake_secret[ 32 ];
1104 6018 : fd_hmac_sha256( /* data */ ecdh_ikm, 32UL,
1105 6018 : /* salt */ handshake_derived, 32UL,
1106 6018 : /* out */ handshake_secret );
1107 :
1108 : /* Derive client/server handshake secrets */
1109 :
1110 6018 : fd_tls_hkdf_expand_label( handshake->client_hs_secret, 32UL,
1111 6018 : handshake_secret,
1112 6018 : "c hs traffic", 12UL,
1113 6018 : transcript_hash, 32UL );
1114 :
1115 6018 : fd_tls_hkdf_expand_label( handshake->server_hs_secret, 32UL,
1116 6018 : handshake_secret,
1117 6018 : "s hs traffic", 12UL,
1118 6018 : transcript_hash, 32UL );
1119 :
1120 : /* Call back with handshake secrets */
1121 :
1122 6018 : client->secrets_fn( handshake,
1123 6018 : /* read secret */ handshake->server_hs_secret,
1124 6018 : /* write secret */ handshake->client_hs_secret,
1125 6018 : FD_TLS_LEVEL_HANDSHAKE );
1126 :
1127 : /* Derive master secret */
1128 :
1129 6018 : uchar master_derive[ 32 ];
1130 6018 : fd_tls_hkdf_expand_label( master_derive, 32UL,
1131 6018 : handshake_secret,
1132 6018 : "derived", 7UL,
1133 6018 : empty_hash, 32UL );
1134 :
1135 6018 : static uchar const zeros[ 32 ] = {0};
1136 6018 : fd_hmac_sha256( /* data */ zeros, 32UL,
1137 6018 : /* salt */ master_derive, 32UL,
1138 6018 : /* out */ handshake->master_secret );
1139 :
1140 : /* Finish up ********************************************************/
1141 :
1142 6018 : handshake->base.state = FD_TLS_HS_WAIT_EE;
1143 :
1144 6018 : return (long)read_sz;
1145 6018 : }
1146 :
1147 : static long
1148 : fd_tls_client_hs_wait_ee( fd_tls_t const * const client,
1149 : fd_tls_estate_cli_t * const handshake,
1150 : uchar const * const record,
1151 : ulong const record_sz,
1152 6018 : uint const encryption_level ) {
1153 :
1154 6018 : (void)client;
1155 :
1156 6018 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1157 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
1158 :
1159 : /* Read EncryptedExtensions (EE) message ****************************/
1160 :
1161 6018 : fd_tls_enc_ext_t ee[1] = {0};
1162 :
1163 6018 : ulong read_sz;
1164 6018 : do {
1165 6018 : uchar const * wire = record;
1166 6018 : uchar const * const wire_end = record + record_sz;
1167 :
1168 : /* Decode message header */
1169 :
1170 6018 : fd_tls_msg_hdr_t msg_hdr = {0};
1171 6018 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1172 6018 : if( FD_UNLIKELY( decode_res<0L ) )
1173 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_EE_PARSE );
1174 6018 : wire += (ulong)decode_res;
1175 :
1176 6018 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_ENCRYPTED_EXT ) )
1177 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_EE_EXPECTED );
1178 :
1179 : /* Decode EncryptedExtensions */
1180 :
1181 6018 : decode_res = fd_tls_decode_enc_ext( ee, wire, (ulong)(wire_end-wire) );
1182 6018 : if( FD_UNLIKELY( decode_res<0L ) )
1183 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_EE_PARSE );
1184 6018 : wire += (ulong)decode_res;
1185 :
1186 6018 : read_sz = (ulong)(wire - record);
1187 6018 : } while(0);
1188 :
1189 : /* Record EE in transcript hash */
1190 :
1191 6018 : fd_sha256_append( &handshake->transcript, record, read_sz );
1192 :
1193 6018 : switch( ee->server_cert.cert_type ) {
1194 0 : case FD_TLS_CERTTYPE_X509:
1195 0 : break; /* ok */
1196 6018 : case FD_TLS_CERTTYPE_RAW_PUBKEY:
1197 6018 : handshake->server_cert_rpk = 1;
1198 6018 : break;
1199 0 : default:
1200 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_CERT_TYPE );
1201 6018 : }
1202 :
1203 6018 : handshake->client_cert_nox509 = 1;
1204 6018 : switch( ee->client_cert.cert_type ) {
1205 0 : case FD_TLS_CERTTYPE_X509:
1206 0 : handshake->client_cert_nox509 = 0;
1207 0 : break;
1208 6018 : case FD_TLS_CERTTYPE_RAW_PUBKEY:
1209 6018 : handshake->client_cert_rpk = 1;
1210 6018 : break;
1211 0 : default:
1212 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_CERT_TYPE );
1213 6018 : }
1214 :
1215 : /* QUIC mode */
1216 :
1217 6018 : if( client->quic ) {
1218 : /* QUIC transport parameters are mandatory in QUIC mode */
1219 6015 : if( FD_UNLIKELY( !ee->quic_tp.buf ) )
1220 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_EE_NO_QUIC );
1221 :
1222 : /* Inform user of peer's QUIC transport parameters */
1223 6015 : client->quic_tp_peer_fn( handshake, ee->quic_tp.buf, ee->quic_tp.bufsz );
1224 6015 : }
1225 :
1226 : /* Check ALPN */
1227 :
1228 6018 : if( client->alpn_sz ) {
1229 6015 : if( FD_UNLIKELY( !ee->alpn.bufsz ) )
1230 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_NO_ALPN );
1231 6015 : if( FD_UNLIKELY( ee->alpn.bufsz != client->alpn_sz ||
1232 6015 : 0!=memcmp( ee->alpn.buf, client->alpn, client->alpn_sz ) ) )
1233 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_ALPN_NEG );
1234 6015 : }
1235 :
1236 : /* Fail if server requested an X.509 client cert, but we can only
1237 : serve a raw public key. */
1238 :
1239 6018 : if( FD_UNLIKELY( ( !!handshake->client_cert )
1240 6018 : & ( !handshake->client_cert_rpk )
1241 6018 : & ( ( !client->cert_x509_sz )
1242 6018 : | ( !!handshake->client_cert_nox509 ) ) ) )
1243 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_NO_X509 );
1244 :
1245 : /* Finish up ********************************************************/
1246 :
1247 6018 : handshake->base.state = FD_TLS_HS_WAIT_CERT_CR;
1248 :
1249 6018 : return (long)read_sz;
1250 6018 : }
1251 :
1252 : static long
1253 : fd_tls_client_handle_cert_req( fd_tls_estate_cli_t * const handshake,
1254 : uchar const * const req,
1255 0 : ulong const req_sz ) {
1256 :
1257 : /* For now, just ignore the content of the certificate request.
1258 : TODO: This is obviously not compliant. */
1259 0 : (void)req; (void)req_sz;
1260 :
1261 0 : handshake->client_cert = 1;
1262 0 : handshake->base.state = FD_TLS_HS_WAIT_CERT;
1263 :
1264 0 : return (long)req_sz;
1265 0 : }
1266 :
1267 : static long
1268 : fd_tls_client_handle_cert_chain( fd_tls_estate_cli_t * const hs,
1269 : uchar const * const cert_chain,
1270 6018 : ulong const cert_chain_sz ) {
1271 : /* pubkey pinning is ...
1272 : ... enabled => check that public key matches cert
1273 : ... disabled => update the handshake's public key value based on cert */
1274 6018 : uchar const * expected_pubkey = ( hs->server_pubkey_pin) ? (hs->server_pubkey) : NULL;
1275 6018 : uchar * out_pubkey = (!hs->server_pubkey_pin) ? (hs->server_pubkey) : NULL;
1276 6018 : return fd_tls_handle_cert_chain( &hs->base, cert_chain, cert_chain_sz, expected_pubkey, out_pubkey, hs->server_cert_rpk );
1277 6018 : }
1278 :
1279 : static long
1280 : fd_tls_client_hs_wait_cert_cr( fd_tls_t const * const client,
1281 : fd_tls_estate_cli_t * const handshake,
1282 : uchar const * const record,
1283 : ulong const record_sz,
1284 6018 : uint const encryption_level ) {
1285 :
1286 6018 : (void)client;
1287 :
1288 6018 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1289 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
1290 :
1291 : /* Read Certificate(Request) ****************************************/
1292 :
1293 6018 : uchar next_state;
1294 :
1295 6018 : ulong read_sz;
1296 6018 : do {
1297 6018 : uchar const * wire = record;
1298 6018 : uchar const * const wire_end = record + record_sz;
1299 :
1300 : /* Decode message header */
1301 :
1302 6018 : fd_tls_msg_hdr_t msg_hdr = {0};
1303 6018 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1304 6018 : if( FD_UNLIKELY( decode_res<0L ) )
1305 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_CR_PARSE );
1306 6018 : wire += (ulong)decode_res;
1307 :
1308 6018 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1309 6018 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1310 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_CR_PARSE );
1311 :
1312 6018 : switch( msg_hdr.type ) {
1313 0 : case FD_TLS_MSG_CERT_REQ:
1314 0 : decode_res = fd_tls_client_handle_cert_req ( handshake, wire, msg_sz );
1315 0 : next_state = FD_TLS_HS_WAIT_CERT;
1316 0 : break;
1317 6018 : case FD_TLS_MSG_CERT:
1318 6018 : decode_res = fd_tls_client_handle_cert_chain( handshake, wire, msg_sz );
1319 6018 : next_state = FD_TLS_HS_WAIT_CV;
1320 6018 : break;
1321 0 : default:
1322 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CERT_CR_EXPECTED );
1323 6018 : }
1324 :
1325 6018 : if( FD_UNLIKELY( decode_res<0L ) )
1326 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CERT_CR_PARSE );
1327 6018 : wire += (ulong)decode_res;
1328 :
1329 6018 : read_sz = (ulong)(wire - record);
1330 6018 : } while(0);
1331 :
1332 6018 : fd_sha256_append( &handshake->transcript, record, read_sz );
1333 :
1334 : /* Finish up ********************************************************/
1335 :
1336 6018 : handshake->base.state = ((uchar)next_state);
1337 6018 : return (long)read_sz;
1338 6018 : }
1339 :
1340 : static long
1341 : fd_tls_client_hs_wait_cert( fd_tls_t const * const client,
1342 : fd_tls_estate_cli_t * const handshake,
1343 : uchar const * const record,
1344 : ulong const record_sz,
1345 0 : uint const encryption_level ) {
1346 :
1347 0 : (void)client;
1348 :
1349 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1350 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
1351 :
1352 : /* Read Certificate *************************************************/
1353 :
1354 0 : ulong read_sz;
1355 0 : do {
1356 0 : uchar const * wire = record;
1357 0 : uchar const * const wire_end = record + record_sz;
1358 :
1359 : /* Decode message header */
1360 :
1361 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1362 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1363 0 : if( FD_UNLIKELY( decode_res<0L ) )
1364 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_PARSE );
1365 0 : wire += (ulong)decode_res;
1366 :
1367 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CERT ) )
1368 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CERT_EXPECTED );
1369 :
1370 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1371 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1372 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_CR_PARSE );
1373 :
1374 : /* Decode Certificate */
1375 :
1376 0 : decode_res = fd_tls_client_handle_cert_chain( handshake, wire, msg_sz );
1377 0 : if( FD_UNLIKELY( decode_res<0L ) )
1378 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CERT_PARSE );
1379 0 : wire += (ulong)decode_res;
1380 :
1381 0 : read_sz = (ulong)(wire - record);
1382 0 : } while(0);
1383 :
1384 0 : fd_sha256_append( &handshake->transcript, record, read_sz );
1385 :
1386 : /* Finish up ********************************************************/
1387 :
1388 0 : handshake->base.state = (char)FD_TLS_HS_WAIT_CV;
1389 0 : return (long)read_sz;
1390 0 : }
1391 :
1392 : static long
1393 : fd_tls_client_hs_wait_cert_verify( fd_tls_t const * const client,
1394 : fd_tls_estate_cli_t * const hs,
1395 : uchar const * const record,
1396 : ulong const record_sz,
1397 6018 : uint const encryption_level ) {
1398 :
1399 6018 : (void)client;
1400 :
1401 6018 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1402 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
1403 :
1404 : /* Decode incoming server CertificateVerify *************************/
1405 :
1406 6018 : long res = fd_tls_handle_cert_verify( &hs->base, &hs->transcript, record, record_sz, hs->server_pubkey, 0 );
1407 6018 : if( FD_UNLIKELY( res<0L ) ) return res;
1408 :
1409 6018 : fd_sha256_append( &hs->transcript, record, (ulong)res );
1410 :
1411 : /* Finish up ********************************************************/
1412 :
1413 6018 : hs->base.state = FD_TLS_HS_WAIT_FINISHED;
1414 6018 : return res;
1415 6018 : }
1416 :
1417 : static long
1418 : fd_tls_client_hs_wait_finished( fd_tls_t const * const client,
1419 : fd_tls_estate_cli_t * const hs,
1420 : uchar const * const record,
1421 : ulong const record_sz,
1422 6018 : uint const encryption_level ) {
1423 :
1424 6018 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1425 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_WRONG_ENC_LVL );
1426 :
1427 : /* Export transcript hash ClientHello..CertificateVerify */
1428 :
1429 6018 : fd_sha256_t transcript_clone = hs->transcript;
1430 6018 : uchar transcript_hash[ 32 ];
1431 6018 : fd_sha256_fini( &transcript_clone, transcript_hash );
1432 :
1433 : /* Derive "Finished" key */
1434 :
1435 6018 : uchar server_finished_key[ 32 ];
1436 6018 : fd_tls_hkdf_expand_label( server_finished_key, 32UL,
1437 6018 : hs->server_hs_secret,
1438 6018 : "finished", 8UL,
1439 6018 : NULL, 0UL );
1440 :
1441 : /* Derive "Finished" verify data */
1442 :
1443 6018 : uchar server_finished_expected[ 32 ];
1444 6018 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
1445 6018 : /* salt */ server_finished_key, 32UL,
1446 6018 : /* out */ server_finished_expected );
1447 :
1448 : /* Read ServerFinished **********************************************/
1449 :
1450 6018 : fd_tls_finished_t server_fin = {0};
1451 :
1452 6018 : ulong read_sz;
1453 6018 : do {
1454 6018 : uchar const * wire = record;
1455 6018 : uchar const * const wire_end = record + record_sz;
1456 :
1457 : /* Decode message header */
1458 :
1459 6018 : fd_tls_msg_hdr_t msg_hdr = {0};
1460 6018 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1461 6018 : if( FD_UNLIKELY( decode_res<0L ) )
1462 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_FINI_PARSE );
1463 6018 : wire += (ulong)decode_res;
1464 :
1465 6018 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_FINISHED ) )
1466 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_FINI_EXPECTED );
1467 :
1468 : /* Decode server Finished */
1469 :
1470 6018 : decode_res = fd_tls_decode_finished( &server_fin, wire, (ulong)(wire_end-wire) );
1471 6018 : if( FD_UNLIKELY( decode_res<0L ) )
1472 0 : return fd_tls_alert( &hs->base, (uint)(-decode_res), FD_TLS_REASON_FINI_PARSE );
1473 6018 : wire += (ulong)decode_res;
1474 :
1475 6018 : read_sz = (ulong)(wire - record);
1476 6018 : } while(0);
1477 :
1478 : /* Record ServerFinished */
1479 :
1480 6018 : fd_sha256_append( &hs->transcript, record, read_sz );
1481 :
1482 : /* Verify that client and server's transcripts match */
1483 :
1484 6018 : int match = 0;
1485 198594 : for( ulong i=0; i<32UL; i++ ) {
1486 192576 : match |= server_fin.verify[i] ^ server_finished_expected[i];
1487 192576 : }
1488 6018 : if( FD_UNLIKELY( match!=0 ) )
1489 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_FINI_FAIL );
1490 :
1491 : /* Derive application secrets ***************************************/
1492 :
1493 : /* Export transcript hash ClientHello..ServerFinished */
1494 :
1495 6018 : transcript_clone = hs->transcript;
1496 6018 : fd_sha256_fini( &transcript_clone, transcript_hash );
1497 :
1498 : /* Derive client/server application secrets */
1499 :
1500 6018 : uchar client_app_secret[ 32UL ];
1501 6018 : fd_tls_hkdf_expand_label( client_app_secret, 32UL,
1502 6018 : hs->master_secret,
1503 6018 : "c ap traffic", 12UL,
1504 6018 : transcript_hash, 32UL );
1505 :
1506 6018 : uchar server_app_secret[ 32UL ];
1507 6018 : fd_tls_hkdf_expand_label( server_app_secret, 32UL,
1508 6018 : hs->master_secret,
1509 6018 : "s ap traffic", 12UL,
1510 6018 : transcript_hash, 32UL );
1511 :
1512 : /* Call back with application secrets */
1513 :
1514 6018 : client->secrets_fn( hs,
1515 6018 : /* read secret */ server_app_secret,
1516 6018 : /* write secret */ client_app_secret,
1517 6018 : FD_TLS_LEVEL_APPLICATION );
1518 :
1519 6018 : if( hs->client_cert ) {
1520 :
1521 : /* Send client Certificate ****************************************/
1522 :
1523 : /* TODO deduplicate this */
1524 :
1525 : /* Message buffer */
1526 0 : # define MSG_BUFSZ 512UL
1527 0 : uchar msg_buf[ MSG_BUFSZ ];
1528 :
1529 : /* TODO: fd_tls does not support certificate_request_context.
1530 : It is an opaque string that the server may send in the cert
1531 : request. The client is supposed to echo it back in its cert
1532 : message. However, the server is not supposed to send it in the
1533 : first place, unless post-handshake auth is used (which is not
1534 : the case) */
1535 :
1536 0 : ulong cert_msg_sz;
1537 0 : if( hs->client_cert_rpk ) {
1538 0 : long sz = fd_tls_encode_raw_public_key( client->cert_public_key, msg_buf, MSG_BUFSZ );
1539 0 : FD_TEST( sz>=0L );
1540 0 : cert_msg_sz = (ulong)sz;
1541 0 : } else if( client->cert_x509_sz ) {
1542 : /* TODO: Technically should check whether the server supports
1543 : X.509. There could be servers that support neither X.509 nor
1544 : raw public keys. */
1545 :
1546 0 : long sz = fd_tls_encode_cert_x509( client->cert_x509, client->cert_x509_sz, msg_buf, MSG_BUFSZ );
1547 0 : FD_TEST( sz>=0L );
1548 0 : cert_msg_sz = (ulong)sz;
1549 0 : } else {
1550 : /* TODO: Unreachable: We should have verified whether we have
1551 : an appropriate certificate in wait_cert_cr. */
1552 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_CERT_TYPE );
1553 0 : }
1554 :
1555 : /* Send certificate message */
1556 :
1557 0 : if( FD_UNLIKELY( !client->sendmsg_fn(
1558 0 : hs,
1559 0 : msg_buf, cert_msg_sz,
1560 0 : FD_TLS_LEVEL_HANDSHAKE,
1561 0 : /* flush */ 0 ) ) )
1562 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
1563 :
1564 : /* Record Certificate message in transcript hash */
1565 :
1566 0 : fd_sha256_append( &hs->transcript, msg_buf, cert_msg_sz );
1567 :
1568 : /* Send client CertificateVerify **********************************/
1569 :
1570 0 : long cvfy_res = fd_tls_send_cert_verify( client, &hs->base, &hs->transcript, 1 );
1571 0 : if( FD_UNLIKELY( !!cvfy_res ) ) return cvfy_res;
1572 :
1573 0 : # undef MSG_BUFSZ
1574 :
1575 0 : }
1576 :
1577 : /* Send client Finished *********************************************/
1578 :
1579 6018 : struct __attribute__((packed)) {
1580 6018 : fd_tls_msg_hdr_t hdr;
1581 6018 : fd_tls_finished_t fin;
1582 6018 : } fin_rec;
1583 6018 : fin_rec.hdr = (fd_tls_msg_hdr_t){
1584 6018 : .type = FD_TLS_MSG_FINISHED,
1585 6018 : .sz = fd_uint_to_tls_u24( 0x20 )
1586 6018 : };
1587 :
1588 6018 : fd_tls_msg_hdr_bswap( &fin_rec.hdr );
1589 :
1590 : /* Export transcript hash up to this point */
1591 :
1592 6018 : fd_sha256_fini( &hs->transcript, transcript_hash );
1593 :
1594 : /* Derive "Finished" key */
1595 :
1596 6018 : uchar client_finished_key[ 32 ];
1597 6018 : fd_tls_hkdf_expand_label( client_finished_key, 32UL,
1598 6018 : hs->client_hs_secret,
1599 6018 : "finished", 8UL,
1600 6018 : NULL, 0UL );
1601 :
1602 : /* Derive "Finished" verify data */
1603 :
1604 6018 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
1605 6018 : /* salt */ client_finished_key, 32UL,
1606 6018 : /* out */ fin_rec.fin.verify );
1607 :
1608 : /* Send client Finished message */
1609 :
1610 6018 : if( FD_UNLIKELY( !client->sendmsg_fn(
1611 6018 : hs,
1612 6018 : &fin_rec, sizeof(fin_rec),
1613 6018 : FD_TLS_LEVEL_HANDSHAKE,
1614 6018 : /* flush */ 1 ) ) )
1615 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
1616 :
1617 6018 : hs->base.state = FD_TLS_HS_CONNECTED;
1618 6018 : return (long)read_sz;
1619 6018 : }
1620 :
1621 : FD_FN_PURE char const *
1622 0 : fd_tls_alert_cstr( uint alert ) {
1623 0 : switch( alert ) {
1624 0 : case FD_TLS_ALERT_UNEXPECTED_MESSAGE:
1625 0 : return "unexpected message";
1626 0 : case FD_TLS_ALERT_BAD_RECORD_MAC:
1627 0 : return "bad record MAC";
1628 0 : case FD_TLS_ALERT_RECORD_OVERFLOW:
1629 0 : return "record overflow";
1630 0 : case FD_TLS_ALERT_HANDSHAKE_FAILURE:
1631 0 : return "handshake failure";
1632 0 : case FD_TLS_ALERT_BAD_CERTIFICATE:
1633 0 : return "bad certificate";
1634 0 : case FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE:
1635 0 : return "unsupported certificate";
1636 0 : case FD_TLS_ALERT_CERTIFICATE_REVOKED:
1637 0 : return "certificate revoked";
1638 0 : case FD_TLS_ALERT_CERTIFICATE_EXPIRED:
1639 0 : return "certificate expired";
1640 0 : case FD_TLS_ALERT_CERTIFICATE_UNKNOWN:
1641 0 : return "certificate unknown";
1642 0 : case FD_TLS_ALERT_ILLEGAL_PARAMETER:
1643 0 : return "illegal parameter";
1644 0 : case FD_TLS_ALERT_UNKNOWN_CA:
1645 0 : return "unknown CA";
1646 0 : case FD_TLS_ALERT_ACCESS_DENIED:
1647 0 : return "access denied";
1648 0 : case FD_TLS_ALERT_DECODE_ERROR:
1649 0 : return "decode error";
1650 0 : case FD_TLS_ALERT_DECRYPT_ERROR:
1651 0 : return "decrypt error";
1652 0 : case FD_TLS_ALERT_PROTOCOL_VERSION:
1653 0 : return "unsupported protocol version";
1654 0 : case FD_TLS_ALERT_INSUFFICIENT_SECURITY:
1655 0 : return "insufficient security";
1656 0 : case FD_TLS_ALERT_INTERNAL_ERROR:
1657 0 : return "internal error";
1658 0 : case FD_TLS_ALERT_INAPPROPRIATE_FALLBACK:
1659 0 : return "inappropriate fallback";
1660 0 : case FD_TLS_ALERT_USER_CANCELED:
1661 0 : return "user canceled";
1662 0 : case FD_TLS_ALERT_MISSING_EXTENSION:
1663 0 : return "missing extension";
1664 0 : case FD_TLS_ALERT_UNSUPPORTED_EXTENSION:
1665 0 : return "unsupported extension";
1666 0 : case FD_TLS_ALERT_UNRECOGNIZED_NAME:
1667 0 : return "unrecognized name";
1668 0 : case FD_TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE:
1669 0 : return "bad certificate status response";
1670 0 : case FD_TLS_ALERT_UNKNOWN_PSK_IDENTITY:
1671 0 : return "unknown PSK identity";
1672 0 : case FD_TLS_ALERT_CERTIFICATE_REQUIRED:
1673 0 : return "certificate required";
1674 0 : case FD_TLS_ALERT_NO_APPLICATION_PROTOCOL:
1675 0 : return "no application protocol";
1676 0 : default:
1677 0 : FD_LOG_WARNING(( "Missing fd_tls_alert_cstr code for %u (memory corruption?)", alert ));
1678 0 : return "unknown alert";
1679 : /* TODO add the other alert codes */
1680 0 : }
1681 0 : }
1682 :
1683 : FD_FN_PURE char const *
1684 0 : fd_tls_reason_cstr( uint reason ) {
1685 0 : switch( reason ) {
1686 0 : case FD_TLS_REASON_ILLEGAL_STATE:
1687 0 : return "illegal handshake state ID (memory corruption?)";
1688 0 : case FD_TLS_REASON_SENDMSG_FAIL:
1689 0 : return "sendmsg callback failed";
1690 0 : case FD_TLS_REASON_WRONG_ENC_LVL:
1691 0 : return "wrong encryption level";
1692 0 : case FD_TLS_REASON_RAND_FAIL:
1693 0 : return "rand function failed";
1694 0 : case FD_TLS_REASON_CH_EXPECTED:
1695 0 : return "expected ClientHello, but got other message type";
1696 0 : case FD_TLS_REASON_CH_PARSE:
1697 0 : return "failed to decode ClientHello";
1698 0 : case FD_TLS_REASON_CH_ENCODE:
1699 0 : return "failed to encode ClientHello";
1700 0 : case FD_TLS_REASON_CH_CRYPTO_NEG:
1701 0 : return "unsupported cryptographic parameters (fd_tls only supports TLS 1.3, X25519, Ed25519, AES-128-GCM)";
1702 0 : case FD_TLS_REASON_CH_NO_QUIC:
1703 0 : return "client does not support QUIC (missing QUIC transport params)";
1704 0 : case FD_TLS_REASON_X25519_FAIL:
1705 0 : return "X25519 key exchange failed";
1706 0 : case FD_TLS_REASON_NO_X509:
1707 0 : return "peer requested X.509 cert, but we don't have one";
1708 0 : case FD_TLS_REASON_WRONG_PUBKEY:
1709 0 : return "peer identity does not match expected public key";
1710 0 : case FD_TLS_REASON_ED25519_FAIL:
1711 0 : return "Ed25519 signature verification failed";
1712 0 : case FD_TLS_REASON_FINI_FAIL:
1713 0 : return "unexpected 'Finished' data (transcript hash fail)";
1714 0 : case FD_TLS_REASON_QUIC_TP_OVERSZ:
1715 0 : return "buffer overflow in QUIC transport param handling (user bug)";
1716 0 : case FD_TLS_REASON_EE_NO_QUIC:
1717 0 : return "server does not support QUIC (missing QUIC transport params)";
1718 0 : case FD_TLS_REASON_X509_PARSE:
1719 0 : return "X.509 cert parse failed";
1720 0 : case FD_TLS_REASON_SPKI_PARSE:
1721 0 : return "Raw public key parse failed";
1722 0 : case FD_TLS_REASON_CV_EXPECTED:
1723 0 : return "expected CertificateVerify, but got other message type";
1724 0 : case FD_TLS_REASON_CV_SIGALG:
1725 0 : return "peer CertificateVerify contains uses incorrect signature algorithm";
1726 0 : case FD_TLS_REASON_FINI_PARSE:
1727 0 : return "failed to parse 'Finished' message";
1728 0 : case FD_TLS_REASON_SH_EXPECTED:
1729 0 : return "expected ServerHello, but got other message type";
1730 0 : case FD_TLS_REASON_SH_PARSE:
1731 0 : return "failed to decode ServerHello";
1732 0 : case FD_TLS_REASON_SH_ENCODE:
1733 0 : return "failed to encode ServerHello";
1734 0 : case FD_TLS_REASON_EE_EXPECTED:
1735 0 : return "expected EncryptedExtensions, but got other message type";
1736 0 : case FD_TLS_REASON_EE_PARSE:
1737 0 : return "failed to decode EncryptedExtensions";
1738 0 : case FD_TLS_REASON_EE_ENCODE:
1739 0 : return "failed to encode EncryptedExtensions";
1740 0 : case FD_TLS_REASON_CERT_TYPE:
1741 0 : return "unsupported certificate type";
1742 0 : case FD_TLS_REASON_CERT_EXPECTED:
1743 0 : return "expected Certificate, but got other message type";
1744 0 : case FD_TLS_REASON_CERT_PARSE:
1745 0 : return "failed to decode Certificate";
1746 0 : case FD_TLS_REASON_FINI_EXPECTED:
1747 0 : return "expected Finished, but got other message type";
1748 0 : case FD_TLS_REASON_CERT_CR_EXPECTED:
1749 0 : return "expected Certificate or CertificateRequest, but got other message type";
1750 0 : case FD_TLS_REASON_CERT_CR_PARSE:
1751 0 : return "failed to decode Certificate or CertificateRequest";
1752 0 : case FD_TLS_REASON_CERT_CHAIN_EMPTY:
1753 0 : return "peer did not provide a certificate";
1754 0 : case FD_TLS_REASON_CERT_CHAIN_PARSE:
1755 0 : return "invalid peer cert chain";
1756 0 : case FD_TLS_REASON_CV_PARSE:
1757 0 : return "failed to decode CertificateVerify";
1758 0 : case FD_TLS_REASON_CV_ENCODE:
1759 0 : return "failed to encode CertificateVerify";
1760 0 : case FD_TLS_REASON_ALPN_PARSE:
1761 0 : return "failed to decode ALPN extension";
1762 0 : case FD_TLS_REASON_ALPN_NEG:
1763 0 : return "ALPN negotiation failed";
1764 0 : case FD_TLS_REASON_NO_ALPN:
1765 0 : return "peer did not send ALPN extension";
1766 0 : default:
1767 0 : FD_LOG_WARNING(( "Missing fd_tls_reason_cstr code for %u (memory corruption?)", reason ));
1768 0 : __attribute__((fallthrough));
1769 : /* TODO need to add a lot more error reason codes */
1770 0 : case FD_TLS_REASON_NULL:
1771 0 : return "unknown reason";
1772 0 : }
1773 0 : }
|