LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls_proto.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 567 679 83.5 %
Date: 2024-11-13 11:58:15 Functions: 21 26 80.8 %

          Line data    Source code
       1             : #include "fd_tls.h"
       2             : #include "fd_tls_proto.h"
       3             : #include "fd_tls_serde.h"
       4             : #include "fd_tls_asn1.h"
       5             : #include "../../ballet/x509/fd_x509_mock.h"
       6             : 
       7             : typedef struct fd_tls_u24 tls_u24;  /* code generator helper */
       8             : 
       9             : #define FD_TLS_ENCODE_EXT_BEGIN( type )                         \
      10             :   do {                                                          \
      11             :     int valid = 1;                                              \
      12             :     FD_TLS_SERDE_LOCATE( ext_type, _, ushort, 1 );              \
      13             :     FD_TLS_SERDE_LOCATE( ext_sz,   _, ushort, 1 );              \
      14             :     FD_TLS_SERDE_CHECK                                          \
      15             :     ushort *    ext_type_ptr = (ushort *)_field_ext_type_laddr; \
      16             :     ushort *    ext_sz_ptr   = (ushort *)_field_ext_sz_laddr;   \
      17             :     ulong const ext_start    = wire_laddr;                      \
      18             :     *ext_type_ptr = fd_ushort_bswap( type );
      19             : 
      20             : #define FD_TLS_ENCODE_EXT_END                    \
      21             :     ulong ext_sz = wire_laddr - ext_start;       \
      22             :     if( FD_UNLIKELY( ext_sz > USHORT_MAX ) )     \
      23             :       return -(long)FD_TLS_ALERT_INTERNAL_ERROR; \
      24             :     *ext_sz_ptr = fd_ushort_bswap( ext_sz );     \
      25             :   } while(0)
      26             : 
      27             : long
      28             : fd_tls_decode_client_hello( fd_tls_client_hello_t * out,
      29             :                             uchar const * const     wire,
      30        6024 :                             ulong                   wire_sz ) {
      31             : 
      32        6024 :   ulong wire_laddr = (ulong)wire;
      33             : 
      34             :   /* Decode static sized part of client hello.
      35             :      (Assuming that session ID field is of a certain size) */
      36             : 
      37        6024 :   ushort legacy_version;       /* ==FD_TLS_VERSION_TLS12 */
      38        6024 :   uchar  legacy_session_id_sz; /* ==0 */
      39             : 
      40        6024 : # define FIELDS( FIELD )                            \
      41       12048 :     FIELD( 0, &legacy_version,       ushort, 1    ) \
      42       12048 :     FIELD( 1, &out->random[0],       uchar,  32UL ) \
      43       12048 :     FIELD( 2, &legacy_session_id_sz, uchar,  1    )
      44       12048 :     FD_TLS_DECODE_STATIC_BATCH( FIELDS )
      45        6024 : # undef FIELDS
      46             : 
      47        6024 :   if( FD_UNLIKELY( ( legacy_session_id_sz > 32      ) |
      48        6024 :                    ( wire_sz < legacy_session_id_sz ) ) )
      49           0 :     return -(long)FD_TLS_ALERT_DECODE_ERROR;
      50             : 
      51        6024 :   out->session_id.buf   = (void *)wire_laddr;
      52        6024 :   out->session_id.bufsz = legacy_session_id_sz;
      53        6024 :   wire_laddr += legacy_session_id_sz;
      54        6024 :   wire_sz    -= legacy_session_id_sz;
      55             : 
      56             :   /* Decode cipher suite list */
      57             : 
      58       24096 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
      59        6051 :     ushort cipher_suite;
      60        6051 :     FD_TLS_DECODE_FIELD( &cipher_suite, ushort );
      61             : 
      62        6051 :     switch( cipher_suite ) {
      63        6021 :     case FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256:
      64        6021 :       out->cipher_suites.aes_128_gcm_sha256 = 1;
      65        6021 :       break;
      66          30 :     default:
      67             :       /* Ignore unsupported cipher suites ... */
      68          30 :       break;
      69        6051 :     }
      70        6051 :   }
      71        6024 :   FD_TLS_DECODE_LIST_END
      72             : 
      73             :   /* Decode next static sized part of client hello */
      74             : 
      75        6024 :   uchar  legacy_compression_method_cnt;    /* == 1  */
      76        6024 :   uchar  legacy_compression_methods[ 1 ];  /* =={0} */
      77             : 
      78        6024 : # define FIELDS( FIELD )                                  \
      79       12048 :     FIELD( 5, &legacy_compression_method_cnt, uchar,  1 ) \
      80       12048 :     FIELD( 6, &legacy_compression_methods[0], uchar,  1 )
      81       12048 :     FD_TLS_DECODE_STATIC_BATCH( FIELDS )
      82        6024 : # undef FIELDS
      83             : 
      84        6024 :   if( FD_UNLIKELY( ( legacy_compression_method_cnt != 1 )
      85        6024 :                  | ( legacy_compression_methods[0] != 0 ) ) )
      86           0 :     return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
      87             : 
      88             :   /* Read extensions */
      89             : 
      90       48201 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
      91             :     /* Read extension type and length */
      92       48201 :     ushort ext_type;
      93       48201 :     ushort ext_sz;
      94       48201 : #   define FIELDS( FIELD )             \
      95       96402 :       FIELD( 0, &ext_type, ushort, 1 ) \
      96       96402 :       FIELD( 1, &ext_sz,   ushort, 1 )
      97       96402 :       FD_TLS_DECODE_STATIC_BATCH( FIELDS )
      98       48201 : #   undef FIELDS
      99             : 
     100             :     /* Bounds check extension data */
     101       48201 :     if( FD_UNLIKELY( ext_sz > wire_sz ) )
     102           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     103             : 
     104             :     /* Decode extension data */
     105       48201 :     uchar const * ext_data = (uchar const *)wire_laddr;
     106       48201 :     long ext_parse_res;
     107       48201 :     switch( ext_type ) {
     108        6024 :     case FD_TLS_EXT_SUPPORTED_VERSIONS:
     109        6024 :       ext_parse_res = fd_tls_decode_ext_supported_versions( &out->supported_versions, ext_data, ext_sz );
     110        6024 :       break;
     111           3 :     case FD_TLS_EXT_SERVER_NAME:
     112           3 :       ext_parse_res = fd_tls_decode_ext_server_name( &out->server_name, ext_data, ext_sz );
     113           3 :       break;
     114        6024 :     case FD_TLS_EXT_SUPPORTED_GROUPS:
     115        6024 :       ext_parse_res = fd_tls_decode_ext_supported_groups( &out->supported_groups, ext_data, ext_sz );
     116        6024 :       break;
     117        6024 :     case FD_TLS_EXT_SIGNATURE_ALGORITHMS:
     118        6024 :       ext_parse_res = fd_tls_decode_ext_signature_algorithms( &out->signature_algorithms, ext_data, ext_sz );
     119        6024 :       break;
     120        6024 :     case FD_TLS_EXT_KEY_SHARE:
     121        6024 :       ext_parse_res = fd_tls_decode_key_share_list( &out->key_share, ext_data, ext_sz );
     122        6024 :       break;
     123        6021 :     case FD_TLS_EXT_SERVER_CERT_TYPE:
     124        6021 :       ext_parse_res = fd_tls_decode_ext_cert_type_list( &out->server_cert_types, ext_data, ext_sz );
     125        6021 :       break;
     126        6021 :     case FD_TLS_EXT_CLIENT_CERT_TYPE:
     127        6021 :       ext_parse_res = fd_tls_decode_ext_cert_type_list( &out->client_cert_types, ext_data, ext_sz );
     128        6021 :       break;
     129        6021 :     case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
     130        6021 :       ext_parse_res = fd_tls_decode_ext_quic_tp( &out->quic_tp, ext_data, ext_sz );
     131        6021 :       break;
     132        6021 :     case FD_TLS_EXT_ALPN:
     133        6021 :       ext_parse_res = fd_tls_decode_ext_alpn( &out->alpn, ext_data, ext_sz );
     134        6021 :       break;
     135          18 :     default:
     136          18 :       ext_parse_res = (long)ext_sz;
     137          18 :       break;
     138       48201 :     }
     139       48201 :     if( FD_UNLIKELY( ext_parse_res<0L ) )
     140           0 :       return ext_parse_res;
     141       48201 :     if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
     142           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     143             : 
     144             :     /* Seek to next extension */
     145       48201 :     wire_laddr += ext_sz;
     146       48201 :     wire_sz    -= ext_sz;
     147       48201 :   }
     148        6024 :   FD_TLS_DECODE_LIST_END
     149             : 
     150        6024 :   return (long)( wire_laddr - (ulong)wire );
     151        6024 : }
     152             : 
     153             : long
     154             : fd_tls_encode_client_hello( fd_tls_client_hello_t const * in,
     155             :                             uchar *                       wire,
     156        6021 :                             ulong                         wire_sz ) {
     157             : 
     158        6021 :   ulong wire_laddr = (ulong)wire;
     159             : 
     160             :   /* Encode static sized part of client hello */
     161             : 
     162        6021 :   ushort legacy_version        = FD_TLS_VERSION_TLS12;
     163        6021 :   uchar  legacy_session_id_sz  = 0;
     164        6021 :   ushort cipher_suite_sz       = 1*sizeof(ushort);
     165        6021 :   ushort cipher_suites[1]      = { FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 };
     166        6021 :   uchar  legacy_comp_method_sz = 1;
     167        6021 :   uchar  legacy_comp_method[1] = {0};
     168             : 
     169        6021 : # define FIELDS( FIELD )                                 \
     170       12042 :     FIELD( 0, &legacy_version,            ushort, 1    ) \
     171       12042 :     FIELD( 1,  in->random,                uchar,  32UL ) \
     172       12042 :     FIELD( 2, &legacy_session_id_sz,      uchar,  1    ) \
     173       12042 :     FIELD( 3, &cipher_suite_sz,           ushort, 1    ) \
     174       12042 :     FIELD( 4,  cipher_suites,             ushort, 1    ) \
     175       12042 :     FIELD( 5, &legacy_comp_method_sz,     uchar,  1    ) \
     176       12042 :     FIELD( 6,  legacy_comp_method,        uchar,  1    )
     177       12042 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     178        6021 : # undef FIELDS
     179             : 
     180             :   /* Encode extensions */
     181             : 
     182        6021 :   ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
     183           0 :   ulong    extension_start  = wire_laddr;
     184             : 
     185        6021 :   ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
     186        6021 :   ushort ext_supported_versions_ext_sz   = 3;
     187        6021 :   uchar  ext_supported_versions_sz       = 2;
     188        6021 :   ushort ext_supported_versions[1]       = { FD_TLS_VERSION_TLS13 };
     189             : 
     190        6021 :   ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
     191        6021 :   ushort ext_key_share_ext_sz   = 38;
     192        6021 :   ushort ext_key_share_sz1      = 36;
     193        6021 :   ushort ext_key_share_group    = FD_TLS_GROUP_X25519;
     194        6021 :   ushort ext_key_share_sz       = 32;
     195             : 
     196        6021 :   ushort ext_supported_groups_ext_type = FD_TLS_EXT_SUPPORTED_GROUPS;
     197        6021 :   ushort ext_supported_groups_ext_sz   = 4;
     198        6021 :   ushort ext_supported_groups_sz       = 2;
     199        6021 :   ushort ext_supported_groups[1]       = { FD_TLS_GROUP_X25519 };
     200             : 
     201        6021 :   ushort ext_sigalg_ext_type = FD_TLS_EXT_SIGNATURE_ALGORITHMS;
     202        6021 :   ushort ext_sigalg_ext_sz   = 4;
     203        6021 :   ushort ext_sigalg_sz       = 2;
     204        6021 :   ushort ext_sigalg[1]       = { FD_TLS_SIGNATURE_ED25519 };
     205             : 
     206        6021 : # define FIELDS( FIELD ) \
     207       12042 :     FIELD( 0, &ext_supported_versions_ext_type,   ushort, 1    ) \
     208       12042 :     FIELD( 1, &ext_supported_versions_ext_sz,     ushort, 1    ) \
     209       12042 :     FIELD( 2, &ext_supported_versions_sz,         uchar,  1    ) \
     210       12042 :     FIELD( 3,  ext_supported_versions,            ushort, 1    ) \
     211       12042 :     FIELD( 4, &ext_key_share_ext_type,            ushort, 1    ) \
     212       12042 :     FIELD( 5, &ext_key_share_ext_sz,              ushort, 1    ) \
     213       12042 :     FIELD( 6, &ext_key_share_sz1,                 ushort, 1    ) \
     214       12042 :     FIELD( 7, &ext_key_share_group,               ushort, 1    ) \
     215       12042 :     FIELD( 8, &ext_key_share_sz,                  ushort, 1    ) \
     216       12042 :     FIELD( 9, &in->key_share.x25519[0],           uchar,  32UL ) \
     217       12042 :     FIELD(10, &ext_supported_groups_ext_type,     ushort, 1    ) \
     218       12042 :     FIELD(11, &ext_supported_groups_ext_sz,       ushort, 1    ) \
     219       12042 :     FIELD(12, &ext_supported_groups_sz,           ushort, 1    ) \
     220       12042 :     FIELD(13,  ext_supported_groups,              ushort, 1    ) \
     221       12042 :     FIELD(14, &ext_sigalg_ext_type,               ushort, 1    ) \
     222       12042 :     FIELD(15, &ext_sigalg_ext_sz,                 ushort, 1    ) \
     223       12042 :     FIELD(16, &ext_sigalg_sz,                     ushort, 1    ) \
     224       12042 :     FIELD(17,  ext_sigalg,                        ushort, 1    )
     225       12042 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     226        6021 : # undef FIELDS
     227             : 
     228             :   /* Add ALPN */
     229             : 
     230        6021 :   if( in->alpn.bufsz ) {
     231        6015 :     fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
     232        6015 :                                  .sz   = (ushort)( in->alpn.bufsz+2 ) };
     233        6015 :     FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr,  &ext_hdr  );
     234        6015 :     FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
     235        6015 :   }
     236             : 
     237             :   /* Add QUIC transport params */
     238             : 
     239        6021 :   if( in->quic_tp.buf ) {
     240        6015 :     ushort  quic_tp_ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
     241        6015 :     ushort  quic_tp_ext_sz   = (ushort)in->quic_tp.bufsz;
     242        6015 : #   define FIELDS( FIELD )                    \
     243       12030 :     FIELD( 0, &quic_tp_ext_type, ushort, 1 ); \
     244       12030 :     FIELD( 1, &quic_tp_ext_sz,   ushort, 1 ); \
     245       12030 :     FIELD( 2, in->quic_tp.buf,   uchar,  in->quic_tp.bufsz );
     246       12030 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     247        6015 : # undef FIELDS
     248        6015 :   }
     249             : 
     250             :   /* Add certificate types */
     251             : 
     252        6021 :   uchar  cert_type_srv[2]            = { FD_TLS_CERTTYPE_RAW_PUBKEY, FD_TLS_CERTTYPE_X509 };
     253        6021 :   ulong  cert_type_srv_cnt           = 1 + (!!in->server_cert_types.x509);
     254        6021 :   ushort cert_type_srv_list_ext_type = FD_TLS_EXT_SERVER_CERT_TYPE;
     255        6021 :   ushort cert_type_srv_list_ext_sz   = (ushort)(cert_type_srv_cnt+1UL);
     256        6021 :   uchar  cert_type_srv_list_sz       = (uchar ) cert_type_srv_cnt;
     257             : 
     258        6021 :   uchar  cert_type_cli[2]            = { FD_TLS_CERTTYPE_RAW_PUBKEY, FD_TLS_CERTTYPE_X509 };
     259        6021 :   ulong  cert_type_cli_cnt           = 1 + (!!in->client_cert_types.x509);
     260        6021 :   ushort cert_type_cli_list_ext_type = FD_TLS_EXT_CLIENT_CERT_TYPE;
     261        6021 :   ushort cert_type_cli_list_ext_sz   = (ushort)(cert_type_cli_cnt+1UL);
     262        6021 :   uchar  cert_type_cli_list_sz       = (uchar ) cert_type_cli_cnt;
     263             : 
     264        6021 : # define FIELDS( FIELD ) \
     265       12042 :   FIELD( 0, &cert_type_srv_list_ext_type, ushort, 1                 ); \
     266       12042 :   FIELD( 1, &cert_type_srv_list_ext_sz,   ushort, 1                 ); \
     267       12042 :   FIELD( 2, &cert_type_srv_list_sz,       uchar,  1                 ); \
     268       12042 :   FIELD( 3,  cert_type_srv,               uchar,  cert_type_srv_cnt ); \
     269       12042 :   FIELD( 4, &cert_type_cli_list_ext_type, ushort, 1                 ); \
     270       12042 :   FIELD( 5, &cert_type_cli_list_ext_sz,   ushort, 1                 ); \
     271       12042 :   FIELD( 6, &cert_type_cli_list_sz,       uchar,  1                 ); \
     272       12042 :   FIELD( 7,  cert_type_cli,               uchar,  cert_type_cli_cnt );
     273       12042 :   FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     274        6021 : # undef FIELDS
     275             : 
     276        6021 :   *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
     277        6021 :   return (long)( wire_laddr - (ulong)wire );
     278        6021 : }
     279             : 
     280             : long
     281             : fd_tls_decode_server_hello( fd_tls_server_hello_t * out,
     282             :                             uchar const *           wire,
     283        6024 :                             ulong                   wire_sz ) {
     284             : 
     285        6024 :   ulong wire_laddr = (ulong)wire;
     286             : 
     287             :   /* Decode static sized part of server hello */
     288             : 
     289        6024 :   ushort legacy_version;            /* ==FD_TLS_VERSION_TLS12 */
     290        6024 :   uchar  legacy_session_id_sz;      /* ==0 */
     291        6024 :   ushort cipher_suite;              /* ==FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 */
     292        6024 :   uchar  legacy_compression_method; /* ==0 */
     293             : 
     294        6024 : # define FIELDS( FIELD )                                 \
     295       12048 :     FIELD( 0, &legacy_version,            ushort, 1    ) \
     296       12048 :     FIELD( 1, &out->random[0],            uchar,  32UL ) \
     297       12048 :     FIELD( 2, &legacy_session_id_sz,      uchar,  1    ) \
     298       12048 :     FIELD( 3, &cipher_suite,              ushort, 1    ) \
     299       12048 :     FIELD( 4, &legacy_compression_method, uchar,  1    )
     300       12048 :     FD_TLS_DECODE_STATIC_BATCH( FIELDS )
     301        6024 : # undef FIELDS
     302             : 
     303        6024 :   if( FD_UNLIKELY( ( legacy_version != FD_TLS_VERSION_TLS12 )
     304        6024 :                  | ( legacy_session_id_sz      != 0         )
     305        6024 :                  | ( legacy_compression_method != 0         ) ) )
     306           0 :     return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
     307             : 
     308        6024 :   if( FD_UNLIKELY( cipher_suite != FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 ) )
     309           3 :     return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
     310             : 
     311             :   /* Middlebox compatibility for HelloRetryRequest */
     312             : 
     313        6021 :   static uchar const special_random[ 32 ] =
     314        6021 :     { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
     315        6021 :       0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
     316        6021 :       0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
     317        6021 :       0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C };
     318        6021 :   if( FD_UNLIKELY( 0==memcmp( out->random, special_random, 32 ) ) )
     319           0 :     return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
     320             : 
     321             :   /* Read extensions */
     322             : 
     323       24084 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
     324             :     /* Read extension type and length */
     325       12042 :     ushort ext_type;
     326       12042 :     ushort ext_sz;
     327       12042 : #   define FIELDS( FIELD )             \
     328       24084 :       FIELD( 0, &ext_type, ushort, 1 ) \
     329       24084 :       FIELD( 1, &ext_sz,   ushort, 1 )
     330       24084 :       FD_TLS_DECODE_STATIC_BATCH( FIELDS )
     331       12042 : #   undef FIELDS
     332             : 
     333             :     /* Bounds check extension data */
     334       12042 :     if( FD_UNLIKELY( ext_sz > wire_sz ) )
     335           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     336             : 
     337       12042 :     ulong next_field = wire_laddr + ext_sz;
     338       12042 :     ulong next_sz    = wire_sz    - ext_sz;
     339             : 
     340             :     /* Decode extension data */
     341       12042 :     uchar const * ext_data = (uchar const *)wire_laddr;
     342       12042 :     long ext_parse_res;
     343       12042 :     switch( ext_type ) {
     344        6021 :     case FD_TLS_EXT_SUPPORTED_VERSIONS: {
     345        6021 :       ushort chosen_version;
     346        6021 :       FD_TLS_DECODE_FIELD( &chosen_version, ushort );
     347        6021 :       ext_parse_res = 2L;
     348        6021 :       if( FD_UNLIKELY( chosen_version!=FD_TLS_VERSION_TLS13 ) )
     349           0 :         return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
     350        6021 :       break;
     351        6021 :     }
     352        6021 :     case FD_TLS_EXT_KEY_SHARE:
     353        6021 :       ext_parse_res = fd_tls_decode_key_share( &out->key_share, ext_data, ext_sz );
     354        6021 :       break;
     355           0 :     case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
     356             :       /* Copy transport params as-is (TODO...) */
     357           0 :       ext_parse_res = (long)ext_sz;
     358           0 :       break;
     359           0 :     default:
     360             :       /* Reject unsolicited extensions */
     361           0 :       return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
     362       12042 :     }
     363             : 
     364       12042 :     if( FD_UNLIKELY( ext_parse_res<0L ) )
     365           0 :       return ext_parse_res;
     366       12042 :     if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
     367           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     368             : 
     369       12042 :     wire_laddr = next_field;
     370       12042 :     wire_sz    = next_sz;
     371       12042 :   }
     372        6021 :   FD_TLS_DECODE_LIST_END
     373             : 
     374             :   /* Check for required extensions */
     375             : 
     376        6021 :   if( FD_UNLIKELY( !out->key_share.has_x25519 ) )
     377           0 :     return -(long)FD_TLS_ALERT_MISSING_EXTENSION;
     378             : 
     379        6021 :   return (long)( wire_laddr - (ulong)wire );
     380        6021 : }
     381             : 
     382             : long
     383             : fd_tls_encode_server_hello( fd_tls_server_hello_t const * in,
     384             :                             uchar *                       wire,
     385        6021 :                             ulong                         wire_sz ) {
     386             : 
     387        6021 :   ulong wire_laddr = (ulong)wire;
     388             : 
     389             :   /* Encode static sized part of server hello.
     390             :      (Assuming that session ID field is of a certain size) */
     391             : 
     392        6021 :   ushort legacy_version            = FD_TLS_VERSION_TLS12;
     393        6021 :   uchar  legacy_session_id_sz      = (uchar)in->session_id.bufsz;
     394        6021 :   ushort cipher_suite              = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256;
     395        6021 :   uchar  legacy_compression_method = 0;
     396             : 
     397        6021 : # define FIELDS( FIELD )                                 \
     398       12042 :     FIELD( 0, &legacy_version,            ushort, 1    ) \
     399       12042 :     FIELD( 1, &in->random[0],             uchar,  32UL ) \
     400       12042 :     FIELD( 2, &legacy_session_id_sz,      uchar,  1    ) \
     401       12042 :     FIELD( 3,  in->session_id.buf,        uchar,  legacy_session_id_sz ) \
     402       12042 :     FIELD( 4, &cipher_suite,              ushort, 1    ) \
     403       12042 :     FIELD( 5, &legacy_compression_method, uchar,  1    )
     404       12042 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     405        6021 : # undef FIELDS
     406             : 
     407             :   /* Encode extensions */
     408             : 
     409        6021 :   ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
     410           0 :   ulong    extension_start  = wire_laddr;
     411             : 
     412        6021 :   ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
     413        6021 :   ushort ext_supported_versions[1]       = { FD_TLS_VERSION_TLS13 };
     414        6021 :   ushort ext_supported_versions_ext_sz   = sizeof(ext_supported_versions);
     415             : 
     416        6021 :   ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
     417        6021 :   ushort ext_key_share_ext_sz   = sizeof(ushort) + sizeof(ushort) + 32UL;
     418        6021 :   ushort ext_key_share_group    = FD_TLS_GROUP_X25519;
     419        6021 :   ushort ext_key_share_sz       = 32UL;
     420             : 
     421        6021 : # define FIELDS( FIELD )                                         \
     422       12042 :     FIELD( 0, &ext_supported_versions_ext_type,   ushort, 1    ) \
     423       12042 :     FIELD( 1, &ext_supported_versions_ext_sz,     ushort, 1    ) \
     424       12042 :     FIELD( 2,  ext_supported_versions,            ushort, 1    ) \
     425       12042 :     FIELD( 3, &ext_key_share_ext_type,            ushort, 1    ) \
     426       12042 :     FIELD( 4, &ext_key_share_ext_sz,              ushort, 1    ) \
     427       12042 :     FIELD( 5, &ext_key_share_group,               ushort, 1    ) \
     428       12042 :     FIELD( 6, &ext_key_share_sz,                  ushort, 1    ) \
     429       12042 :     FIELD( 7, &in->key_share.x25519[0],           uchar,  32UL )
     430       12042 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     431        6021 : # undef FIELDS
     432             : 
     433        6021 :   *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
     434        6021 :   return (long)( wire_laddr - (ulong)wire );
     435        6021 : }
     436             : 
     437             : long
     438             : fd_tls_decode_enc_ext( fd_tls_enc_ext_t * const out,
     439             :                        uchar const *      const wire,
     440        6018 :                        ulong                    wire_sz ) {
     441             : 
     442        6018 :   ulong wire_laddr = (ulong)wire;
     443             : 
     444       24072 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
     445       24066 :     ushort ext_type;
     446       24066 :     ushort ext_sz;
     447       24066 : #   define FIELDS( FIELD )             \
     448       48132 :       FIELD( 0, &ext_type, ushort, 1 ) \
     449       48132 :       FIELD( 1, &ext_sz,   ushort, 1 )
     450       48132 :       FD_TLS_DECODE_STATIC_BATCH( FIELDS )
     451       24066 : #   undef FIELDS
     452             : 
     453             :     /* Bounds check extension data
     454             :        (list_stop declared by DECODE_LIST macro) */
     455       24066 :     if( FD_UNLIKELY( wire_laddr + ext_sz > list_stop ) )
     456           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     457             : 
     458       24066 :     switch( ext_type ) {
     459        6015 :     case FD_TLS_EXT_ALPN: {
     460        6015 :       long res = fd_tls_decode_ext_alpn( &out->alpn, (uchar const *)wire_laddr, ext_sz );
     461        6015 :       if( FD_UNLIKELY( res<0L ) )
     462           0 :         return res;
     463        6015 :       if( FD_UNLIKELY( res!=(long)ext_sz ) )
     464           0 :         return -(long)FD_TLS_ALERT_DECODE_ERROR;
     465        6015 :       break;
     466        6015 :     }
     467        6015 :     case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
     468        6015 :       if( FD_UNLIKELY( ext_sz > FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
     469           0 :         return -(long)FD_TLS_ALERT_DECODE_ERROR;
     470        6015 :       out->quic_tp.buf   = (void *)wire_laddr;
     471        6015 :       out->quic_tp.bufsz = (ushort)ext_sz;
     472        6015 :       break;
     473        6018 :     case FD_TLS_EXT_SERVER_CERT_TYPE:
     474        6018 :       if( FD_UNLIKELY( (ext_sz>wire_sz) | (ext_sz!=1) ) )
     475           0 :         return -(long)FD_TLS_ALERT_DECODE_ERROR;
     476        6018 :       out->server_cert.cert_type = *(uchar const *)wire_laddr;
     477        6018 :       break;
     478        6018 :     case FD_TLS_EXT_CLIENT_CERT_TYPE:
     479        6018 :       if( FD_UNLIKELY( (ext_sz>wire_sz) | (ext_sz!=1) ) )
     480           0 :         return -(long)FD_TLS_ALERT_DECODE_ERROR;
     481        6018 :       out->client_cert.cert_type = *(uchar const *)wire_laddr;
     482        6018 :       break;
     483           0 :     default:
     484           0 :       break;  /* TODO should we error on unknown extensions? */
     485       24066 :     }
     486             : 
     487       24066 :     wire_laddr += ext_sz;
     488       24066 :     wire_sz    -= ext_sz;
     489       24066 :   }
     490        6018 :   FD_TLS_DECODE_LIST_END
     491             : 
     492             :   /* TODO Fail if trailing bytes detected? */
     493             : 
     494        6018 :   return (long)( wire_laddr - (ulong)wire );
     495        6018 : }
     496             : 
     497             : long
     498             : fd_tls_encode_cert_x509( uchar const * x509,
     499             :                          ulong         x509_sz,
     500             :                          uchar *       wire,
     501           0 :                          ulong         wire_sz ) {
     502             : 
     503           0 :   ulong wire_laddr = (ulong)wire;
     504             : 
     505             :   /* TLS Record Header */
     506           0 :   uchar msg_type = (uchar)FD_TLS_MSG_CERT;
     507             : 
     508             :   /* TLS Certificate Message header preceding X.509 data */
     509             : 
     510             :   /* All size prefixes known in advance */
     511           0 :   fd_tls_u24_t msg_sz       = fd_uint_to_tls_u24( (uint)( x509_sz + 9UL ) );
     512           0 :   fd_tls_u24_t cert_list_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 5UL ) );
     513           0 :   fd_tls_u24_t cert_sz      = fd_uint_to_tls_u24( (uint)( x509_sz       ) );
     514             : 
     515             :   /* zero sz certificate_request_context
     516             :      (Server certificate never has a request context) */
     517           0 :   uchar certificate_request_context_sz = (uchar)0;
     518             : 
     519             :   /* No certificate extensions */
     520           0 :   ushort ext_sz = (ushort)0;
     521             : 
     522           0 : # define FIELDS( FIELD )                                            \
     523           0 :     FIELD( 0, &msg_type,                         uchar,   1       ) \
     524           0 :     FIELD( 1, &msg_sz,                           tls_u24, 1       ) \
     525           0 :       FIELD( 2, &certificate_request_context_sz, uchar,   1       ) \
     526           0 :       FIELD( 3, &cert_list_sz,                   tls_u24, 1       ) \
     527           0 :         FIELD( 4, &cert_sz,                      tls_u24, 1       ) \
     528           0 :         FIELD( 5, x509,                          uchar,   x509_sz ) \
     529           0 :         FIELD( 6, &ext_sz,                       ushort,  1       )
     530           0 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     531           0 : # undef FIELDS
     532             : 
     533           0 :   return (long)( wire_laddr - (ulong)wire );
     534           0 : }
     535             : 
     536             : long
     537             : fd_tls_encode_enc_ext( fd_tls_enc_ext_t const * in,
     538             :                        uchar *                  wire,
     539        6018 :                        ulong                    wire_sz ) {
     540             : 
     541        6018 :   ulong wire_laddr = (ulong)wire;
     542             : 
     543             :   /* ALPN */
     544             : 
     545        6018 :   if( in->alpn.bufsz ) {
     546        6015 :     fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
     547        6015 :                                  .sz   = (ushort)( in->alpn.bufsz+2 ) };
     548        6015 :     FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr,  &ext_hdr  );
     549        6015 :     FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
     550        6015 :   }
     551             : 
     552             :   /* QUIC transport params */
     553             : 
     554        6018 :   if( in->quic_tp.buf ) {
     555        6015 :     ushort ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
     556        6015 :     ushort ext_sz   = (ushort)in->quic_tp.bufsz;
     557        6015 : #   define FIELDS( FIELD )             \
     558       12030 :       FIELD( 0, &ext_type, ushort, 1 ) \
     559       12030 :       FIELD( 1, &ext_sz,   ushort, 1 ) \
     560       12030 :         FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz )
     561       12030 :       FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     562        6015 : #   undef FIELDS
     563        6015 :   }
     564             : 
     565             :   /* Server certificate type */
     566             : 
     567        6018 :   if( in->server_cert.cert_type ) {
     568        6018 :     ushort ext_type  = FD_TLS_EXT_SERVER_CERT_TYPE;
     569        6018 :     ushort ext_sz    = 1;
     570        6018 :     uchar  cert_type = (uchar)in->server_cert.cert_type;
     571        6018 : #   define FIELDS( FIELD )                \
     572       12036 :       FIELD( 0, &ext_type,    ushort, 1 ) \
     573       12036 :       FIELD( 1, &ext_sz,      ushort, 1 ) \
     574       12036 :         FIELD( 2, &cert_type, uchar,  1 )
     575       12036 :       FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     576        6018 : #   undef FIELDS
     577        6018 :   }
     578             : 
     579             :   /* Client certificate type */
     580             : 
     581        6018 :   if( in->client_cert.cert_type ) {
     582        6018 :     ushort ext_type  = FD_TLS_EXT_CLIENT_CERT_TYPE;
     583        6018 :     ushort ext_sz    = 1;
     584        6018 :     uchar  cert_type = (uchar)in->client_cert.cert_type;
     585        6018 : #   define FIELDS( FIELD )                \
     586       12036 :       FIELD( 0, &ext_type,    ushort, 1 ) \
     587       12036 :       FIELD( 1, &ext_sz,      ushort, 1 ) \
     588       12036 :         FIELD( 2, &cert_type, uchar,  1 )
     589       12036 :       FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     590        6018 : #   undef FIELDS
     591        6018 :   }
     592             : 
     593        6018 :   return (long)( wire_laddr - (ulong)wire );
     594        6018 : }
     595             : 
     596             : long
     597             : fd_tls_encode_raw_public_key( uchar const * key,
     598             :                               uchar *       wire,
     599        6018 :                               ulong         wire_sz ) {
     600             : 
     601        6018 :   ulong wire_laddr = (ulong)wire;
     602             : 
     603             :   /* TLS Record Header */
     604        6018 :   uchar msg_type = (uchar)FD_TLS_MSG_CERT;
     605             : 
     606             :   /* TLS Certificate Message header preceding X.509 data */
     607             : 
     608             :   /* All size prefixes known in advance */
     609        6018 :   uint         rpk_sz       = sizeof(fd_asn1_ed25519_pubkey_prefix)+32UL;
     610        6018 :   fd_tls_u24_t msg_sz       = fd_uint_to_tls_u24( (uint)( rpk_sz + 9UL ) );
     611        6018 :   fd_tls_u24_t cert_list_sz = fd_uint_to_tls_u24( (uint)( rpk_sz + 5UL ) );
     612        6018 :   fd_tls_u24_t cert_sz      = fd_uint_to_tls_u24( (uint)( rpk_sz       ) );
     613             : 
     614             :   /* zero sz certificate_request_context
     615             :      (Server certificate never has a request context) */
     616        6018 :   uchar certificate_request_context_sz = (uchar)0;
     617             : 
     618             :   /* No certificate extensions */
     619        6018 :   ushort ext_sz = (ushort)0;
     620             : 
     621        6018 : # define FIELDS( FIELD )                                            \
     622       12036 :     FIELD( 0, &msg_type,                         uchar,   1       ) \
     623       12036 :     FIELD( 1, &msg_sz,                           tls_u24, 1       ) \
     624       12036 :       FIELD( 2, &certificate_request_context_sz, uchar,   1       ) \
     625       12036 :       FIELD( 3, &cert_list_sz,                   tls_u24, 1       ) \
     626       12036 :         FIELD( 4, &cert_sz,                      tls_u24, 1       ) \
     627       12036 :         FIELD( 5, fd_asn1_ed25519_pubkey_prefix, uchar,   sizeof(fd_asn1_ed25519_pubkey_prefix) ) \
     628       12036 :         FIELD( 6, key,                           uchar,   32UL    ) \
     629       12036 :         FIELD( 7, &ext_sz,                       ushort,  1       )
     630       12036 :     FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     631        6018 : # undef FIELDS
     632             : 
     633        6018 :   return (long)( wire_laddr - (ulong)wire );
     634        6018 : }
     635             : 
     636             : long
     637             : fd_tls_decode_cert_verify( fd_tls_cert_verify_t * out,
     638             :                            uchar const *          wire,
     639        6018 :                            ulong                  wire_sz ) {
     640             : 
     641        6018 :   ulong wire_laddr = (ulong)wire;
     642             : 
     643        6018 :   ushort sig_sz;
     644        6018 : # define FIELDS( FIELD ) \
     645       12036 :     FIELD( 0, &out->sig_alg, ushort,  1 ) \
     646       12036 :     FIELD( 1, &sig_sz,       ushort,  1 ) \
     647       12036 :     FIELD( 2,  out->sig,     uchar,  64 )
     648       12036 :   FD_TLS_DECODE_STATIC_BATCH( FIELDS )
     649        6018 : # undef FIELDS
     650             : 
     651        6018 :   if( FD_UNLIKELY( ( out->sig_alg != FD_TLS_SIGNATURE_ED25519 )
     652        6018 :                  | (      sig_sz  != 0x40UL                   ) ) )
     653           0 :     return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
     654             : 
     655        6018 :   return (long)( wire_laddr - (ulong)wire );
     656        6018 : }
     657             : 
     658             : long
     659             : fd_tls_encode_cert_verify( fd_tls_cert_verify_t const * in,
     660             :                            uchar *                      wire,
     661        6018 :                            ulong                        wire_sz ) {
     662             : 
     663        6018 :   ulong wire_laddr = (ulong)wire;
     664             : 
     665        6018 :   ushort sig_sz = 0x40;
     666        6018 : # define FIELDS( FIELD ) \
     667       12036 :     FIELD( 0, &in->sig_alg, ushort,  1 ) \
     668       12036 :     FIELD( 1, &sig_sz,      ushort,  1 ) \
     669       12036 :     FIELD( 2,  in->sig,     uchar,  64 )
     670       12036 :   FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
     671        6018 : # undef FIELDS
     672             : 
     673        6018 :   return (long)( wire_laddr - (ulong)wire );
     674        6018 : }
     675             : 
     676             : long
     677             : fd_tls_decode_ext_server_name( fd_tls_ext_server_name_t * out,
     678             :                                uchar const *              wire,
     679           3 :                                ulong                      wire_sz ) {
     680             : 
     681           3 :   ulong wire_laddr = (ulong)wire;
     682             : 
     683             :   /* TLS v1.3 server name lists practically always have one element. */
     684             : 
     685          12 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
     686             :     /* Read type and length */
     687           3 :     uchar  name_type;
     688           3 :     ushort name_sz;
     689           3 : #   define FIELDS( FIELD )              \
     690           6 :       FIELD( 0, &name_type, uchar,  1 ) \
     691           6 :       FIELD( 1, &name_sz,   ushort, 1 )
     692           6 :       FD_TLS_DECODE_STATIC_BATCH( FIELDS )
     693           3 : #   undef FIELDS
     694             : 
     695             :     /* Bounds check name */
     696           3 :     if( FD_UNLIKELY( wire_laddr + name_sz > list_stop ) )
     697           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     698             : 
     699             :     /* Decode name on first use */
     700           3 :     if( ( ( name_type == FD_TLS_SERVER_NAME_TYPE_DNS )
     701           3 :         & ( name_sz < 254                            )
     702           3 :         & ( out->host_name_len == 0                  ) ) ) {
     703           3 :       out->host_name_len = (uchar)name_sz;
     704           3 :       memcpy( out->host_name, (uchar const *)wire_laddr, name_sz );
     705           3 :       out->host_name[ name_sz ] = '\0';
     706           3 :     }
     707             : 
     708             :     /* Seek to next name */
     709           3 :     wire_laddr += name_sz;
     710           3 :     wire_sz    -= name_sz;
     711           3 :   }
     712           3 :   FD_TLS_DECODE_LIST_END
     713             : 
     714           3 :   return (long)( wire_laddr - (ulong)wire );
     715           3 : }
     716             : 
     717             : long
     718             : fd_tls_decode_ext_supported_groups( fd_tls_ext_supported_groups_t * out,
     719             :                                     uchar const *                   wire,
     720        6024 :                                     ulong                           wire_sz ) {
     721             : 
     722        6024 :   ulong wire_laddr = (ulong)wire;
     723             : 
     724       24096 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
     725        6030 :     ushort group;
     726        6030 :     FD_TLS_DECODE_FIELD( &group, ushort );
     727        6030 :     switch( group ) {
     728        6024 :     case FD_TLS_GROUP_X25519:
     729        6024 :       out->x25519 = 1;
     730        6024 :       break;
     731           6 :     default:
     732             :       /* Ignore unsupported groups ... */
     733           6 :       break;
     734        6030 :     }
     735        6030 :   }
     736        6024 :   FD_TLS_DECODE_LIST_END
     737             : 
     738        6024 :   return (long)( wire_laddr - (ulong)wire );
     739        6024 : }
     740             : 
     741             : long
     742             : fd_tls_decode_ext_supported_versions( fd_tls_ext_supported_versions_t * out,
     743             :                                       uchar const *                     wire,
     744        6024 :                                       ulong                             wire_sz ) {
     745             : 
     746        6024 :   ulong wire_laddr = (ulong)wire;
     747             : 
     748       24096 :   FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(ushort) ) {
     749        6024 :     ushort group;
     750        6024 :     FD_TLS_DECODE_FIELD( &group, ushort );
     751        6024 :     switch( group ) {
     752        6024 :     case FD_TLS_VERSION_TLS13:
     753        6024 :       out->tls13 = 1;
     754        6024 :       break;
     755           0 :     default:
     756             :       /* Ignore unsupported TLS versions ... */
     757           0 :       break;
     758        6024 :     }
     759        6024 :   }
     760        6024 :   FD_TLS_DECODE_LIST_END
     761             : 
     762        6024 :   return (long)( wire_laddr - (ulong)wire );
     763        6024 : }
     764             : 
     765             : long
     766             : fd_tls_decode_ext_signature_algorithms( fd_tls_ext_signature_algorithms_t * out,
     767             :                                         uchar const *                       wire,
     768        6024 :                                         ulong                               wire_sz ) {
     769             : 
     770        6024 :   ulong wire_laddr = (ulong)wire;
     771             : 
     772       24096 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
     773        6048 :     ushort group;
     774        6048 :     FD_TLS_DECODE_FIELD( &group, ushort );
     775        6048 :     switch( group ) {
     776        6024 :     case FD_TLS_SIGNATURE_ED25519:
     777        6024 :       out->ed25519 = 1;
     778        6024 :       break;
     779          24 :     default:
     780             :       /* Ignore unsupported signature algorithms ... */
     781          24 :       break;
     782        6048 :     }
     783        6048 :   }
     784        6024 :   FD_TLS_DECODE_LIST_END
     785             : 
     786        6024 :   return (long)( wire_laddr - (ulong)wire );
     787        6024 : }
     788             : 
     789             : long
     790             : fd_tls_decode_key_share( fd_tls_key_share_t * out,
     791             :                          uchar const *        wire,
     792       12045 :                          ulong                wire_sz ) {
     793             : 
     794       12045 :   ulong wire_laddr = (ulong)wire;
     795             : 
     796             :   /* Read type and length */
     797       12045 :   ushort group;
     798       12045 :   ushort kex_data_sz;
     799       12045 : # define FIELDS( FIELD )                \
     800       24090 :     FIELD( 0, &group,       ushort, 1 ) \
     801       24090 :     FIELD( 1, &kex_data_sz, ushort, 1 )
     802       24090 :     FD_TLS_DECODE_STATIC_BATCH( FIELDS )
     803       12045 : # undef FIELDS
     804             : 
     805             :   /* Bounds check */
     806       12045 :   if( FD_UNLIKELY( kex_data_sz > wire_sz ) )
     807           0 :     return -(long)FD_TLS_ALERT_DECODE_ERROR;
     808             : 
     809       12045 :   switch( group ) {
     810       12045 :   case FD_TLS_GROUP_X25519:
     811       12045 :     if( FD_UNLIKELY( kex_data_sz != 32UL ) )
     812           0 :       return -(long)FD_TLS_ALERT_DECODE_ERROR;
     813       12045 :     out->has_x25519 = 1;
     814       12045 :     memcpy( out->x25519, (uchar const *)wire_laddr, 32UL );
     815       12045 :     break;
     816           0 :   default:
     817             :     /* Ignore unsupported key share groups ... */
     818           0 :     break;
     819       12045 :   }
     820             : 
     821             :   /* Seek to next group */
     822       12045 :   wire_laddr += kex_data_sz;
     823       12045 :   wire_sz    -= kex_data_sz;
     824             : 
     825       12045 :   return (long)( wire_laddr - (ulong)wire );
     826       12045 : }
     827             : 
     828             : long
     829             : fd_tls_decode_key_share_list( fd_tls_key_share_t * out,
     830             :                               uchar const *        wire,
     831        6024 :                               ulong                wire_sz ) {
     832             : 
     833        6024 :   ulong wire_laddr = (ulong)wire;
     834             : 
     835       24096 :   FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
     836        6024 :     FD_TLS_DECODE_SUB( fd_tls_decode_key_share, out );
     837        6024 :   }
     838        6024 :   FD_TLS_DECODE_LIST_END
     839             : 
     840        6024 :   return (long)( wire_laddr - (ulong)wire );
     841        6024 : }
     842             : 
     843             : long
     844             : fd_tls_decode_ext_cert_type_list( fd_tls_ext_cert_type_list_t * out,
     845             :                                   uchar const *                 wire,
     846       12042 :                                   ulong                         wire_sz ) {
     847             : 
     848       12042 :   ulong wire_laddr = (ulong)wire;
     849             : 
     850       12042 :   out->present = 1;
     851       48168 :   FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(uchar) ) {
     852       24078 :     uchar cert_type;
     853       24078 :     FD_TLS_DECODE_FIELD( &cert_type, uchar );  /* is this really a uchar? */
     854       24078 :     switch( cert_type ) {
     855       12036 :     case FD_TLS_CERTTYPE_X509:       out->x509 = 1;       break;
     856       12042 :     case FD_TLS_CERTTYPE_RAW_PUBKEY: out->raw_pubkey = 1; break;
     857           0 :     default:
     858             :       /* Ignore unsupported cert types ... */
     859           0 :       break;
     860       24078 :     }
     861       24078 :   }
     862       12042 :   FD_TLS_DECODE_LIST_END
     863             : 
     864       12042 :   return (long)( wire_laddr - (ulong)wire );
     865       12042 : }
     866             : 
     867             : long
     868             : fd_tls_encode_ext_cert_type_list( fd_tls_ext_cert_type_list_t in,
     869             :                                   uchar const *               wire,
     870           0 :                                   ulong                       wire_sz ) {
     871             : 
     872           0 :   ulong wire_laddr = (ulong)wire;
     873             : 
     874             :   /* Encode list size */
     875           0 :   uchar cnt = (uchar)fd_uchar_popcnt( in.uc );
     876           0 :   FD_TLS_ENCODE_FIELD( &cnt, uchar );
     877             : 
     878             :   /* Encode list */
     879           0 :   uchar * fields = FD_TLS_SKIP_FIELDS( uchar, cnt );
     880           0 :   if( in.x509       ) *fields++ = FD_TLS_CERTTYPE_X509;
     881           0 :   if( in.raw_pubkey ) *fields++ = FD_TLS_CERTTYPE_RAW_PUBKEY;
     882             : 
     883           0 :   return (long)( wire_laddr - (ulong)wire );
     884           0 : }
     885             : 
     886             : long
     887             : fd_tls_decode_ext_cert_type( fd_tls_ext_cert_type_t * out,
     888             :                               uchar const *           wire,
     889           0 :                               ulong                   wire_sz ) {
     890           0 :   ulong wire_laddr = (ulong)wire;
     891           0 :   FD_TLS_DECODE_FIELD( &out->cert_type, uchar );
     892           0 :   return (long)( wire_laddr - (ulong)wire );
     893           0 : }
     894             : 
     895             : long
     896             : fd_tls_encode_ext_cert_type( fd_tls_ext_cert_type_t in,
     897             :                              uchar const *          wire,
     898           0 :                              ulong                  wire_sz ) {
     899           0 :   ulong wire_laddr = (ulong)wire;
     900           0 :   FD_TLS_ENCODE_FIELD( &in.cert_type, uchar );
     901           0 :   return (long)( wire_laddr - (ulong)wire );
     902           0 : }
     903             : 
     904             : long
     905             : fd_tls_decode_ext_opaque( fd_tls_ext_opaque_t * const out,
     906             :                           uchar const *         const wire,
     907       18057 :                           ulong                       wire_sz ) {
     908       18057 :   out->buf   = wire;
     909       18057 :   out->bufsz = wire_sz;
     910       18057 :   return (long)wire_sz;
     911       18057 : }
     912             : 
     913             : long
     914             : fd_tls_decode_ext_alpn( fd_tls_ext_alpn_t * const out,
     915             :                         uchar const *       const wire,
     916       12036 :                         ulong                     wire_sz ) {
     917       12036 :   ulong wire_laddr = (ulong)wire;
     918       12036 :   ushort alpn_sz;
     919       12036 :   FD_TLS_DECODE_FIELD( &alpn_sz, ushort );
     920       12036 :   if( FD_UNLIKELY( (ulong)alpn_sz != wire_sz ) )
     921           0 :     return -(long)FD_TLS_ALERT_DECODE_ERROR;
     922       12036 :   return 2L + (long)fd_tls_decode_ext_opaque( out, (uchar const *)wire_laddr, wire_sz );
     923       12036 : }
     924             : 
     925             : long
     926             : fd_tls_encode_ext_alpn( fd_tls_ext_alpn_t const * in,
     927             :                         uchar *                   wire,
     928       12030 :                         ulong                     wire_sz ) {
     929       12030 :   ulong sz = 2UL + in->bufsz;
     930       12030 :   if( FD_UNLIKELY( sz>wire_sz ) )
     931           0 :     return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
     932       12030 :   wire[0] = (uchar)( (in->bufsz >> 8)&0xFF );
     933       12030 :   wire[1] = (uchar)(  in->bufsz      &0xFF );
     934       12030 :   fd_memcpy( wire+2UL, in->buf, in->bufsz );
     935       12030 :   return (long)sz;
     936       12030 : }
     937             : 
     938             : /* fd_tls_client_handle_x509 extracts the Ed25519 subject public key
     939             :    from the certificate.  Does not validate the signature found on the
     940             :    certificate (might be self-signed).  [cert,cert+cert_sz) points to
     941             :    an ASN.1 DER serialization of the certificate.  On success, copies
     942             :    public key bits to out_pubkey and returns 0U.  On failure, returns
     943             :    positive TLS alert error code. */
     944             : 
     945             : static uint
     946             : fd_tls_client_handle_x509( uchar const *  const cert,
     947             :                            ulong          const cert_sz,
     948           0 :                            uchar const ** const out_pubkey ) {
     949           0 :   uchar const * pubkey = fd_x509_mock_pubkey( cert, cert_sz );
     950           0 :   if( FD_UNLIKELY( !pubkey ) )
     951           0 :     return FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE;
     952           0 :   *out_pubkey = pubkey;
     953           0 :   return 0U;
     954           0 : }
     955             : 
     956             : static long
     957             : fd_tls_extract_cert_pubkey_( fd_tls_extract_cert_pubkey_res_t * res,
     958             :                              uchar const * cert_chain,
     959             :                              ulong         cert_chain_sz,
     960        6018 :                              uint          cert_type ) {
     961             : 
     962        6018 :   fd_memset( res, 0, sizeof(fd_tls_extract_cert_pubkey_res_t) );
     963             : 
     964        6018 :   ulong wire_laddr = (ulong)cert_chain;
     965        6018 :   ulong wire_sz    = cert_chain_sz;
     966             : 
     967             :   /* Skip 'opaque certificate_request_context<0..2^8-1>' */
     968        6018 :   uchar const * opaque_sz = FD_TLS_SKIP_FIELD( uchar );
     969        6018 :   uchar const * opaque    = FD_TLS_SKIP_FIELDS( uchar, *opaque_sz );
     970           0 :   (void)opaque;
     971             : 
     972             :   /* Get first entry of certificate chain
     973             :      CertificateEntry certificate_list<0..2^24-1> */
     974        6018 :   fd_tls_u24_t const * cert_list_sz_be = FD_TLS_SKIP_FIELD( fd_tls_u24_t );
     975           0 :   fd_tls_u24_t         cert_list_sz_   = fd_tls_u24_bswap( *cert_list_sz_be );
     976        6018 :   uint                 cert_list_sz    = fd_tls_u24_to_uint( cert_list_sz_ );
     977        6018 :   if( FD_UNLIKELY( cert_list_sz==0U ) ) {
     978           0 :     res->alert  = FD_TLS_ALERT_BAD_CERTIFICATE;
     979           0 :     res->reason = FD_TLS_REASON_CERT_CHAIN_EMPTY;
     980           0 :     return -1L;
     981           0 :   }
     982             : 
     983             :   /* Get certificate size */
     984        6018 :   fd_tls_u24_t const * cert_sz_be = FD_TLS_SKIP_FIELD( fd_tls_u24_t );
     985           0 :   fd_tls_u24_t         cert_sz_   = fd_tls_u24_bswap( *cert_sz_be );
     986        6018 :   uint                 cert_sz    = fd_tls_u24_to_uint( cert_sz_ );
     987        6018 :   if( FD_UNLIKELY( cert_sz>wire_sz ) ) {
     988           0 :     res->alert = FD_TLS_ALERT_DECODE_ERROR;
     989           0 :     res->reason = FD_TLS_REASON_CERT_PARSE;
     990           0 :     return -1L;
     991           0 :   }
     992             : 
     993        6018 :   void * cert = (void *)wire_laddr;
     994             : 
     995        6018 :   switch( cert_type ) {
     996             : 
     997           0 :   case FD_TLS_CERTTYPE_X509: {
     998             : 
     999             :     /* DER-encoded X.509 certificate */
    1000             : 
    1001           0 :     uint x509_alert = fd_tls_client_handle_x509( cert, cert_sz, &res->pubkey );
    1002           0 :     if( FD_UNLIKELY( x509_alert!=0U ) ) {
    1003           0 :       res->pubkey = NULL;
    1004           0 :       res->alert  = x509_alert;
    1005           0 :       res->reason = FD_TLS_REASON_X509_PARSE;
    1006           0 :       return -1L;
    1007           0 :     }
    1008             : 
    1009           0 :     return 0L;
    1010           0 :   }
    1011             : 
    1012        6018 :   case FD_TLS_CERTTYPE_RAW_PUBKEY: {
    1013             : 
    1014             :     /* Interpret certificate entry as raw public key (RFC 7250)
    1015             :        'opaque ASN1_subjectPublicKeyInfo<1..2^24-1>' */
    1016             : 
    1017        6018 :     res->pubkey = fd_ed25519_public_key_from_asn1( cert, cert_sz );
    1018        6018 :     if( FD_UNLIKELY( !res->pubkey ) ) {
    1019           0 :       res->reason = FD_TLS_REASON_SPKI_PARSE;
    1020           0 :       res->alert  = FD_TLS_ALERT_BAD_CERTIFICATE;
    1021           0 :       return -1L;
    1022           0 :     }
    1023             : 
    1024        6018 :     return 0L;
    1025        6018 :   }
    1026             : 
    1027           0 :   default:
    1028           0 :     __builtin_unreachable();
    1029             : 
    1030        6018 :   } /* end switch */
    1031        6018 : }
    1032             : 
    1033             : fd_tls_extract_cert_pubkey_res_t
    1034             : fd_tls_extract_cert_pubkey( uchar const * cert_chain,
    1035             :                             ulong         cert_chain_sz,
    1036        6018 :                             uint          cert_type ) {
    1037        6018 :   fd_tls_extract_cert_pubkey_res_t res;
    1038        6018 :   long ret = fd_tls_extract_cert_pubkey_( &res, cert_chain, cert_chain_sz, cert_type );
    1039        6018 :   (void)ret;
    1040        6018 :   return res;
    1041        6018 : }

Generated by: LCOV version 1.14