LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 699 1005 69.6 %
Date: 2024-11-13 11:58:15 Functions: 23 29 79.3 %

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

Generated by: LCOV version 1.14