LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 868 1138 76.3 %
Date: 2026-07-09 05:37:44 Functions: 30 32 93.8 %

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

Generated by: LCOV version 1.14