LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 697 1070 65.1 %
Date: 2025-01-08 12:08:44 Functions: 23 30 76.7 %

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

Generated by: LCOV version 1.14