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

Generated by: LCOV version 1.14