LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 1292 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 33 0.0 %

          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 : }

Generated by: LCOV version 1.14