Line data Source code
1 : #include "fd_tls.h"
2 : #include "../../util/sanitize/fd_msan.h"
3 : #include "fd_tls_proto.h"
4 : #include "../../ballet/ed25519/fd_ed25519.h"
5 : #include "../../ballet/ed25519/fd_x25519.h"
6 : #include "../../ballet/hmac/fd_hmac.h"
7 : #include "../../ballet/secp256r1/fd_secp256r1.h"
8 : #include "../../ballet/x509/fd_x509.h"
9 : #include "../../ballet/x509/fd_x509_verify.h"
10 :
11 : /* Pre-generated keys */
12 :
13 : char const fd_tls13_cli_sign_prefix[ 98 ] =
14 : " " /* 32 spaces */
15 : " " /* 32 spaces */
16 : "TLS 1.3, client CertificateVerify";
17 :
18 : char const fd_tls13_srv_sign_prefix[ 98 ] =
19 : " " /* 32 spaces */
20 : " " /* 32 spaces */
21 : "TLS 1.3, server CertificateVerify";
22 :
23 : //uchar empty_hash[ 32 ];
24 : //fd_sha256_hash( empty_hash, NULL, 0UL );
25 : static uchar const empty_hash[ 32 ] =
26 : { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
27 : 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
28 : 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
29 : 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 };
30 :
31 : //static uchar const psk[ 32 ] = {0};
32 : //uchar early_secret[ 32 ];
33 : //fd_hmac_sha256( /* data */ psk, 32UL,
34 : // /* salt */ NULL, 0UL,
35 : // early_secret );
36 : //static uchar const early_secret[ 32 ] =
37 : // { 0x33, 0xad, 0x0a, 0x1c, 0x60, 0x7e, 0xc0, 0x3b,
38 : // 0x09, 0xe6, 0xcd, 0x98, 0x93, 0x68, 0x0c, 0xe2,
39 : // 0x10, 0xad, 0xf3, 0x00, 0xaa, 0x1f, 0x26, 0x60,
40 : // 0xe1, 0xb2, 0x2e, 0x10, 0xf1, 0x70, 0xf9, 0x2a };
41 :
42 : //uchar handshake_derived[ 32 ];
43 : //fd_tls_hkdf_expand_label( handshake_derived,
44 : // early_secret,
45 : // "derived", 7UL,
46 : // empty_hash, 32UL );
47 : static uchar const handshake_derived[ 32 ] =
48 : { 0x6f, 0x26, 0x15, 0xa1, 0x08, 0xc7, 0x02, 0xc5,
49 : 0x67, 0x8f, 0x54, 0xfc, 0x9d, 0xba, 0xb6, 0x97,
50 : 0x16, 0xc0, 0x76, 0x18, 0x9c, 0x48, 0x25, 0x0c,
51 : 0xeb, 0xea, 0xc3, 0x57, 0x6c, 0x36, 0x11, 0xba };
52 :
53 : /* fd_tls_t boilerplate */
54 :
55 : ulong
56 0 : fd_tls_align( void ) {
57 0 : return alignof(fd_tls_t);
58 0 : }
59 :
60 : ulong
61 0 : fd_tls_footprint( void ) {
62 0 : return sizeof(fd_tls_t);
63 0 : }
64 :
65 : void *
66 0 : fd_tls_new( void * mem ) {
67 :
68 0 : if( FD_UNLIKELY( !mem ) ) {
69 0 : FD_LOG_WARNING(( "NULL mem" ));
70 0 : return NULL;
71 0 : }
72 :
73 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_tls_align() ) ) ) {
74 0 : FD_LOG_WARNING(( "unaligned mem" ));
75 0 : return NULL;
76 0 : }
77 :
78 0 : ulong fp = fd_tls_footprint();
79 0 : memset( mem, 0, fp );
80 0 : return mem;
81 0 : }
82 :
83 : fd_tls_t *
84 0 : fd_tls_join( void * mem ) {
85 0 : return (fd_tls_t *)mem;
86 0 : }
87 :
88 : void *
89 0 : fd_tls_leave( fd_tls_t * server ) {
90 0 : return (void *)server;
91 0 : }
92 :
93 : void *
94 0 : fd_tls_delete( void * mem ) {
95 0 : return mem;
96 0 : }
97 :
98 : /* TODO create internal state machine and integrate Tango for
99 : accelerating cryptographic computations (e.g. FPGA sigverify) */
100 :
101 : fd_tls_estate_srv_t *
102 0 : fd_tls_estate_srv_new( void * mem ) {
103 :
104 0 : fd_tls_estate_srv_t * hs = mem;
105 :
106 0 : memset( hs, 0, sizeof(fd_tls_estate_srv_t) );
107 0 : hs->base.state = FD_TLS_HS_START;
108 0 : hs->base.server = 1;
109 :
110 0 : return hs;
111 0 : }
112 :
113 : fd_tls_estate_cli_t *
114 0 : fd_tls_estate_cli_new( void * mem ) {
115 :
116 0 : fd_tls_estate_cli_t * hs = mem;
117 :
118 0 : memset( hs, 0, sizeof(fd_tls_estate_cli_t) );
119 0 : hs->base.state = FD_TLS_HS_START;
120 :
121 0 : return hs;
122 0 : }
123 :
124 : static void
125 0 : fd_tls_clear_secret( uchar (*secret)[ 32 ] ) {
126 0 : fd_memzero_explicit( *secret, 32UL );
127 0 : }
128 :
129 : void *
130 : fd_tls_hkdf_expand_label( uchar * out,
131 : ulong out_sz,
132 : uchar const secret[ 32 ],
133 : char const * label,
134 : ulong label_sz,
135 : uchar const * context,
136 0 : ulong context_sz ) {
137 :
138 0 : # define LABEL_BUFSZ (64UL)
139 0 : FD_TEST( label_sz <=LABEL_BUFSZ );
140 0 : FD_TEST( context_sz<=LABEL_BUFSZ );
141 0 : FD_TEST( out_sz <=32UL );
142 :
143 : /* Create HKDF info */
144 0 : uchar info[ 2+1+6+LABEL_BUFSZ+1+LABEL_BUFSZ+1 ];
145 0 : ulong info_sz = 0UL;
146 :
147 : /* Length of hash output */
148 0 : info[0]=0; info[1]=(uchar)out_sz;
149 0 : info_sz += 2UL;
150 :
151 : /* Length prefix of label */
152 0 : info[ info_sz ] = (uchar)( 6UL + label_sz );
153 0 : info_sz += 1UL;
154 :
155 : /* Label */
156 0 : memcpy( info+info_sz, "tls13 ", 6UL );
157 0 : info_sz += 6UL;
158 0 : memcpy( info+info_sz, label, label_sz );
159 0 : info_sz += label_sz;
160 :
161 : /* Length prefix of context */
162 0 : info[ info_sz ] = (uchar)( context_sz );
163 0 : info_sz += 1UL;
164 :
165 : /* Context */
166 0 : fd_memcpy( info+info_sz, context, context_sz );
167 0 : info_sz += context_sz;
168 :
169 : /* HKDF-Expand suffix */
170 0 : info[ info_sz ] = 0x01;
171 0 : info_sz += 1UL;
172 :
173 : /* Compute result of HKDF-Expand-Label */
174 0 : uchar hash[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
175 0 : fd_msan_unpoison( info, info_sz );
176 0 : fd_hmac_sha256( info, info_sz, secret, 32UL, hash );
177 0 : fd_memcpy( out, hash, out_sz );
178 0 : return out;
179 0 : # undef LABEL_BUFSZ
180 0 : }
181 :
182 : static int
183 : fd_tls_has_alpn( uchar const * list,
184 : ulong const list_sz,
185 : uchar const * target,
186 0 : ulong const target_sz ) {
187 0 : if( FD_UNLIKELY( target_sz<=1UL ) ) return 0;
188 :
189 0 : uchar const * list_end = list + list_sz;
190 0 : while( list < list_end ) {
191 0 : ulong ele_sz = list[0];
192 0 : list += 1UL;
193 0 : uchar const * ele = list;
194 0 : if( FD_UNLIKELY( (long)ele_sz > list_end-list ) ) return -1;
195 0 : list += ele_sz;
196 :
197 0 : if( ele_sz==target_sz-1UL )
198 0 : if( 0==memcmp( ele, target+1UL, ele_sz ) )
199 0 : return 1;
200 0 : }
201 0 : return 0;
202 0 : }
203 :
204 : /* fd_tls_alert is a convenience function for setting a handshake
205 : failure alert and reason code. */
206 :
207 : static inline long __attribute__((warn_unused_result))
208 : fd_tls_alert( fd_tls_estate_base_t * hs,
209 : uint alert,
210 0 : ushort reason ) { /* hint if not yet set */
211 0 : hs->state = FD_TLS_HS_FAIL;
212 0 : if( !hs->reason ) hs->reason = reason;
213 0 : return -(long)alert;
214 0 : }
215 :
216 : /* fd_tls_send_cert_verify generates and sends a CertificateVerify
217 : message. Returns 0L on success and negated TLS alert number on
218 : failure. this is the local client or server object. hs is the
219 : local handshake object. transcript is the hash state immediately
220 : preceding the CertificateVerify (where last entry is Certificate).
221 : is_client is 1 if the local role is a client, 0 otherwise. */
222 :
223 : static long
224 : fd_tls_send_cert_verify( fd_tls_t const * this,
225 : fd_tls_estate_base_t * hs,
226 : fd_sha256_t * transcript,
227 0 : int is_client ) {
228 :
229 : /* Export current transcript hash
230 : And create message to be signed */
231 :
232 0 : uchar sign_msg[ FD_TLS_CV_SIGN_SZ ];
233 0 : fd_memcpy( sign_msg,
234 0 : is_client ? fd_tls13_cli_sign_prefix : fd_tls13_srv_sign_prefix,
235 0 : 98UL );
236 :
237 0 : fd_sha256_t transcript_clone = *transcript;
238 0 : fd_sha256_fini( &transcript_clone, sign_msg+98 );
239 :
240 : /* Sign certificate */
241 :
242 0 : uchar cert_verify_sig[ FD_ED25519_SIG_SZ ];
243 0 : fd_tls_sign( &this->sign, cert_verify_sig, sign_msg );
244 :
245 : /* Create CertificateVerify message */
246 :
247 0 : # define MSG_BUFSZ (512UL)
248 0 : uchar msg_buf[ MSG_BUFSZ ];
249 :
250 0 : ulong cv_sz;
251 :
252 0 : do {
253 0 : uchar * wire = msg_buf;
254 0 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
255 :
256 : /* Leave space for message header */
257 :
258 0 : void * hdr_ptr = wire;
259 0 : wire += sizeof(fd_tls_msg_hdr_t);
260 0 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_CERT_VERIFY };
261 :
262 : /* Construct CertificateVerify */
263 :
264 0 : fd_tls_cert_verify_t cv = {
265 0 : .algorithm = FD_TLS_SIGNATURE_ED25519,
266 0 : .signature_len = 64,
267 0 : };
268 0 : fd_memcpy( cv.signature, cert_verify_sig, FD_ED25519_SIG_SZ );
269 :
270 : /* Encode CertificateVerify */
271 :
272 0 : long encode_res = fd_tls_encode_cert_verify( &cv, wire, (ulong)(wire_end-wire) );
273 0 : if( FD_UNLIKELY( encode_res<0L ) )
274 0 : return fd_tls_alert( hs, (uint)(-encode_res), FD_TLS_REASON_CV_ENCODE );
275 0 : wire += (ulong)encode_res;
276 :
277 0 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
278 0 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
279 0 : cv_sz = (ulong)(wire - msg_buf);
280 0 : } while(0);
281 :
282 : /* Send CertificateVerify message */
283 :
284 0 : if( FD_UNLIKELY( !this->sendmsg_fn(
285 0 : hs,
286 0 : msg_buf, cv_sz,
287 0 : FD_TLS_LEVEL_HANDSHAKE,
288 0 : /* flush */ 0 ) ) )
289 0 : return fd_tls_alert( hs, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
290 :
291 : /* Record CertificateVerify in transcript hash */
292 :
293 0 : fd_sha256_append( transcript, msg_buf, cv_sz );
294 :
295 0 : # undef MSG_BUFSZ
296 0 : return 0L;
297 0 : }
298 :
299 : static long fd_tls_server_hs_start ( fd_tls_t const *, fd_tls_estate_srv_t *, uchar const *, ulong, uint );
300 : static long fd_tls_server_hs_wait_cert ( fd_tls_t const *, fd_tls_estate_srv_t *, uchar const *, ulong, uint );
301 : static long fd_tls_server_hs_wait_cert_verify( fd_tls_t const *, fd_tls_estate_srv_t *, uchar const *, ulong, uint );
302 : static long fd_tls_server_hs_wait_finished ( fd_tls_t const *, fd_tls_estate_srv_t *, uchar const *, ulong, uint );
303 :
304 : long
305 : fd_tls_server_handshake( fd_tls_t const * server,
306 : fd_tls_estate_srv_t * handshake,
307 : void const * msg,
308 : ulong msg_sz,
309 0 : uint encryption_level ) {
310 0 : switch( handshake->base.state ) {
311 0 : case FD_TLS_HS_START:
312 0 : return fd_tls_server_hs_start ( server, handshake, msg, msg_sz, encryption_level );
313 0 : case FD_TLS_HS_WAIT_CERT:
314 0 : return fd_tls_server_hs_wait_cert ( server, handshake, msg, msg_sz, encryption_level );
315 0 : case FD_TLS_HS_WAIT_CV:
316 0 : return fd_tls_server_hs_wait_cert_verify( server, handshake, msg, msg_sz, encryption_level );
317 0 : case FD_TLS_HS_WAIT_FINISHED:
318 0 : return fd_tls_server_hs_wait_finished ( server, handshake, msg, msg_sz, encryption_level );
319 0 : default:
320 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_ILLEGAL_STATE );
321 0 : }
322 0 : }
323 :
324 : static long
325 : fd_tls_server_hs_retry( fd_tls_t const * server,
326 : fd_tls_estate_srv_t * handshake,
327 : fd_tls_client_hello_t const * ch,
328 0 : uchar const ch1_hash[32] ) {
329 :
330 0 : if( FD_UNLIKELY( handshake->hello_retry ) ) {
331 : /* Already retried but still no X25519 share */
332 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_ILLEGAL_PARAMETER, FD_TLS_REASON_CH_RETRY_KS );
333 0 : }
334 0 : handshake->hello_retry = 1;
335 :
336 : /* Message buffer */
337 0 : # define MSG_BUFSZ 512UL
338 0 : uchar msg_buf[ MSG_BUFSZ ];
339 :
340 : /* Transcript hasher (RetryHelloRequest variation)
341 : https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.1 */
342 0 : fd_sha256_t transcript; fd_sha256_init( &transcript );
343 0 : uchar const transcript_prefix[] = { 254, 0x00, 0x00, 32 };
344 0 : fd_sha256_append( &transcript, transcript_prefix, sizeof(transcript_prefix) );
345 0 : fd_sha256_append( &transcript, ch1_hash, 32 );
346 :
347 : /* Create HelloRetryRequest message */
348 :
349 0 : ulong server_hello_sz;
350 :
351 0 : do {
352 0 : uchar * wire = msg_buf;
353 0 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
354 :
355 : /* Leave space for message header */
356 :
357 0 : void * hdr_ptr = wire;
358 0 : wire += sizeof(fd_tls_msg_hdr_t);
359 0 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_SERVER_HELLO };
360 :
361 : /* Construct server hello */
362 :
363 0 : fd_tls_server_hello_t sh = {
364 0 : .cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256,
365 0 : .key_share = { .has_x25519 = 1 },
366 0 : .session_id = ch->session_id,
367 0 : };
368 0 : memcpy( sh.key_share.x25519, server->kex_public_key, 32UL );
369 :
370 : /* Encode server hello */
371 :
372 0 : long encode_res = fd_tls_encode_hello_retry_request( &sh, wire, (ulong)(wire_end-wire) );
373 0 : if( FD_UNLIKELY( encode_res<0L ) )
374 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_SH_ENCODE );
375 0 : wire += (ulong)encode_res;
376 :
377 0 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
378 0 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
379 0 : server_hello_sz = (ulong)(wire - msg_buf);
380 0 : } while(0);
381 :
382 : /* Call back with HelloRetryRequest */
383 :
384 0 : if( FD_UNLIKELY( !server->sendmsg_fn(
385 0 : handshake,
386 0 : msg_buf, server_hello_sz,
387 0 : FD_TLS_LEVEL_INITIAL,
388 0 : /* flush */ 1 ) ) )
389 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
390 :
391 : /* Record HelloRetryRequest in transcript hash */
392 :
393 0 : fd_sha256_append( &transcript, msg_buf, server_hello_sz );
394 :
395 : /* Finish up ********************************************************/
396 :
397 : /* Store transcript hash state */
398 :
399 0 : fd_tls_transcript_store( &handshake->transcript, &transcript );
400 :
401 : /* Done */
402 :
403 0 : handshake->base.state = FD_TLS_HS_START;
404 :
405 0 : # undef MSG_BUFSZ
406 0 : return (long)0L;
407 0 : }
408 :
409 : /* fd_tls_server_hs_start is invoked in response to the initial
410 : ClientHello. We send back several messages in response, including
411 : - the ServerHello, completing cryptographic negotiation
412 : - EncryptedExtensions, for further handshake data
413 : - Finished, completing the server's handshake message sequence */
414 :
415 : static long
416 : fd_tls_server_hs_start( fd_tls_t const * const server,
417 : fd_tls_estate_srv_t * const handshake,
418 : uchar const * const record,
419 : ulong record_sz,
420 0 : uint encryption_level ) {
421 :
422 : /* Request QUIC transport params */
423 0 : uchar quic_tp[ FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ];
424 0 : long quic_tp_sz = -1L;
425 0 : if( server->quic )
426 0 : quic_tp_sz = (long)server->quic_tp_self_fn( handshake, quic_tp, FD_TLS_EXT_QUIC_PARAMS_SZ_MAX );
427 0 : if( FD_UNLIKELY( quic_tp_sz > (long)FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
428 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_QUIC_TP_OVERSZ );
429 :
430 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_INITIAL ) )
431 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
432 :
433 0 : if( FD_UNLIKELY( !server->cert_x509_sz ) )
434 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_NO_X509 );
435 :
436 : /* Message buffer */
437 0 : # define MSG_BUFSZ FD_TLS_SERVER_CERT_MSG_SZ_MAX
438 0 : uchar msg_buf[ MSG_BUFSZ ];
439 :
440 : /* Transcript hasher */
441 0 : fd_sha256_t transcript;
442 0 : if( handshake->hello_retry ) {
443 0 : fd_tls_transcript_load( &handshake->transcript, &transcript );
444 0 : } else {
445 0 : fd_sha256_init( &transcript );
446 0 : }
447 :
448 : /* Read client hello ************************************************/
449 :
450 0 : fd_tls_client_hello_t ch = {0};
451 :
452 0 : ulong read_sz;
453 0 : do {
454 0 : uchar const * wire = record;
455 0 : uchar const * const wire_end = record + record_sz;
456 :
457 : /* Decode message header */
458 :
459 0 : fd_tls_msg_hdr_t msg_hdr = {0};
460 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
461 0 : if( FD_UNLIKELY( decode_res<0L ) )
462 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CH_PARSE );
463 0 : wire += (ulong)decode_res;
464 :
465 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CLIENT_HELLO ) )
466 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CH_EXPECTED );
467 :
468 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
469 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
470 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CH_PARSE );
471 :
472 : /* Decode Client Hello */
473 :
474 0 : decode_res = fd_tls_decode_client_hello( &ch, wire, msg_sz );
475 0 : if( FD_UNLIKELY( decode_res<0L ) )
476 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CH_PARSE );
477 0 : if( FD_UNLIKELY( (ulong)decode_res != msg_sz ) )
478 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CH_PARSE );
479 0 : wire += (ulong)decode_res;
480 :
481 0 : read_sz = (ulong)(wire - record);
482 0 : } while(0);
483 :
484 : /* Check for cryptographic compatibility */
485 :
486 0 : if( FD_UNLIKELY( !ch.supported_versions.tls13 ) )
487 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_PROTOCOL_VERSION, FD_TLS_REASON_CH_NEG_VER );
488 : /* RFC 8446 Section 9.2: these extensions are mandatory for our
489 : certificate-based key exchange. An empty key_share permits HRR. */
490 0 : if( FD_UNLIKELY( !ch.has_supported_groups || !ch.has_key_share ) )
491 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_CH_NEG_KX );
492 0 : if( FD_UNLIKELY( !ch.has_signature_algorithms ) )
493 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_CH_NEG_SIG );
494 0 : if( FD_UNLIKELY( !ch.supported_groups.x25519 ) )
495 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CH_NEG_KX );
496 0 : if( FD_UNLIKELY( !ch.signature_algorithms.ed25519 ) )
497 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CH_NEG_SIG );
498 0 : if( FD_UNLIKELY( !ch.cipher_suites.aes_128_gcm_sha256 ) )
499 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CH_NEG_CIPHER );
500 :
501 : /* Remember client random for SSLKEYLOGFILE */
502 0 : fd_memcpy( handshake->base.client_random, ch.random, 32UL );
503 :
504 : /* Detect QUIC */
505 :
506 0 : if( server->quic ) {
507 0 : if( FD_UNLIKELY( ch.session_id.bufsz ) )
508 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_ILLEGAL_PARAMETER, FD_TLS_REASON_CH_SESSION_ID );
509 : /* QUIC transport parameters are mandatory in QUIC mode */
510 0 : if( FD_UNLIKELY( !ch.quic_tp.buf ) )
511 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_CH_NO_QUIC );
512 :
513 : /* Inform user of peer's QUIC transport parameters */
514 0 : server->quic_tp_peer_fn( handshake, ch.quic_tp.buf, ch.quic_tp.bufsz );
515 0 : } else if( FD_UNLIKELY( ch.quic_tp.buf ) ) {
516 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_EXTENSION, FD_TLS_REASON_CH_PARSE );
517 0 : }
518 :
519 : /* Reject connection if ALPN not advertised */
520 :
521 0 : if( server->alpn[0] ) {
522 0 : if( FD_UNLIKELY( !ch.alpn.bufsz ) )
523 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_NO_APPLICATION_PROTOCOL, FD_TLS_REASON_NO_ALPN );
524 0 : int ok = fd_tls_has_alpn( ch.alpn.buf, ch.alpn.bufsz, server->alpn, server->alpn_sz );
525 0 : if( FD_UNLIKELY( ok==-1 ) )
526 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_ALPN_PARSE );
527 0 : if( FD_UNLIKELY( ok==0 ) )
528 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_NO_APPLICATION_PROTOCOL, FD_TLS_REASON_ALPN_NEG );
529 0 : }
530 :
531 : /* Record client hello in transcript hash */
532 :
533 0 : fd_sha256_append( &transcript, record, read_sz );
534 :
535 : /* Retry if key share is missing */
536 :
537 0 : if( !ch.key_share.has_x25519 ) {
538 0 : uchar ch1_hash[ 32 ];
539 0 : fd_sha256_fini( &transcript, ch1_hash );
540 0 : long rc = fd_tls_server_hs_retry( server, handshake, &ch, ch1_hash );
541 0 : /**/ rc = fd_long_if( rc>=0, (long)read_sz, rc );
542 0 : return rc;
543 0 : }
544 :
545 : /* Respond with server hello ****************************************/
546 :
547 : /* Create server random */
548 :
549 0 : uchar server_random[ 32 ];
550 0 : fd_chacha_rng_read32( server->rng, server_random );
551 :
552 : /* Create server hello message */
553 :
554 0 : ulong server_hello_sz;
555 :
556 0 : do {
557 0 : uchar * wire = msg_buf;
558 0 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
559 :
560 : /* Leave space for message header */
561 :
562 0 : void * hdr_ptr = wire;
563 0 : wire += sizeof(fd_tls_msg_hdr_t);
564 0 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_SERVER_HELLO };
565 :
566 : /* Construct server hello */
567 :
568 0 : fd_tls_server_hello_t sh = {
569 0 : .cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256,
570 0 : .key_share = { .has_x25519 = 1 },
571 0 : .session_id = ch.session_id,
572 0 : };
573 0 : memcpy( sh.random, server_random, 32UL );
574 0 : memcpy( sh.key_share.x25519, server->kex_public_key, 32UL );
575 :
576 : /* Encode server hello */
577 :
578 0 : long encode_res = fd_tls_encode_server_hello( &sh, wire, (ulong)(wire_end-wire) );
579 0 : if( FD_UNLIKELY( encode_res<0L ) )
580 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_SH_ENCODE );
581 0 : wire += (ulong)encode_res;
582 :
583 0 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
584 0 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
585 0 : server_hello_sz = (ulong)(wire - msg_buf);
586 0 : } while(0);
587 :
588 : /* Call back with server hello */
589 :
590 0 : if( FD_UNLIKELY( !server->sendmsg_fn(
591 0 : handshake,
592 0 : msg_buf, server_hello_sz,
593 0 : FD_TLS_LEVEL_INITIAL,
594 0 : /* flush */ 1 ) ) )
595 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
596 :
597 : /* Record server hello in transcript hash */
598 :
599 0 : fd_sha256_append( &transcript, msg_buf, server_hello_sz );
600 :
601 : /* Derive handshake secrets *****************************************/
602 :
603 : /* Export handshake transcript hash */
604 :
605 0 : fd_sha256_t transcript_clone = transcript;
606 0 : uchar transcript_hash[ 32 ];
607 0 : fd_sha256_fini( &transcript_clone, transcript_hash );
608 :
609 : /* Derive ECDH input key material */
610 :
611 0 : uchar _ecdh_ikm[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
612 0 : void * ecdh_ikm = fd_x25519_exchange( _ecdh_ikm,
613 0 : server->kex_private_key,
614 0 : ch.key_share.x25519 );
615 0 : if( FD_UNLIKELY( !ecdh_ikm ) )
616 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_X25519_FAIL );
617 :
618 : /* RFC 8446 Section 7.1: Handshake Secret = HKDF-Extract(
619 : salt = Derive-Secret(Early Secret, "derived", ""),
620 : IKM = (EC)DHE shared secret)
621 : RFC 5869 Section 2.2: PRK = HMAC-Hash(key=salt, data=IKM) */
622 :
623 0 : uchar handshake_secret[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
624 0 : fd_hmac_sha256( /* IKM */ ecdh_ikm, 32UL,
625 0 : /* salt */ handshake_derived, 32UL,
626 0 : /* out */ handshake_secret );
627 :
628 : /* RFC 8446 Section 7.1: client_handshake_traffic_secret =
629 : Derive-Secret(Handshake Secret, "c hs traffic",
630 : ClientHello...ServerHello) */
631 :
632 0 : uchar client_hs_secret[ 32UL ] __attribute__((cleanup(fd_tls_clear_secret)));
633 0 : fd_tls_hkdf_expand_label( client_hs_secret, 32UL,
634 0 : handshake_secret,
635 0 : "c hs traffic", 12UL,
636 0 : transcript_hash, 32UL );
637 0 : memcpy( handshake->client_hs_secret, client_hs_secret, 32UL );
638 :
639 : /* RFC 8446 Section 7.1: server_handshake_traffic_secret =
640 : Derive-Secret(Handshake Secret, "s hs traffic",
641 : ClientHello...ServerHello) */
642 :
643 0 : uchar server_hs_secret[ 32UL ] __attribute__((cleanup(fd_tls_clear_secret)));
644 0 : fd_tls_hkdf_expand_label( server_hs_secret, 32UL,
645 0 : handshake_secret,
646 0 : "s hs traffic", 12UL,
647 0 : transcript_hash, 32UL );
648 :
649 : /* Call back with handshake secrets */
650 :
651 0 : server->secrets_fn( handshake,
652 0 : /* read secret */ client_hs_secret,
653 0 : /* write secret */ server_hs_secret,
654 0 : FD_TLS_LEVEL_HANDSHAKE );
655 :
656 : /* Derive master secret */
657 :
658 0 : uchar master_derive[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
659 0 : fd_tls_hkdf_expand_label( master_derive, 32UL,
660 0 : handshake_secret,
661 0 : "derived", 7UL,
662 0 : empty_hash, 32UL );
663 :
664 : /* RFC 8446 Section 7.1: Master Secret = HKDF-Extract(
665 : salt = Derive-Secret(Handshake Secret, "derived", ""),
666 : IKM = 0)
667 : RFC 5869 Section 2.2: PRK = HMAC-Hash(key=salt, data=IKM) */
668 :
669 0 : static uchar const zeros[ 32 ] = {0};
670 0 : uchar master_secret[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
671 0 : fd_hmac_sha256( /* IKM */ zeros, 32UL,
672 0 : /* salt */ master_derive, 32UL,
673 0 : /* out */ master_secret );
674 :
675 : /* Send EncryptedExtensions (EE) message ****************************/
676 :
677 0 : ulong server_ee_sz;
678 :
679 0 : do {
680 0 : uchar * wire = msg_buf;
681 0 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
682 :
683 : /* Leave space for message header */
684 :
685 0 : void * hdr_ptr = wire;
686 0 : wire += sizeof(fd_tls_msg_hdr_t);
687 0 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_ENCRYPTED_EXT };
688 :
689 0 : uchar * ext_sz_ptr = wire;
690 0 : wire += sizeof(ushort);
691 :
692 : /* Construct encrypted extensions */
693 :
694 0 : fd_tls_enc_ext_t ee = {
695 0 : .quic_tp = {
696 0 : .buf = (quic_tp_sz>=0L) ? quic_tp : NULL,
697 0 : .bufsz = (ushort)quic_tp_sz,
698 0 : },
699 0 : .alpn = {
700 0 : .buf = server->alpn,
701 0 : .bufsz = server->alpn_sz,
702 0 : }
703 0 : };
704 :
705 : /* Encode encrypted extensions */
706 :
707 0 : long encode_res = fd_tls_encode_enc_ext( &ee, wire, (ulong)(wire_end-wire) );
708 0 : if( FD_UNLIKELY( encode_res<0L ) )
709 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_EE_ENCODE );
710 0 : wire += (ulong)encode_res;
711 :
712 0 : FD_STORE( ushort, ext_sz_ptr, fd_ushort_bswap( (ushort)encode_res ) );
713 0 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res + (uint)sizeof(ushort) );
714 0 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, 4UL );
715 0 : server_ee_sz = (ulong)(wire - msg_buf);
716 0 : } while(0);
717 :
718 : /* Call back with EE */
719 :
720 0 : if( FD_UNLIKELY( !server->sendmsg_fn(
721 0 : handshake,
722 0 : msg_buf, server_ee_sz,
723 0 : FD_TLS_LEVEL_HANDSHAKE,
724 0 : /* flush */ 0 ) ) )
725 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
726 :
727 : /* Record EE in transcript hash */
728 :
729 0 : fd_sha256_append( &transcript, msg_buf, server_ee_sz );
730 :
731 : /* Send CertificateRequest ******************************************/
732 :
733 0 : handshake->client_cert = !!server->req_client_cert;
734 0 : if( handshake->client_cert ) {
735 0 : static uchar const cert_req[] = {
736 0 : FD_TLS_MSG_CERT_REQ, /* msg_type */
737 0 : 0x00, 0x00, 0x0b, /* msg_sz */
738 0 : 0x00, /* certificate_request_context */
739 0 : 0x00, 0x08, /* extensions length prefix */
740 0 : 0x00, FD_TLS_EXT_SIGNATURE_ALGORITHMS,
741 : /* ext type */
742 0 : 0x00, 0x04, /* ext sz */
743 0 : 0x00, 0x02, /* sigalg sz */
744 0 : 0x08, 0x07, /* Ed25519 */
745 0 : };
746 :
747 0 : if( FD_UNLIKELY( !server->sendmsg_fn(
748 0 : handshake,
749 0 : cert_req, sizeof(cert_req),
750 0 : FD_TLS_LEVEL_HANDSHAKE,
751 0 : /* flush */ 0 ) ) )
752 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
753 :
754 : /* Record CertificateRequest in transcript hash */
755 :
756 0 : fd_sha256_append( &transcript, cert_req, sizeof(cert_req) );
757 0 : }
758 :
759 : /* Send Certificate *************************************************/
760 :
761 0 : long cert_msg_sz = fd_tls_encode_cert_x509( server->cert_x509, server->cert_x509_sz, msg_buf, MSG_BUFSZ );
762 0 : if( FD_UNLIKELY( cert_msg_sz<0L ) )
763 0 : return fd_tls_alert( &handshake->base, (uint)(-cert_msg_sz), FD_TLS_REASON_CERT_ENCODE );
764 :
765 : /* Send certificate message */
766 :
767 0 : if( FD_UNLIKELY( !server->sendmsg_fn(
768 0 : handshake,
769 0 : msg_buf, (ulong)cert_msg_sz,
770 0 : FD_TLS_LEVEL_HANDSHAKE,
771 0 : /* flush */ 0 ) ) )
772 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
773 :
774 : /* Record Certificate message in transcript hash */
775 :
776 0 : fd_sha256_append( &transcript, msg_buf, (ulong)cert_msg_sz );
777 :
778 : /* Send CertificateVerify *******************************************/
779 :
780 0 : long cvfy_res = fd_tls_send_cert_verify( server, &handshake->base, &transcript, 0 );
781 0 : if( FD_UNLIKELY( !!cvfy_res ) ) return cvfy_res;
782 : /* CertificateVerify already included in transcript hash */
783 :
784 : /* Send Finished ****************************************************/
785 :
786 : /* Create static size message layout */
787 :
788 0 : struct __attribute__((packed)) {
789 0 : fd_tls_msg_hdr_t hdr;
790 0 : fd_tls_finished_t fin;
791 0 : } fin_rec;
792 0 : fin_rec.hdr = (fd_tls_msg_hdr_t){
793 0 : .type = FD_TLS_MSG_FINISHED,
794 0 : .sz = fd_uint_to_tls_u24( 0x20 )
795 0 : };
796 0 : fd_tls_msg_hdr_bswap( &fin_rec.hdr );
797 0 : fd_tls_finished_bswap( &fin_rec.fin );
798 :
799 : /* Export transcript hash ClientHello..CertificateVerify */
800 :
801 0 : transcript_clone = transcript;
802 0 : fd_sha256_fini( &transcript_clone, transcript_hash );
803 :
804 : /* RFC 8446 Section 4.4.4:
805 : finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
806 : verify_data = HMAC(finished_key, Transcript-Hash(
807 : Handshake Context, Certificate*, CertificateVerify*)) */
808 :
809 0 : uchar finished_key[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
810 0 : fd_tls_hkdf_expand_label( finished_key, 32UL,
811 0 : server_hs_secret,
812 0 : "finished", 8UL,
813 0 : NULL, 0UL );
814 :
815 0 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
816 0 : /* salt */ finished_key, 32UL,
817 0 : /* out */ fin_rec.fin.verify );
818 :
819 : /* Send Finished message */
820 :
821 0 : if( FD_UNLIKELY( !server->sendmsg_fn(
822 0 : handshake,
823 0 : &fin_rec, sizeof(fin_rec),
824 0 : FD_TLS_LEVEL_HANDSHAKE,
825 0 : /* flush */ 1 ) ) )
826 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
827 :
828 : /* Record Finished in transcript hash */
829 :
830 0 : fd_sha256_append( &transcript, &fin_rec, sizeof(fin_rec) );
831 :
832 : /* Derive application secrets ***************************************/
833 :
834 : /* Export transcript hash ClientHello..ServerFinished */
835 :
836 0 : transcript_clone = transcript;
837 0 : fd_sha256_fini( &transcript_clone, transcript_hash );
838 :
839 : /* RFC 8446 Section 7.1:
840 : client_application_traffic_secret_0 =
841 : Derive-Secret(Master Secret, "c ap traffic",
842 : ClientHello...server Finished) */
843 :
844 0 : uchar client_app_secret[ 32UL ] __attribute__((cleanup(fd_tls_clear_secret)));
845 0 : fd_tls_hkdf_expand_label( client_app_secret, 32UL,
846 0 : master_secret,
847 0 : "c ap traffic", 12UL,
848 0 : transcript_hash, 32UL );
849 :
850 : /* RFC 8446 Section 7.1:
851 : server_application_traffic_secret_0 =
852 : Derive-Secret(Master Secret, "s ap traffic",
853 : ClientHello...server Finished) */
854 :
855 0 : uchar server_app_secret[ 32UL ] __attribute__((cleanup(fd_tls_clear_secret)));
856 0 : fd_tls_hkdf_expand_label( server_app_secret, 32UL,
857 0 : master_secret,
858 0 : "s ap traffic", 12UL,
859 0 : transcript_hash, 32UL );
860 :
861 : /* Call back with application secrets */
862 :
863 0 : server->secrets_fn( handshake,
864 0 : /* read secret */ client_app_secret,
865 0 : /* write secret */ server_app_secret,
866 0 : FD_TLS_LEVEL_APPLICATION );
867 :
868 : /* Finish up ********************************************************/
869 :
870 : /* Store transcript hash state */
871 :
872 0 : fd_tls_transcript_store( &handshake->transcript, &transcript );
873 :
874 : /* Done */
875 :
876 0 : handshake->base.state = handshake->client_cert ? FD_TLS_HS_WAIT_CERT : FD_TLS_HS_WAIT_FINISHED;
877 :
878 0 : # undef MSG_BUFSZ
879 0 : return (long)read_sz;
880 0 : }
881 :
882 : /* fd_tls_handle_cert_chain validates a Certificate message body and
883 : extracts the leaf public key into *extract. Returns the number of
884 : bytes consumed, or a negated alert. */
885 :
886 : static long
887 : fd_tls_handle_cert_chain( fd_tls_estate_base_t * const base,
888 : uchar const * const cert_chain,
889 : ulong const cert_chain_sz,
890 0 : fd_tls_extract_cert_pubkey_res_t * const extract ) {
891 :
892 0 : *extract = fd_tls_extract_cert_pubkey( cert_chain, cert_chain_sz );
893 :
894 0 : if( FD_UNLIKELY( !extract->pubkey ) ) {
895 0 : uint alert = extract->alert ? extract->alert : FD_TLS_ALERT_DECODE_ERROR;
896 0 : ushort reason = extract->reason ? extract->reason : FD_TLS_REASON_CERT_PARSE;
897 0 : return fd_tls_alert( base, alert, reason );
898 0 : }
899 :
900 : /* Skip extensions */
901 : /* Skip remaining certificate chain */
902 :
903 0 : return (long)cert_chain_sz;
904 0 : }
905 :
906 : static long
907 : fd_tls_handle_cert_verify( fd_tls_estate_base_t * hs,
908 : fd_sha256_t const * transcript,
909 : uchar const * record,
910 : ulong record_sz,
911 : uchar const * pubkey,
912 : ulong pubkey_len,
913 : uchar key_type,
914 0 : int is_client ) {
915 :
916 : /* Read CertificateVerify *******************************************/
917 :
918 0 : fd_tls_cert_verify_t vfy[1] = {{0}};
919 :
920 0 : ulong read_sz;
921 0 : do {
922 0 : uchar const * wire = record;
923 0 : uchar const * const wire_end = record + record_sz;
924 :
925 : /* Decode message header */
926 :
927 0 : fd_tls_msg_hdr_t msg_hdr = {0};
928 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
929 0 : if( FD_UNLIKELY( decode_res<0L ) )
930 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CV_PARSE );
931 0 : wire += (ulong)decode_res;
932 :
933 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CERT_VERIFY ) )
934 0 : return fd_tls_alert( hs, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CV_EXPECTED );
935 :
936 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
937 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
938 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CV_PARSE );
939 :
940 : /* Decode CertificateVerify */
941 :
942 0 : decode_res = fd_tls_decode_cert_verify( vfy, wire, msg_sz );
943 0 : if( FD_UNLIKELY( decode_res<0L ) )
944 0 : return fd_tls_alert( hs, (uint)(-decode_res), FD_TLS_REASON_CV_PARSE );
945 0 : if( FD_UNLIKELY( (ulong)decode_res != msg_sz ) )
946 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CV_PARSE );
947 0 : wire += (ulong)decode_res;
948 :
949 0 : read_sz = (ulong)(wire - record);
950 0 : } while(0);
951 :
952 : /* Verify signature *************************************************/
953 :
954 : /* Export transcript hash ClientHello..peer Certificate
955 : And recover message that was signed */
956 :
957 0 : uchar sign_msg[ FD_TLS_CV_SIGN_SZ ];
958 0 : fd_memcpy( sign_msg,
959 0 : is_client ? fd_tls13_cli_sign_prefix : fd_tls13_srv_sign_prefix,
960 0 : 98UL );
961 :
962 0 : fd_sha256_t cv_transcript_clone = *transcript;
963 0 : fd_sha256_fini( &cv_transcript_clone, sign_msg+98 );
964 :
965 : /* Verify certificate signature
966 : > If the verification fails, the receiver MUST terminate the handshake
967 : > with a "decrypt_error" alert. */
968 :
969 0 : switch( vfy->algorithm ) {
970 :
971 0 : case FD_TLS_SIGNATURE_ED25519: {
972 0 : if( FD_UNLIKELY( key_type != FD_TLS_KEY_ED25519 ) )
973 0 : return fd_tls_alert( hs, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CV_SIGALG );
974 0 : fd_sha512_t sha512[1];
975 0 : int sig_err = fd_ed25519_verify( sign_msg, FD_TLS_CV_SIGN_SZ, vfy->signature, pubkey, sha512 );
976 0 : if( FD_UNLIKELY( sig_err != FD_ED25519_SUCCESS ) )
977 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_ED25519_FAIL );
978 0 : break;
979 0 : }
980 :
981 0 : case FD_TLS_SIGNATURE_ECDSA_SECP256R1_SHA256: {
982 0 : if( FD_UNLIKELY( key_type != FD_TLS_KEY_ECDSA_P256 ) )
983 0 : return fd_tls_alert( hs, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CV_SIGALG );
984 :
985 0 : uchar raw_sig[64];
986 0 : if( FD_UNLIKELY( fd_x509_decode_ecdsa_sig( vfy->signature, vfy->signature_len, raw_sig, 32 ) ) )
987 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_CV_PARSE );
988 :
989 0 : uchar compressed_pk[33];
990 0 : if( FD_UNLIKELY( pubkey_len != 65 ) )
991 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_CV_PARSE );
992 0 : if( FD_UNLIKELY( fd_x509_ec_point_compress( pubkey, 32, compressed_pk ) ) )
993 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_CV_PARSE );
994 :
995 0 : fd_sha256_t sha256[1];
996 0 : int sig_err = fd_secp256r1_verify_allow_high_s( sign_msg, 130UL, raw_sig, compressed_pk, sha256 );
997 0 : if( FD_UNLIKELY( sig_err != FD_SECP256R1_SUCCESS ) )
998 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_SECP256R1_FAIL );
999 0 : break;
1000 0 : }
1001 :
1002 0 : #if FD_HAS_INT128
1003 0 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA256:
1004 0 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA384:
1005 0 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA512: {
1006 0 : if( FD_UNLIKELY( key_type != FD_TLS_KEY_RSA ) )
1007 0 : return fd_tls_alert( hs, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CV_SIGALG );
1008 :
1009 0 : fd_rsa_pubkey_t key[1];
1010 0 : if( FD_UNLIKELY( fd_x509_decode_rsa_pubkey( pubkey, pubkey_len, key ) ) )
1011 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_CV_PARSE );
1012 :
1013 0 : int hash = vfy->algorithm==FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA256 ? FD_RSA_HASH_SHA256 :
1014 0 : vfy->algorithm==FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA384 ? FD_RSA_HASH_SHA384 :
1015 0 : FD_RSA_HASH_SHA512;
1016 0 : int sig_err = fd_rsa_verify_pss( key, vfy->signature, vfy->signature_len, sign_msg, 130UL, hash );
1017 0 : if( FD_UNLIKELY( sig_err != FD_RSA_SUCCESS ) )
1018 0 : return fd_tls_alert( hs, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_RSA_FAIL );
1019 0 : break;
1020 0 : }
1021 0 : #endif
1022 :
1023 0 : default:
1024 0 : return fd_tls_alert( hs, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_CV_SIGALG );
1025 0 : }
1026 :
1027 0 : return (long)read_sz;
1028 0 : }
1029 :
1030 : static long
1031 : fd_tls_server_hs_wait_cert( fd_tls_t const * server,
1032 : fd_tls_estate_srv_t * handshake,
1033 : uchar const * const record,
1034 : ulong const record_sz,
1035 0 : uint encryption_level ) {
1036 :
1037 0 : (void)server;
1038 :
1039 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1040 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1041 :
1042 : /* Read Certificate *************************************************/
1043 :
1044 0 : ulong read_sz;
1045 0 : do {
1046 0 : uchar const * wire = record;
1047 0 : uchar const * const wire_end = record + record_sz;
1048 :
1049 : /* Decode message header */
1050 :
1051 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1052 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1053 0 : if( FD_UNLIKELY( decode_res<0L ) )
1054 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_PARSE );
1055 0 : wire += (ulong)decode_res;
1056 :
1057 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CERT ) )
1058 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CERT_EXPECTED );
1059 :
1060 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1061 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1062 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_PARSE );
1063 :
1064 : /* Decode Certificate */
1065 :
1066 0 : fd_tls_extract_cert_pubkey_res_t extract;
1067 0 : decode_res = fd_tls_handle_cert_chain( &handshake->base, wire, msg_sz, &extract );
1068 0 : if( FD_UNLIKELY( decode_res<0L ) )
1069 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CERT_PARSE );
1070 0 : if( FD_UNLIKELY( extract.key_type!=FD_TLS_KEY_ED25519 || extract.pubkey_len!=32UL ) )
1071 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_CERT_KEY_TYPE );
1072 0 : fd_memcpy( handshake->client_pubkey, extract.pubkey, 32UL );
1073 0 : wire += (ulong)decode_res;
1074 :
1075 0 : read_sz = (ulong)(wire - record);
1076 0 : } while(0);
1077 :
1078 0 : fd_sha256_t transcript;
1079 0 : fd_tls_transcript_load( &handshake->transcript, &transcript );
1080 0 : fd_sha256_append( &transcript, record, read_sz );
1081 0 : fd_tls_transcript_store( &handshake->transcript, &transcript );
1082 :
1083 : /* Finish up ********************************************************/
1084 :
1085 0 : handshake->base.state = FD_TLS_HS_WAIT_CV;
1086 0 : return (long)read_sz;
1087 0 : }
1088 :
1089 : static long
1090 : fd_tls_server_hs_wait_cert_verify( fd_tls_t const * server,
1091 : fd_tls_estate_srv_t * hs,
1092 : uchar const * const record,
1093 : ulong const record_sz,
1094 0 : uint encryption_level ) {
1095 :
1096 0 : (void)server;
1097 :
1098 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1099 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1100 :
1101 0 : fd_sha256_t transcript;
1102 0 : fd_tls_transcript_load( &hs->transcript, &transcript );
1103 0 : fd_sha256_t transcript_clone = transcript;
1104 :
1105 : /* Decode incoming client CertificateVerify *************************/
1106 :
1107 0 : long res = fd_tls_handle_cert_verify( &hs->base, &transcript_clone,
1108 0 : record, record_sz,
1109 0 : hs->client_pubkey, 32UL, FD_TLS_KEY_ED25519, 1 );
1110 0 : if( FD_UNLIKELY( res<0L ) ) return res;
1111 :
1112 0 : fd_sha256_append( &transcript, record, (ulong)res );
1113 0 : fd_tls_transcript_store( &hs->transcript, &transcript );
1114 :
1115 : /* Finish up ********************************************************/
1116 :
1117 0 : hs->base.state = FD_TLS_HS_WAIT_FINISHED;
1118 0 : return res;
1119 0 : }
1120 :
1121 : static long
1122 : fd_tls_server_hs_wait_finished( fd_tls_t const * server,
1123 : fd_tls_estate_srv_t * handshake,
1124 : uchar const * const record,
1125 : ulong record_sz,
1126 0 : uint encryption_level ) {
1127 :
1128 0 : (void)server;
1129 :
1130 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1131 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1132 :
1133 : /* Restore state ****************************************************/
1134 :
1135 0 : fd_sha256_t transcript;
1136 0 : fd_tls_transcript_load( &handshake->transcript, &transcript );
1137 :
1138 : /* Decode incoming client "Finished" message ************************/
1139 :
1140 0 : fd_tls_finished_t finished = {0};
1141 :
1142 0 : ulong read_sz;
1143 0 : do {
1144 0 : uchar const * wire = record;
1145 0 : uchar const * const wire_end = record + record_sz;
1146 :
1147 : /* Decode message header */
1148 :
1149 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1150 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1151 0 : if( FD_UNLIKELY( decode_res<0L ) )
1152 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_FINI_PARSE );
1153 0 : wire += (ulong)decode_res;
1154 :
1155 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_FINISHED ) )
1156 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_FINI_EXPECTED );
1157 :
1158 0 : if( FD_UNLIKELY( fd_tls_u24_to_uint( msg_hdr.sz ) != sizeof(fd_tls_finished_t) ) )
1159 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_FINI_PARSE );
1160 :
1161 : /* Decode client Finished */
1162 :
1163 0 : decode_res = fd_tls_decode_finished( &finished, wire, (ulong)(wire_end-wire) );
1164 0 : if( FD_UNLIKELY( decode_res<0L ) )
1165 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_FINI_PARSE );
1166 0 : wire += (ulong)decode_res;
1167 :
1168 0 : read_sz = (ulong)(wire - record);
1169 0 : } while(0);
1170 :
1171 : /* Check "Finished" verify data *************************************/
1172 :
1173 : /* Export transcript hash */
1174 :
1175 0 : uchar transcript_hash[ 32 ];
1176 0 : fd_sha256_fini( &transcript, transcript_hash );
1177 :
1178 : /* RFC 8446 Section 4.4.4:
1179 : finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
1180 : verify_data = HMAC(finished_key, Transcript-Hash(
1181 : Handshake Context, Certificate*, CertificateVerify*)) */
1182 :
1183 0 : uchar finished_key[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1184 0 : fd_tls_hkdf_expand_label( finished_key, 32UL,
1185 0 : handshake->client_hs_secret,
1186 0 : "finished", 8UL,
1187 0 : NULL, 0UL );
1188 :
1189 0 : uchar finished_expected[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1190 0 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
1191 0 : /* salt */ finished_key, 32UL,
1192 0 : /* out */ finished_expected );
1193 :
1194 : /* Verify that client and server's transcripts match */
1195 :
1196 0 : int match = 0;
1197 0 : for( ulong i=0; i<32UL; i++ )
1198 0 : match |= finished.verify[i] ^ finished_expected[i];
1199 0 : if( FD_UNLIKELY( match!=0 ) )
1200 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_FINI_FAIL );
1201 :
1202 : /* Done */
1203 :
1204 0 : handshake->base.state = FD_TLS_HS_CONNECTED;
1205 0 : return (long)read_sz;
1206 0 : }
1207 :
1208 : static long fd_tls_client_hs_start ( fd_tls_t const *, fd_tls_estate_cli_t * );
1209 : static long fd_tls_client_hs_wait_sh ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
1210 : static long fd_tls_client_hs_wait_ee ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
1211 : static long fd_tls_client_hs_wait_cert_cr ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
1212 : static long fd_tls_client_hs_wait_cert ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
1213 : static long fd_tls_client_hs_wait_cert_verify( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
1214 : static long fd_tls_client_hs_wait_finished ( fd_tls_t const *, fd_tls_estate_cli_t *, uchar const *, ulong, uint );
1215 :
1216 : long
1217 : fd_tls_client_handshake( fd_tls_t const * client,
1218 : fd_tls_estate_cli_t * handshake,
1219 : void const * record,
1220 : ulong record_sz,
1221 0 : uint encryption_level ) {
1222 0 : switch( handshake->base.state ) {
1223 0 : case FD_TLS_HS_START:
1224 : /* Record argument is ignored, since ClientHello is always the first message */
1225 0 : (void)record; (void)record_sz; (void)encryption_level;
1226 0 : return fd_tls_client_hs_start( client, handshake );
1227 0 : case FD_TLS_HS_WAIT_SH:
1228 : /* Incoming ServerHello */
1229 0 : return fd_tls_client_hs_wait_sh( client, handshake, record, record_sz, encryption_level );
1230 0 : case FD_TLS_HS_WAIT_EE:
1231 : /* Incoming EncryptedExtensions */
1232 0 : return fd_tls_client_hs_wait_ee( client, handshake, record, record_sz, encryption_level );
1233 0 : case FD_TLS_HS_WAIT_CERT_CR:
1234 : /* Incoming CertificateRequest or Certificate */
1235 0 : return fd_tls_client_hs_wait_cert_cr( client, handshake, record, record_sz, encryption_level );
1236 0 : case FD_TLS_HS_WAIT_CERT:
1237 : /* Incoming Certificate */
1238 0 : return fd_tls_client_hs_wait_cert( client, handshake, record, record_sz, encryption_level );
1239 0 : case FD_TLS_HS_WAIT_CV:
1240 : /* Incoming CertificateVerify */
1241 0 : return fd_tls_client_hs_wait_cert_verify( client, handshake, record, record_sz, encryption_level );
1242 0 : case FD_TLS_HS_WAIT_FINISHED:
1243 : /* Incoming Server Finished */
1244 0 : return fd_tls_client_hs_wait_finished( client, handshake, record, record_sz, encryption_level );
1245 0 : default:
1246 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_ILLEGAL_STATE );
1247 0 : }
1248 0 : }
1249 :
1250 : static long
1251 : fd_tls_client_hs_start( fd_tls_t const * const client,
1252 0 : fd_tls_estate_cli_t * const handshake ) {
1253 :
1254 0 : if( FD_UNLIKELY( client->server_name_len>=sizeof(client->server_name) ) )
1255 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_CH_ENCODE );
1256 :
1257 : /* Request QUIC transport params */
1258 0 : uchar quic_tp[ FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ];
1259 0 : long quic_tp_sz = -1L;
1260 0 : if( client->quic )
1261 0 : quic_tp_sz = (long)client->quic_tp_self_fn( handshake, quic_tp, FD_TLS_EXT_QUIC_PARAMS_SZ_MAX );
1262 0 : if( FD_UNLIKELY( quic_tp_sz > (long)FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
1263 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_QUIC_TP_OVERSZ );
1264 :
1265 : /* Message buffer (sized for session_id + SNI) */
1266 0 : # define MSG_BUFSZ 1024UL
1267 0 : uchar msg_buf[ MSG_BUFSZ ];
1268 :
1269 0 : fd_sha256_init( &handshake->transcript );
1270 :
1271 : /* Send ClientHello *************************************************/
1272 :
1273 : /* Create client random */
1274 :
1275 0 : uchar client_random[ 32 ];
1276 0 : fd_chacha_rng_read32( client->rng, client_random );
1277 :
1278 : /* Remember client random for SSLKEYLOGFILE */
1279 0 : fd_memcpy( handshake->base.client_random, client_random, 32UL );
1280 :
1281 : /* Generate session_id for TCP middlebox compat (RFC 8446 Section 4.1.2) */
1282 :
1283 0 : uchar session_id_buf[ 32 ];
1284 0 : uchar session_id_sz = 0;
1285 0 : if( !client->quic ) {
1286 0 : fd_chacha_rng_read32( client->rng, session_id_buf );
1287 0 : session_id_sz = 32;
1288 0 : fd_memcpy( handshake->session_id, session_id_buf, 32UL );
1289 0 : handshake->session_id_sz = 32;
1290 0 : }
1291 :
1292 : /* Create client hello message */
1293 :
1294 0 : ulong client_hello_sz;
1295 :
1296 0 : do {
1297 0 : uchar * wire = msg_buf;
1298 0 : uchar * const wire_end = msg_buf + MSG_BUFSZ;
1299 :
1300 : /* Leave space for message header */
1301 :
1302 0 : void * hdr_ptr = wire;
1303 0 : wire += sizeof(fd_tls_msg_hdr_t);
1304 0 : fd_tls_msg_hdr_t hdr = { .type = FD_TLS_MSG_CLIENT_HELLO };
1305 :
1306 : /* Construct client hello */
1307 :
1308 0 : fd_tls_client_hello_t ch = {
1309 0 : .supported_versions = { .tls13=1 },
1310 0 : .supported_groups = { .x25519=1 },
1311 : /* TPU/QUIC peers always present Ed25519 identities. Only the
1312 : TCP-based TLS client talks to CAs issuing ECDSA certs. */
1313 0 : .signature_algorithms =
1314 0 : { .ed25519 = 1,
1315 0 : .ecdsa_secp256r1_sha256 = !client->quic,
1316 0 : .rsa_pss_rsae_sha256 = !client->quic && FD_HAS_INT128,
1317 0 : .rsa_pss_rsae_sha384 = !client->quic && FD_HAS_INT128,
1318 0 : .rsa_pss_rsae_sha512 = !client->quic && FD_HAS_INT128 },
1319 0 : .signature_algorithms_cert =
1320 0 : { .ed25519 = !client->quic,
1321 0 : .ecdsa_secp256r1_sha256 = !client->quic,
1322 0 : .ecdsa_secp384r1_sha384 = !client->quic,
1323 0 : .rsa_pkcs1_sha256 = !client->quic && FD_HAS_INT128,
1324 0 : .rsa_pkcs1_sha384 = !client->quic && FD_HAS_INT128,
1325 0 : .rsa_pkcs1_sha512 = !client->quic && FD_HAS_INT128 },
1326 0 : .cipher_suites = { .aes_128_gcm_sha256=1 },
1327 0 : .key_share = { .has_x25519=1 },
1328 0 : .session_id = {
1329 0 : .buf = session_id_sz ? session_id_buf : NULL,
1330 0 : .bufsz = session_id_sz,
1331 0 : },
1332 0 : .quic_tp = {
1333 0 : .buf = (quic_tp_sz>=0L) ? quic_tp : NULL,
1334 0 : .bufsz = (quic_tp_sz>=0L) ? (ushort)quic_tp_sz : 0,
1335 0 : },
1336 0 : .alpn = {
1337 0 : .buf = client->alpn,
1338 0 : .bufsz = client->alpn_sz,
1339 0 : }
1340 0 : };
1341 0 : memcpy( ch.random, client_random, 32UL );
1342 0 : memcpy( ch.key_share.x25519, client->kex_public_key, 32UL );
1343 :
1344 : /* Copy SNI from config if set */
1345 0 : if( client->server_name_len ) {
1346 0 : ch.server_name.host_name_len = client->server_name_len;
1347 0 : fd_memcpy( ch.server_name.host_name, client->server_name, client->server_name_len );
1348 0 : ch.server_name.host_name[ client->server_name_len ] = '\0';
1349 0 : }
1350 :
1351 : /* Encode client hello */
1352 :
1353 0 : long encode_res = fd_tls_encode_client_hello( &ch, wire, (ulong)(wire_end-wire) );
1354 0 : if( FD_UNLIKELY( encode_res<0L ) )
1355 0 : return fd_tls_alert( &handshake->base, (uint)(-encode_res), FD_TLS_REASON_CH_ENCODE );
1356 0 : wire += (ulong)encode_res;
1357 :
1358 0 : hdr.sz = fd_uint_to_tls_u24( (uint)encode_res );
1359 0 : fd_tls_encode_msg_hdr( &hdr, hdr_ptr, sizeof(fd_tls_msg_hdr_t) );
1360 0 : client_hello_sz = (ulong)(wire - msg_buf);
1361 0 : } while(0);
1362 :
1363 : /* Call back with client hello */
1364 :
1365 0 : if( FD_UNLIKELY( !client->sendmsg_fn(
1366 0 : handshake,
1367 0 : msg_buf, client_hello_sz,
1368 0 : FD_TLS_LEVEL_INITIAL,
1369 0 : /* flush */ 1 ) ) )
1370 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
1371 :
1372 : /* Record client hello in transcript hash */
1373 :
1374 0 : fd_sha256_append( &handshake->transcript, msg_buf, client_hello_sz );
1375 :
1376 : /* Finish up ********************************************************/
1377 :
1378 0 : handshake->base.state = FD_TLS_HS_WAIT_SH;
1379 :
1380 0 : # undef MSG_BUFSZ
1381 0 : return 0L;
1382 0 : }
1383 :
1384 : static long
1385 : fd_tls_client_hs_wait_sh( fd_tls_t const * const client,
1386 : fd_tls_estate_cli_t * const handshake,
1387 : uchar const * const record,
1388 : ulong const record_sz,
1389 0 : uint const encryption_level ) {
1390 :
1391 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_INITIAL ) )
1392 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1393 :
1394 : /* Read server hello ************************************************/
1395 :
1396 0 : fd_tls_server_hello_t sh[1] = {0};
1397 :
1398 0 : ulong read_sz;
1399 0 : do {
1400 0 : uchar const * wire = record;
1401 0 : uchar const * const wire_end = record + record_sz;
1402 :
1403 : /* Decode message header */
1404 :
1405 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1406 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1407 0 : if( FD_UNLIKELY( decode_res<0L ) )
1408 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_SH_PARSE );
1409 0 : wire += (ulong)decode_res;
1410 :
1411 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_SERVER_HELLO ) )
1412 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_SH_EXPECTED );
1413 :
1414 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1415 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1416 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_SH_PARSE );
1417 :
1418 : /* Decode Server Hello */
1419 :
1420 0 : decode_res = fd_tls_decode_server_hello( sh, wire, msg_sz );
1421 0 : if( FD_UNLIKELY( decode_res<0L ) )
1422 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_SH_PARSE );
1423 0 : if( FD_UNLIKELY( (ulong)decode_res != msg_sz ) )
1424 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_SH_PARSE );
1425 0 : wire += (ulong)decode_res;
1426 :
1427 0 : read_sz = (ulong)(wire - record);
1428 0 : } while(0);
1429 :
1430 : /* legacy_session_id_echo must match the session_id sent in the
1431 : ClientHello (RFC 8446 Section 4.1.3). Empty in QUIC mode. */
1432 :
1433 0 : if( FD_UNLIKELY( ( sh->session_id.bufsz != handshake->session_id_sz ) ||
1434 0 : ( 0!=memcmp( sh->session_id.buf, handshake->session_id, handshake->session_id_sz ) ) ) )
1435 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_ILLEGAL_PARAMETER, FD_TLS_REASON_SH_SESSION_ID );
1436 :
1437 : /* Server must select a cipher suite offered by ClientHello. */
1438 :
1439 0 : if( FD_UNLIKELY( sh->cipher_suite != FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 ) )
1440 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_ILLEGAL_PARAMETER, FD_TLS_REASON_SH_NEG_CIPHER );
1441 :
1442 : /* Record server hello in transcript hash */
1443 :
1444 0 : fd_sha256_append( &handshake->transcript, record, read_sz );
1445 :
1446 : /* Derive handshake secrets *****************************************/
1447 :
1448 : /* Export handshake transcript hash */
1449 :
1450 0 : fd_sha256_t transcript_clone = handshake->transcript;
1451 0 : uchar transcript_hash[ 32 ];
1452 0 : fd_sha256_fini( &transcript_clone, transcript_hash );
1453 :
1454 : /* Derive ECDH input key material */
1455 :
1456 0 : uchar _ecdh_ikm[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1457 0 : void * ecdh_ikm = fd_x25519_exchange( _ecdh_ikm,
1458 0 : client->kex_private_key,
1459 0 : sh->key_share.x25519 );
1460 0 : if( FD_UNLIKELY( !ecdh_ikm ) )
1461 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_X25519_FAIL );
1462 :
1463 : /* RFC 8446 Section 7.1: Handshake Secret = HKDF-Extract(
1464 : salt = Derive-Secret(Early Secret, "derived", ""),
1465 : IKM = (EC)DHE shared secret)
1466 : RFC 5869 Section 2.2: PRK = HMAC-Hash(key=salt, data=IKM) */
1467 :
1468 0 : uchar handshake_secret[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1469 0 : fd_hmac_sha256( /* IKM */ ecdh_ikm, 32UL,
1470 0 : /* salt */ handshake_derived, 32UL,
1471 0 : /* out */ handshake_secret );
1472 :
1473 : /* RFC 8446 Section 7.1: client_handshake_traffic_secret =
1474 : Derive-Secret(Handshake Secret, "c hs traffic",
1475 : ClientHello...ServerHello) */
1476 :
1477 0 : fd_tls_hkdf_expand_label( handshake->client_hs_secret, 32UL,
1478 0 : handshake_secret,
1479 0 : "c hs traffic", 12UL,
1480 0 : transcript_hash, 32UL );
1481 :
1482 : /* RFC 8446 Section 7.1: server_handshake_traffic_secret =
1483 : Derive-Secret(Handshake Secret, "s hs traffic",
1484 : ClientHello...ServerHello) */
1485 :
1486 0 : fd_tls_hkdf_expand_label( handshake->server_hs_secret, 32UL,
1487 0 : handshake_secret,
1488 0 : "s hs traffic", 12UL,
1489 0 : transcript_hash, 32UL );
1490 :
1491 : /* Call back with handshake secrets */
1492 :
1493 0 : client->secrets_fn( handshake,
1494 0 : /* read secret */ handshake->server_hs_secret,
1495 0 : /* write secret */ handshake->client_hs_secret,
1496 0 : FD_TLS_LEVEL_HANDSHAKE );
1497 :
1498 : /* Derive master secret */
1499 :
1500 0 : uchar master_derive[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1501 0 : fd_tls_hkdf_expand_label( master_derive, 32UL,
1502 0 : handshake_secret,
1503 0 : "derived", 7UL,
1504 0 : empty_hash, 32UL );
1505 :
1506 : /* RFC 8446 Section 7.1: Master Secret = HKDF-Extract(
1507 : salt = Derive-Secret(Handshake Secret, "derived", ""),
1508 : IKM = 0)
1509 : RFC 5869 Section 2.2: PRK = HMAC-Hash(key=salt, data=IKM) */
1510 :
1511 0 : static uchar const zeros[ 32 ] = {0};
1512 0 : fd_hmac_sha256( /* IKM */ zeros, 32UL,
1513 0 : /* salt */ master_derive, 32UL,
1514 0 : /* out */ handshake->master_secret );
1515 :
1516 : /* Finish up ********************************************************/
1517 :
1518 0 : handshake->base.state = FD_TLS_HS_WAIT_EE;
1519 :
1520 0 : return (long)read_sz;
1521 0 : }
1522 :
1523 : static long
1524 : fd_tls_client_hs_wait_ee( fd_tls_t const * const client,
1525 : fd_tls_estate_cli_t * const handshake,
1526 : uchar const * const record,
1527 : ulong const record_sz,
1528 0 : uint const encryption_level ) {
1529 :
1530 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1531 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1532 :
1533 : /* Read EncryptedExtensions (EE) message ****************************/
1534 :
1535 0 : fd_tls_enc_ext_t ee[1] = {0};
1536 :
1537 0 : ulong read_sz;
1538 0 : do {
1539 0 : uchar const * wire = record;
1540 0 : uchar const * const wire_end = record + record_sz;
1541 :
1542 : /* Decode message header */
1543 :
1544 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1545 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1546 0 : if( FD_UNLIKELY( decode_res<0L ) )
1547 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_EE_PARSE );
1548 0 : wire += (ulong)decode_res;
1549 :
1550 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_ENCRYPTED_EXT ) )
1551 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_EE_EXPECTED );
1552 :
1553 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1554 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1555 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_EE_PARSE );
1556 :
1557 : /* Decode EncryptedExtensions */
1558 :
1559 0 : decode_res = fd_tls_decode_enc_ext( ee, wire, msg_sz );
1560 0 : if( FD_UNLIKELY( decode_res<0L ) )
1561 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_EE_PARSE );
1562 0 : if( FD_UNLIKELY( (ulong)decode_res != msg_sz ) )
1563 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_EE_PARSE );
1564 0 : wire += (ulong)decode_res;
1565 :
1566 0 : read_sz = (ulong)(wire - record);
1567 0 : } while(0);
1568 :
1569 : /* Record EE in transcript hash */
1570 :
1571 0 : fd_sha256_append( &handshake->transcript, record, read_sz );
1572 :
1573 : /* QUIC mode */
1574 :
1575 0 : if( FD_UNLIKELY( ( ee->server_name && !client->server_name_len ) ||
1576 0 : ( ee->quic_tp.buf && !client->quic ) ||
1577 0 : ( ee->alpn.buf && !client->alpn_sz ) ) )
1578 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNSUPPORTED_EXTENSION, FD_TLS_REASON_EE_PARSE );
1579 :
1580 0 : if( client->quic ) {
1581 : /* QUIC transport parameters are mandatory in QUIC mode */
1582 0 : if( FD_UNLIKELY( !ee->quic_tp.buf ) )
1583 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_MISSING_EXTENSION, FD_TLS_REASON_EE_NO_QUIC );
1584 :
1585 : /* Inform user of peer's QUIC transport parameters */
1586 0 : client->quic_tp_peer_fn( handshake, ee->quic_tp.buf, ee->quic_tp.bufsz );
1587 0 : }
1588 :
1589 : /* Check ALPN.
1590 :
1591 : In QUIC mode, ALPN is mandatory (RFC 9001 Section 8.1).
1592 : In TCP mode, many HTTP servers omit the ALPN extension from
1593 : EncryptedExtensions, permitted by RFC 8446 Section 4.2.
1594 : We only enforce ALPN matching when the server actually sends it. */
1595 :
1596 0 : if( client->alpn_sz && ee->alpn.bufsz ) {
1597 0 : if( FD_UNLIKELY( ee->alpn.bufsz != client->alpn_sz ||
1598 0 : 0!=memcmp( ee->alpn.buf, client->alpn, client->alpn_sz ) ) )
1599 0 : return fd_tls_alert( &handshake->base,
1600 0 : client->quic ? FD_TLS_ALERT_NO_APPLICATION_PROTOCOL : FD_TLS_ALERT_HANDSHAKE_FAILURE,
1601 0 : FD_TLS_REASON_ALPN_NEG );
1602 0 : handshake->alpn_negotiated = 1;
1603 0 : }
1604 0 : if( client->quic && client->alpn_sz && !ee->alpn.bufsz )
1605 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_NO_APPLICATION_PROTOCOL, FD_TLS_REASON_NO_ALPN );
1606 :
1607 : /* Finish up ********************************************************/
1608 :
1609 0 : handshake->base.state = FD_TLS_HS_WAIT_CERT_CR;
1610 :
1611 0 : return (long)read_sz;
1612 0 : }
1613 :
1614 : static long
1615 : fd_tls_client_handle_cert_req( fd_tls_estate_cli_t * const handshake,
1616 : uchar const * const req,
1617 0 : ulong const req_sz ) {
1618 :
1619 0 : fd_tls_ext_signature_algorithms_t sigalgs = {0};
1620 0 : long res = fd_tls_decode_cert_req( &sigalgs, req, req_sz );
1621 0 : if( FD_UNLIKELY( res<0L ) ) return res;
1622 0 : if( FD_UNLIKELY( (ulong)res != req_sz ) ) return -(long)FD_TLS_ALERT_DECODE_ERROR;
1623 :
1624 0 : handshake->client_cert_empty = !sigalgs.ed25519;
1625 0 : handshake->client_cert = 1;
1626 0 : handshake->base.state = FD_TLS_HS_WAIT_CERT;
1627 :
1628 0 : return (long)req_sz;
1629 0 : }
1630 :
1631 : static long
1632 : fd_tls_client_handle_cert_chain( fd_tls_t const * const client,
1633 : fd_tls_estate_cli_t * const hs,
1634 : uchar const * const cert_chain,
1635 0 : ulong const cert_chain_sz ) {
1636 0 : fd_tls_extract_cert_pubkey_res_t extract;
1637 0 : long res = fd_tls_handle_cert_chain( &hs->base, cert_chain, cert_chain_sz, &extract );
1638 0 : if( FD_UNLIKELY( res < 0L ) ) return res;
1639 :
1640 : /* QUIC mode offers Ed25519 only, so a P-256 or RSA cert is not
1641 : acceptable. */
1642 0 : if( FD_UNLIKELY( client->quic && extract.key_type!=FD_TLS_KEY_ED25519 ) )
1643 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_CERT_KEY_TYPE );
1644 :
1645 0 : if( FD_UNLIKELY( extract.pubkey_len > sizeof(hs->server_pubkey) ) )
1646 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE, FD_TLS_REASON_CERT_KEY_TYPE );
1647 :
1648 : /* pubkey pinning is ...
1649 : ... enabled => check that public key matches cert
1650 : ... disabled => update the handshake's public key value based on cert */
1651 0 : if( hs->server_pubkey_pin ) {
1652 0 : if( FD_UNLIKELY( extract.pubkey_len!=hs->server_pubkey_len ||
1653 0 : 0!=memcmp( extract.pubkey, hs->server_pubkey, extract.pubkey_len ) ) )
1654 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_HANDSHAKE_FAILURE, FD_TLS_REASON_WRONG_PUBKEY );
1655 0 : } else {
1656 0 : fd_memcpy( hs->server_pubkey, extract.pubkey, extract.pubkey_len );
1657 0 : }
1658 0 : hs->server_pubkey_len = extract.pubkey_len;
1659 0 : hs->server_key_type = extract.key_type;
1660 :
1661 : /* Verify the chain against the trust store and the SNI we sent */
1662 0 : if( client->ca_store ) {
1663 0 : int verify_err = fd_x509_verify_tls_cert_msg( cert_chain, cert_chain_sz, client->ca_store,
1664 0 : client->server_name, client->server_name_len,
1665 0 : fd_x509_unix_now_seconds() );
1666 0 : hs->cert_verify_err = (uchar)verify_err;
1667 0 : if( FD_UNLIKELY( verify_err ) ) {
1668 0 : FD_LOG_WARNING(( "certificate verification failed (%i) for %s", verify_err, client->server_name ));
1669 0 : uchar alert = FD_TLS_ALERT_BAD_CERTIFICATE;
1670 0 : switch( verify_err ) {
1671 0 : case FD_X509_VERIFY_ERR_NOT_YET_VALID:
1672 0 : case FD_X509_VERIFY_ERR_EXPIRED: alert = FD_TLS_ALERT_CERTIFICATE_EXPIRED; break;
1673 0 : case FD_X509_VERIFY_ERR_NO_TRUST_ANCHOR: alert = FD_TLS_ALERT_UNKNOWN_CA; break;
1674 0 : case FD_X509_VERIFY_ERR_UNSUPPORTED: alert = FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE; break;
1675 0 : }
1676 0 : return fd_tls_alert( &hs->base, alert, FD_TLS_REASON_CERT_VERIFY );
1677 0 : }
1678 0 : }
1679 :
1680 0 : return res;
1681 0 : }
1682 :
1683 : static long
1684 : fd_tls_client_hs_wait_cert_cr( fd_tls_t const * const client,
1685 : fd_tls_estate_cli_t * const handshake,
1686 : uchar const * const record,
1687 : ulong const record_sz,
1688 0 : uint const encryption_level ) {
1689 :
1690 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1691 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1692 :
1693 : /* Read Certificate(Request) ****************************************/
1694 :
1695 0 : uchar next_state;
1696 :
1697 0 : ulong read_sz;
1698 0 : do {
1699 0 : uchar const * wire = record;
1700 0 : uchar const * const wire_end = record + record_sz;
1701 :
1702 : /* Decode message header */
1703 :
1704 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1705 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1706 0 : if( FD_UNLIKELY( decode_res<0L ) )
1707 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_CR_PARSE );
1708 0 : wire += (ulong)decode_res;
1709 :
1710 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1711 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1712 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_CR_PARSE );
1713 :
1714 0 : switch( msg_hdr.type ) {
1715 0 : case FD_TLS_MSG_CERT_REQ:
1716 0 : decode_res = fd_tls_client_handle_cert_req( handshake, wire, msg_sz );
1717 0 : next_state = FD_TLS_HS_WAIT_CERT;
1718 0 : break;
1719 0 : case FD_TLS_MSG_CERT:
1720 0 : decode_res = fd_tls_client_handle_cert_chain( client, handshake, wire, msg_sz );
1721 0 : next_state = FD_TLS_HS_WAIT_CV;
1722 0 : break;
1723 0 : default:
1724 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CERT_CR_EXPECTED );
1725 0 : }
1726 :
1727 0 : if( FD_UNLIKELY( decode_res<0L ) )
1728 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CERT_CR_PARSE );
1729 0 : wire += (ulong)decode_res;
1730 :
1731 0 : read_sz = (ulong)(wire - record);
1732 0 : } while(0);
1733 :
1734 0 : fd_sha256_append( &handshake->transcript, record, read_sz );
1735 :
1736 : /* Finish up ********************************************************/
1737 :
1738 0 : handshake->base.state = ((uchar)next_state);
1739 0 : return (long)read_sz;
1740 0 : }
1741 :
1742 : static long
1743 : fd_tls_client_hs_wait_cert( fd_tls_t const * const client,
1744 : fd_tls_estate_cli_t * const handshake,
1745 : uchar const * const record,
1746 : ulong const record_sz,
1747 0 : uint const encryption_level ) {
1748 :
1749 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1750 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1751 :
1752 : /* Read Certificate *************************************************/
1753 :
1754 0 : ulong read_sz;
1755 0 : do {
1756 0 : uchar const * wire = record;
1757 0 : uchar const * const wire_end = record + record_sz;
1758 :
1759 : /* Decode message header */
1760 :
1761 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1762 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1763 0 : if( FD_UNLIKELY( decode_res<0L ) )
1764 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_PARSE );
1765 0 : wire += (ulong)decode_res;
1766 :
1767 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_CERT ) )
1768 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_CERT_EXPECTED );
1769 :
1770 0 : ulong msg_sz = fd_tls_u24_to_uint( msg_hdr.sz );
1771 0 : if( FD_UNLIKELY( msg_sz > (ulong)(wire_end-wire) ) )
1772 0 : return fd_tls_alert( &handshake->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_CERT_PARSE );
1773 :
1774 : /* Decode Certificate */
1775 :
1776 0 : decode_res = fd_tls_client_handle_cert_chain( client, handshake, wire, msg_sz );
1777 0 : if( FD_UNLIKELY( decode_res<0L ) )
1778 0 : return fd_tls_alert( &handshake->base, (uint)(-decode_res), FD_TLS_REASON_CERT_PARSE );
1779 0 : wire += (ulong)decode_res;
1780 :
1781 0 : read_sz = (ulong)(wire - record);
1782 0 : } while(0);
1783 :
1784 0 : fd_sha256_append( &handshake->transcript, record, read_sz );
1785 :
1786 : /* Finish up ********************************************************/
1787 :
1788 0 : handshake->base.state = (char)FD_TLS_HS_WAIT_CV;
1789 0 : return (long)read_sz;
1790 0 : }
1791 :
1792 : static long
1793 : fd_tls_client_hs_wait_cert_verify( fd_tls_t const * const client,
1794 : fd_tls_estate_cli_t * const hs,
1795 : uchar const * const record,
1796 : ulong const record_sz,
1797 0 : uint const encryption_level ) {
1798 :
1799 0 : (void)client;
1800 :
1801 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1802 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1803 :
1804 : /* Decode incoming server CertificateVerify *************************/
1805 :
1806 0 : long res = fd_tls_handle_cert_verify( &hs->base, &hs->transcript,
1807 0 : record, record_sz,
1808 0 : hs->server_pubkey, hs->server_pubkey_len, hs->server_key_type, 0 );
1809 0 : if( FD_UNLIKELY( res<0L ) ) return res;
1810 :
1811 0 : fd_sha256_append( &hs->transcript, record, (ulong)res );
1812 :
1813 : /* Finish up ********************************************************/
1814 :
1815 0 : hs->base.state = FD_TLS_HS_WAIT_FINISHED;
1816 0 : return res;
1817 0 : }
1818 :
1819 : static long
1820 : fd_tls_client_hs_wait_finished( fd_tls_t const * const client,
1821 : fd_tls_estate_cli_t * const hs,
1822 : uchar const * const record,
1823 : ulong const record_sz,
1824 0 : uint const encryption_level ) {
1825 :
1826 0 : if( FD_UNLIKELY( encryption_level != FD_TLS_LEVEL_HANDSHAKE ) )
1827 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_WRONG_ENC_LVL );
1828 :
1829 : /* Export transcript hash ClientHello..CertificateVerify */
1830 :
1831 0 : fd_sha256_t transcript_clone = hs->transcript;
1832 0 : uchar transcript_hash[ 32 ];
1833 0 : fd_sha256_fini( &transcript_clone, transcript_hash );
1834 :
1835 : /* RFC 8446 Section 4.4.4:
1836 : finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
1837 : verify_data = HMAC(finished_key, Transcript-Hash(
1838 : Handshake Context, Certificate*, CertificateVerify*)) */
1839 :
1840 0 : uchar server_finished_key[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1841 0 : fd_tls_hkdf_expand_label( server_finished_key, 32UL,
1842 0 : hs->server_hs_secret,
1843 0 : "finished", 8UL,
1844 0 : NULL, 0UL );
1845 :
1846 0 : uchar server_finished_expected[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
1847 0 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
1848 0 : /* salt */ server_finished_key, 32UL,
1849 0 : /* out */ server_finished_expected );
1850 :
1851 : /* Read ServerFinished **********************************************/
1852 :
1853 0 : fd_tls_finished_t server_fin = {0};
1854 :
1855 0 : ulong read_sz;
1856 0 : do {
1857 0 : uchar const * wire = record;
1858 0 : uchar const * const wire_end = record + record_sz;
1859 :
1860 : /* Decode message header */
1861 :
1862 0 : fd_tls_msg_hdr_t msg_hdr = {0};
1863 0 : long decode_res = fd_tls_decode_msg_hdr( &msg_hdr, wire, (ulong)(wire_end-wire) );
1864 0 : if( FD_UNLIKELY( decode_res<0L ) )
1865 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_FINI_PARSE );
1866 0 : wire += (ulong)decode_res;
1867 :
1868 0 : if( FD_UNLIKELY( msg_hdr.type != FD_TLS_MSG_FINISHED ) )
1869 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_UNEXPECTED_MESSAGE, FD_TLS_REASON_FINI_EXPECTED );
1870 :
1871 0 : if( FD_UNLIKELY( fd_tls_u24_to_uint( msg_hdr.sz ) != sizeof(fd_tls_finished_t) ) )
1872 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_DECODE_ERROR, FD_TLS_REASON_FINI_PARSE );
1873 :
1874 : /* Decode server Finished */
1875 :
1876 0 : decode_res = fd_tls_decode_finished( &server_fin, wire, (ulong)(wire_end-wire) );
1877 0 : if( FD_UNLIKELY( decode_res<0L ) )
1878 0 : return fd_tls_alert( &hs->base, (uint)(-decode_res), FD_TLS_REASON_FINI_PARSE );
1879 0 : wire += (ulong)decode_res;
1880 :
1881 0 : read_sz = (ulong)(wire - record);
1882 0 : } while(0);
1883 :
1884 : /* Record ServerFinished */
1885 :
1886 0 : fd_sha256_append( &hs->transcript, record, read_sz );
1887 :
1888 : /* Verify that client and server's transcripts match */
1889 :
1890 0 : int match = 0;
1891 0 : for( ulong i=0; i<32UL; i++ ) {
1892 0 : match |= server_fin.verify[i] ^ server_finished_expected[i];
1893 0 : }
1894 0 : if( FD_UNLIKELY( match!=0 ) )
1895 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_DECRYPT_ERROR, FD_TLS_REASON_FINI_FAIL );
1896 :
1897 : /* Derive application secrets ***************************************/
1898 :
1899 : /* Export transcript hash ClientHello..ServerFinished */
1900 :
1901 0 : transcript_clone = hs->transcript;
1902 0 : fd_sha256_fini( &transcript_clone, transcript_hash );
1903 :
1904 : /* RFC 8446 Section 7.1:
1905 : client_application_traffic_secret_0 =
1906 : Derive-Secret(Master Secret, "c ap traffic",
1907 : ClientHello...server Finished) */
1908 :
1909 0 : uchar client_app_secret[ 32UL ] __attribute__((cleanup(fd_tls_clear_secret)));
1910 0 : fd_tls_hkdf_expand_label( client_app_secret, 32UL,
1911 0 : hs->master_secret,
1912 0 : "c ap traffic", 12UL,
1913 0 : transcript_hash, 32UL );
1914 :
1915 : /* RFC 8446 Section 7.1:
1916 : server_application_traffic_secret_0 =
1917 : Derive-Secret(Master Secret, "s ap traffic",
1918 : ClientHello...server Finished) */
1919 :
1920 0 : uchar server_app_secret[ 32UL ] __attribute__((cleanup(fd_tls_clear_secret)));
1921 0 : fd_tls_hkdf_expand_label( server_app_secret, 32UL,
1922 0 : hs->master_secret,
1923 0 : "s ap traffic", 12UL,
1924 0 : transcript_hash, 32UL );
1925 :
1926 : /* Call back with application secrets */
1927 :
1928 0 : client->secrets_fn( hs,
1929 0 : /* read secret */ server_app_secret,
1930 0 : /* write secret */ client_app_secret,
1931 0 : FD_TLS_LEVEL_APPLICATION );
1932 :
1933 0 : if( hs->client_cert && ( hs->client_cert_empty || !client->cert_x509_sz || !client->sign.sign_fn ) ) {
1934 :
1935 : /* RFC 8446 Section 4.4.2: a client that was asked for a certificate
1936 : but has none to offer sends a Certificate message with an empty
1937 : certificate_list and no CertificateVerify. The server decides
1938 : whether to continue. */
1939 :
1940 0 : static uchar const empty_cert[] = {
1941 0 : FD_TLS_MSG_CERT, /* msg_type */
1942 0 : 0x00, 0x00, 0x04, /* msg sz */
1943 0 : 0x00, /* certificate_request_context */
1944 0 : 0x00, 0x00, 0x00, /* certificate_list */
1945 0 : };
1946 :
1947 0 : if( FD_UNLIKELY( !client->sendmsg_fn(
1948 0 : hs,
1949 0 : empty_cert, sizeof(empty_cert),
1950 0 : FD_TLS_LEVEL_HANDSHAKE,
1951 0 : /* flush */ 0 ) ) )
1952 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
1953 :
1954 0 : fd_sha256_append( &hs->transcript, empty_cert, sizeof(empty_cert) );
1955 :
1956 0 : } else if( hs->client_cert ) {
1957 :
1958 : /* Send client Certificate ****************************************/
1959 :
1960 : /* Message buffer */
1961 0 : uchar msg_buf[ FD_TLS_SERVER_CERT_MSG_SZ_MAX ];
1962 0 : long cert_msg_sz = fd_tls_encode_cert_x509( client->cert_x509, client->cert_x509_sz, msg_buf, sizeof(msg_buf) );
1963 0 : if( FD_UNLIKELY( cert_msg_sz<0L ) )
1964 0 : return fd_tls_alert( &hs->base, (uint)(-cert_msg_sz), FD_TLS_REASON_CERT_ENCODE );
1965 :
1966 : /* Send certificate message */
1967 :
1968 0 : if( FD_UNLIKELY( !client->sendmsg_fn(
1969 0 : hs,
1970 0 : msg_buf, (ulong)cert_msg_sz,
1971 0 : FD_TLS_LEVEL_HANDSHAKE,
1972 0 : /* flush */ 0 ) ) )
1973 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
1974 :
1975 : /* Record Certificate message in transcript hash */
1976 :
1977 0 : fd_sha256_append( &hs->transcript, msg_buf, (ulong)cert_msg_sz );
1978 :
1979 : /* Send client CertificateVerify **********************************/
1980 :
1981 0 : long cvfy_res = fd_tls_send_cert_verify( client, &hs->base, &hs->transcript, 1 );
1982 0 : if( FD_UNLIKELY( !!cvfy_res ) ) return cvfy_res;
1983 :
1984 0 : }
1985 :
1986 : /* Send client Finished *********************************************/
1987 :
1988 0 : struct __attribute__((packed)) {
1989 0 : fd_tls_msg_hdr_t hdr;
1990 0 : fd_tls_finished_t fin;
1991 0 : } fin_rec;
1992 0 : fin_rec.hdr = (fd_tls_msg_hdr_t){
1993 0 : .type = FD_TLS_MSG_FINISHED,
1994 0 : .sz = fd_uint_to_tls_u24( 0x20 )
1995 0 : };
1996 :
1997 0 : fd_tls_msg_hdr_bswap( &fin_rec.hdr );
1998 :
1999 : /* Export transcript hash up to this point */
2000 :
2001 0 : fd_sha256_fini( &hs->transcript, transcript_hash );
2002 :
2003 : /* RFC 8446 Section 4.4.4:
2004 : finished_key = HKDF-Expand-Label(BaseKey, "finished", "", Hash.length)
2005 : verify_data = HMAC(finished_key, Transcript-Hash(
2006 : Handshake Context, Certificate*, CertificateVerify*)) */
2007 :
2008 0 : uchar client_finished_key[ 32 ] __attribute__((cleanup(fd_tls_clear_secret)));
2009 0 : fd_tls_hkdf_expand_label( client_finished_key, 32UL,
2010 0 : hs->client_hs_secret,
2011 0 : "finished", 8UL,
2012 0 : NULL, 0UL );
2013 :
2014 0 : fd_hmac_sha256( /* data */ transcript_hash, 32UL,
2015 0 : /* salt */ client_finished_key, 32UL,
2016 0 : /* out */ fin_rec.fin.verify );
2017 :
2018 : /* Send client Finished message */
2019 :
2020 0 : if( FD_UNLIKELY( !client->sendmsg_fn(
2021 0 : hs,
2022 0 : &fin_rec, sizeof(fin_rec),
2023 0 : FD_TLS_LEVEL_HANDSHAKE,
2024 0 : /* flush */ 1 ) ) )
2025 0 : return fd_tls_alert( &hs->base, FD_TLS_ALERT_INTERNAL_ERROR, FD_TLS_REASON_SENDMSG_FAIL );
2026 :
2027 0 : hs->base.state = FD_TLS_HS_CONNECTED;
2028 0 : return (long)read_sz;
2029 0 : }
2030 :
2031 : char const *
2032 0 : fd_tls_alert_cstr( uint alert ) {
2033 0 : switch( alert ) {
2034 0 : case FD_TLS_ALERT_UNEXPECTED_MESSAGE:
2035 0 : return "unexpected message";
2036 0 : case FD_TLS_ALERT_BAD_RECORD_MAC:
2037 0 : return "bad record MAC";
2038 0 : case FD_TLS_ALERT_RECORD_OVERFLOW:
2039 0 : return "record overflow";
2040 0 : case FD_TLS_ALERT_HANDSHAKE_FAILURE:
2041 0 : return "handshake failure";
2042 0 : case FD_TLS_ALERT_BAD_CERTIFICATE:
2043 0 : return "bad certificate";
2044 0 : case FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE:
2045 0 : return "unsupported certificate";
2046 0 : case FD_TLS_ALERT_CERTIFICATE_REVOKED:
2047 0 : return "certificate revoked";
2048 0 : case FD_TLS_ALERT_CERTIFICATE_EXPIRED:
2049 0 : return "certificate expired";
2050 0 : case FD_TLS_ALERT_CERTIFICATE_UNKNOWN:
2051 0 : return "certificate unknown";
2052 0 : case FD_TLS_ALERT_ILLEGAL_PARAMETER:
2053 0 : return "illegal parameter";
2054 0 : case FD_TLS_ALERT_UNKNOWN_CA:
2055 0 : return "unknown CA";
2056 0 : case FD_TLS_ALERT_ACCESS_DENIED:
2057 0 : return "access denied";
2058 0 : case FD_TLS_ALERT_DECODE_ERROR:
2059 0 : return "decode error";
2060 0 : case FD_TLS_ALERT_DECRYPT_ERROR:
2061 0 : return "decrypt error";
2062 0 : case FD_TLS_ALERT_PROTOCOL_VERSION:
2063 0 : return "unsupported protocol version";
2064 0 : case FD_TLS_ALERT_INSUFFICIENT_SECURITY:
2065 0 : return "insufficient security";
2066 0 : case FD_TLS_ALERT_INTERNAL_ERROR:
2067 0 : return "internal error";
2068 0 : case FD_TLS_ALERT_INAPPROPRIATE_FALLBACK:
2069 0 : return "inappropriate fallback";
2070 0 : case FD_TLS_ALERT_USER_CANCELED:
2071 0 : return "user canceled";
2072 0 : case FD_TLS_ALERT_MISSING_EXTENSION:
2073 0 : return "missing extension";
2074 0 : case FD_TLS_ALERT_UNSUPPORTED_EXTENSION:
2075 0 : return "unsupported extension";
2076 0 : case FD_TLS_ALERT_UNRECOGNIZED_NAME:
2077 0 : return "unrecognized name";
2078 0 : case FD_TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE:
2079 0 : return "bad certificate status response";
2080 0 : case FD_TLS_ALERT_UNKNOWN_PSK_IDENTITY:
2081 0 : return "unknown PSK identity";
2082 0 : case FD_TLS_ALERT_CERTIFICATE_REQUIRED:
2083 0 : return "certificate required";
2084 0 : case FD_TLS_ALERT_NO_APPLICATION_PROTOCOL:
2085 0 : return "no application protocol";
2086 0 : default:
2087 0 : return "unknown alert";
2088 : /* TODO add the other alert codes */
2089 0 : }
2090 0 : }
2091 :
2092 : char const *
2093 0 : fd_tls_reason_cstr( uint reason ) {
2094 0 : switch( reason ) {
2095 0 : case FD_TLS_REASON_ILLEGAL_STATE:
2096 0 : return "illegal handshake state ID (memory corruption?)";
2097 0 : case FD_TLS_REASON_SENDMSG_FAIL:
2098 0 : return "sendmsg callback failed";
2099 0 : case FD_TLS_REASON_WRONG_ENC_LVL:
2100 0 : return "wrong encryption level";
2101 0 : case FD_TLS_REASON_CH_EXPECTED:
2102 0 : return "expected ClientHello, but got other message type";
2103 0 : case FD_TLS_REASON_CH_PARSE:
2104 0 : return "failed to decode ClientHello";
2105 0 : case FD_TLS_REASON_CH_ENCODE:
2106 0 : return "failed to encode ClientHello";
2107 0 : case FD_TLS_REASON_CH_NEG_VER:
2108 0 : return "unsupported TLS version (fd_tls only supports TLS 1.3)";
2109 0 : case FD_TLS_REASON_CH_NEG_KX:
2110 0 : return "ClientHello did not advertise X25519 as a supported key exchange alg";
2111 0 : case FD_TLS_REASON_CH_NEG_SIG:
2112 0 : return "ClientHello did not advertise Ed25519 as a supported signature alg";
2113 0 : case FD_TLS_REASON_CH_NEG_CIPHER:
2114 0 : return "ClientHello did not advertise AES-128-GCM as a supported cipher suite";
2115 0 : case FD_TLS_REASON_CH_SESSION_ID:
2116 0 : return "QUIC ClientHello requested compatibility mode";
2117 0 : case FD_TLS_REASON_CH_NO_QUIC:
2118 0 : return "client does not support QUIC (missing QUIC transport params)";
2119 0 : case FD_TLS_REASON_CH_RETRY_KS:
2120 0 : return "client didn't provide an X25519 key share even after a RetryHelloRequest";
2121 0 : case FD_TLS_REASON_X25519_FAIL:
2122 0 : return "X25519 key exchange failed";
2123 0 : case FD_TLS_REASON_NO_X509:
2124 0 : return "local X.509 certificate is not configured";
2125 0 : case FD_TLS_REASON_WRONG_PUBKEY:
2126 0 : return "peer identity does not match expected public key";
2127 0 : case FD_TLS_REASON_ED25519_FAIL:
2128 0 : return "Ed25519 signature verification failed";
2129 0 : case FD_TLS_REASON_SECP256R1_FAIL:
2130 0 : return "ECDSA P-256 signature verification failed";
2131 0 : case FD_TLS_REASON_RSA_FAIL:
2132 0 : return "RSA-PSS signature verification failed";
2133 0 : case FD_TLS_REASON_FINI_FAIL:
2134 0 : return "unexpected 'Finished' data (transcript hash fail)";
2135 0 : case FD_TLS_REASON_QUIC_TP_OVERSZ:
2136 0 : return "buffer overflow in QUIC transport param handling (user bug)";
2137 0 : case FD_TLS_REASON_EE_NO_QUIC:
2138 0 : return "server does not support QUIC (missing QUIC transport params)";
2139 0 : case FD_TLS_REASON_X509_PARSE:
2140 0 : return "X.509 cert parse failed";
2141 0 : case FD_TLS_REASON_CV_EXPECTED:
2142 0 : return "expected CertificateVerify, but got other message type";
2143 0 : case FD_TLS_REASON_CV_SIGALG:
2144 0 : return "peer CertificateVerify uses a signature algorithm incompatible with its cert";
2145 0 : case FD_TLS_REASON_FINI_PARSE:
2146 0 : return "failed to parse 'Finished' message";
2147 0 : case FD_TLS_REASON_SH_EXPECTED:
2148 0 : return "expected ServerHello, but got other message type";
2149 0 : case FD_TLS_REASON_SH_PARSE:
2150 0 : return "failed to decode ServerHello";
2151 0 : case FD_TLS_REASON_SH_ENCODE:
2152 0 : return "failed to encode ServerHello";
2153 0 : case FD_TLS_REASON_SH_NEG_CIPHER:
2154 0 : return "ServerHello selected a cipher suite not offered by ClientHello";
2155 0 : case FD_TLS_REASON_SH_SESSION_ID:
2156 0 : return "ServerHello legacy_session_id_echo does not match ClientHello";
2157 0 : case FD_TLS_REASON_EE_EXPECTED:
2158 0 : return "expected EncryptedExtensions, but got other message type";
2159 0 : case FD_TLS_REASON_EE_PARSE:
2160 0 : return "failed to decode EncryptedExtensions";
2161 0 : case FD_TLS_REASON_EE_ENCODE:
2162 0 : return "failed to encode EncryptedExtensions";
2163 0 : case FD_TLS_REASON_CERT_KEY_TYPE:
2164 0 : return "unsupported certificate key type";
2165 0 : case FD_TLS_REASON_CERT_EXPECTED:
2166 0 : return "expected Certificate, but got other message type";
2167 0 : case FD_TLS_REASON_CERT_PARSE:
2168 0 : return "failed to decode Certificate";
2169 0 : case FD_TLS_REASON_CERT_ENCODE:
2170 0 : return "failed to encode Certificate";
2171 0 : case FD_TLS_REASON_CERT_VERIFY:
2172 0 : return "certificate chain failed verification";
2173 0 : case FD_TLS_REASON_FINI_EXPECTED:
2174 0 : return "expected Finished, but got other message type";
2175 0 : case FD_TLS_REASON_CERT_CR_EXPECTED:
2176 0 : return "expected Certificate or CertificateRequest, but got other message type";
2177 0 : case FD_TLS_REASON_CERT_CR_PARSE:
2178 0 : return "failed to decode Certificate or CertificateRequest";
2179 0 : case FD_TLS_REASON_CERT_CHAIN_EMPTY:
2180 0 : return "peer did not provide a certificate";
2181 0 : case FD_TLS_REASON_CERT_CHAIN_PARSE:
2182 0 : return "invalid peer cert chain";
2183 0 : case FD_TLS_REASON_CV_PARSE:
2184 0 : return "failed to decode CertificateVerify";
2185 0 : case FD_TLS_REASON_CV_ENCODE:
2186 0 : return "failed to encode CertificateVerify";
2187 0 : case FD_TLS_REASON_ALPN_PARSE:
2188 0 : return "failed to decode ALPN extension";
2189 0 : case FD_TLS_REASON_ALPN_NEG:
2190 0 : return "ALPN negotiation failed";
2191 0 : case FD_TLS_REASON_NO_ALPN:
2192 0 : return "peer did not send ALPN extension";
2193 0 : case FD_TLS_REASON_POST_HS_MSG:
2194 0 : return "unexpected post-handshake message type";
2195 0 : case FD_TLS_REASON_KEY_UPDATE_PARSE:
2196 0 : return "failed to parse KeyUpdate";
2197 0 : case FD_TLS_REASON_CCS:
2198 0 : return "unexpected ChangeCipherSpec record";
2199 0 : case FD_TLS_REASON_ALERT_PARSE:
2200 0 : return "malformed alert record";
2201 0 : case FD_TLS_REASON_PEER_ALERT:
2202 0 : return "peer sent a fatal alert";
2203 0 : case FD_TLS_REASON_HS_INTERLEAVED:
2204 0 : return "record interleaved with a fragmented handshake message";
2205 0 : case FD_TLS_REASON_REC_TYPE:
2206 0 : return "unexpected record layer content type";
2207 0 : case FD_TLS_REASON_REC_OVERFLOW:
2208 0 : return "record larger than the protocol allows";
2209 0 : case FD_TLS_REASON_HS_KEY_CHANGE:
2210 0 : return "handshake data follows a key change in the same record";
2211 0 : case FD_TLS_REASON_HS_MSG_SIZE:
2212 0 : return "handshake message length invalid";
2213 0 : case FD_TLS_REASON_REC_MAC:
2214 0 : return "record failed authentication";
2215 0 : case FD_TLS_REASON_REC_PADDING:
2216 0 : return "record has no content type byte";
2217 0 : default:
2218 0 : FD_LOG_WARNING(( "Missing fd_tls_reason_cstr code for %u (memory corruption?)", reason ));
2219 0 : __attribute__((fallthrough));
2220 : /* TODO need to add a lot more error reason codes */
2221 0 : case FD_TLS_REASON_NULL:
2222 0 : return "unknown reason";
2223 0 : }
2224 0 : }
|