LCOV - code coverage report
Current view: top level - waltz/tls - fd_tls_estate.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 17 17 100.0 %
Date: 2024-11-13 11:58:15 Functions: 6 152 3.9 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_waltz_tls_fd_tls_estate_h
       2             : #define HEADER_fd_src_waltz_tls_fd_tls_estate_h
       3             : 
       4             : #include "../fd_waltz_base.h"
       5             : #include "../../ballet/sha256/fd_sha256.h"
       6             : 
       7             : /* Base ***************************************************************/
       8             : 
       9             : /* fd_tls_estate_base_t is the shared header of the
      10             :    fd_tls_estate_{srv,cli} objects. */
      11             : 
      12             : struct fd_tls_estate_base {
      13             :   uchar  state;
      14             :   uchar  server : 1;  /* 1 if server, 0 if client */
      15             :   ushort reason;      /* FD_TLS_REASON_{...} */
      16             : 
      17             :   /* Sadly required for SSLKEYLOGFILE */
      18             :   uchar client_random[ 32 ];
      19             : };
      20             : 
      21             : typedef struct fd_tls_estate_base fd_tls_estate_base_t;
      22             : 
      23             : /* The transcript is a running hash over all handshake messages.  The
      24             :    hash state depends on the current handshake progression.  The hash
      25             :    order is as follows:
      26             : 
      27             :      client   ClientHello           always
      28             :      server   ServerHello           always
      29             :      server   EncryptedExtensions   always
      30             :      server   CertificateRequest    optional
      31             :      server   Certificate           always
      32             :      server   CertificateVerify     always
      33             :      server   Finished              always
      34             :      client   Certificate           optional
      35             :      client   CertificateVerify     optional
      36             :      client   Finished              always */
      37             : 
      38             : struct fd_tls_transcript {
      39             :   uchar buf[ 64 ];  /* Pending SHA block */
      40             :   uint  sha[ 8 ];   /* Current internal SHA state */
      41             :   uint  len;        /* Number of bytes so far compressed into SHA state
      42             :                        plus number of bytes in pending in buf */
      43             : };
      44             : 
      45             : typedef struct fd_tls_transcript fd_tls_transcript_t;
      46             : 
      47             : /* Note:  An experimental memory optimization that is not implemented
      48             :    here is alignment of SHA state.  It might be possible to craft a
      49             :    transcript preimage that is aligned to SHA block size.  This allows
      50             :    omitting the SHA block buffer, saving 64 bytes per transcript (and
      51             :    thus per in-flight handshake). */
      52             : 
      53             : FD_PROTOTYPES_BEGIN
      54             : 
      55             : static inline void
      56             : fd_tls_transcript_store( fd_tls_transcript_t * script,
      57        6018 :                          fd_sha256_t const *   sha ) {
      58        6018 :   memcpy( script->buf, sha->buf,   64UL );
      59        6018 :   memcpy( script->sha, sha->state, 32UL );
      60        6018 :   script->len = (uint)( sha->bit_cnt / 8UL );
      61        6018 : }
      62             : 
      63             : static inline void
      64             : fd_tls_transcript_load( fd_tls_transcript_t const * script,
      65        6018 :                         fd_sha256_t *               sha ) {
      66        6018 :   memcpy( sha->buf,   script->buf, 64UL );
      67        6018 :   memcpy( sha->state, script->sha, 32UL );
      68        6018 :   sha->bit_cnt = (ulong)( script->len ) * 8UL;
      69        6018 :   sha->buf_used = (uint)( script->len % 64U );
      70        6018 : }
      71             : 
      72             : FD_PROTOTYPES_END
      73             : 
      74             : /* Server *************************************************************/
      75             : 
      76             : /* fd_tls_estate_srv contains compressed TLS server handshake state
      77             :    while waiting for the client to send a message.  estate is optimized
      78             :    for small memory use for incoming conns (128 byte per handshake).
      79             : 
      80             :    *** Security ********************************************************
      81             : 
      82             :    fd_tls servers must handle handshake requests from untrusted clients,
      83             :    and thus require hardening.  A typical lifetime of an estate object
      84             :    is in the order of ~3 seconds (conn timeout).  This requires some
      85             :    care to avoid memory exhaustion attacks.
      86             : 
      87             :    For example, a default OpenSSL app uses a handshake state size of
      88             :    about 10 KB (via multiple allocations on global heap).  Assuming 3
      89             :    second conn timeout, and flood rate of 1 million ClientHello msg/s,
      90             :    an attacker could indefinitely occupy ~30 GB of raw heap allocations!
      91             :    More concerning -- Global heap pressure will cause latent allocation
      92             :    failures in unrelated code, which might escalate to OOM kills.
      93             : 
      94             :    fd_tls_estate would only require 0.38 GB of memory for the same spam
      95             :    rate.  The memory of estate_srv objects is provided by the transport
      96             :    layer (e.g. QUIC or TLS record layer).  Each estate_srv object has
      97             :    static footprint.  This allows dense packing in custom memory arenas.
      98             : 
      99             :    This allows for robust handling of packet floods:  Even in the event
     100             :    the estate_srv arena is exhausted, the impact is limited to temporary
     101             :    inability to accept new connections.  Processing of established conns
     102             :    and unrelated code is unaffected.
     103             : 
     104             :    *** State Machine ***************************************************
     105             : 
     106             :    Each estate_srv object corresponds to an instance of a server-side
     107             :    TLS handshake state machine.  It is first instantiated when the
     108             :    client sent its ClientHello, the first message of a TLS handshake.
     109             : 
     110             :    Currently, only one external state exists:
     111             : 
     112             :      FD_TLS_HS_WAIT_FINISHED:  Processed ClientHello.
     113             : 
     114             :        At this point, the server has responded with all messages up to
     115             :        server Finished and is waiting for the client to respond with
     116             :        client Finished (and optionally, a certificate).
     117             : 
     118             :    State data contains:
     119             : 
     120             :    - The transcript hash state, which commits both sides to the entire
     121             :      sequence of handshake messages (such that they cannot be tampered
     122             :      with).
     123             : 
     124             :    - The client handshake secret, which is used to derive the "client
     125             :      Finished" verify data. */
     126             : 
     127             : struct fd_tls_estate_srv {
     128             :   fd_tls_estate_base_t base;
     129             : 
     130             :   uchar  server_cert_rpk : 1;  /* 0: X.509  1: raw public key */
     131             :   uchar  client_cert     : 1;  /* 0: no client auth  1: client cert */
     132             :   uchar  client_cert_rpk : 1;  /* 0: X.509  1: raw public key */
     133             : 
     134             :   fd_tls_transcript_t transcript;
     135             :   uchar               client_hs_secret[32];
     136             :   uchar               client_pubkey[32];
     137             : };
     138             : 
     139             : typedef struct fd_tls_estate_srv fd_tls_estate_srv_t;
     140             : 
     141             : 
     142             : /* Note:  When requesting a cert, the server should consider stopping
     143             :    after CertificateVerify to save compute resources (at the expense of
     144             :    more memory required to save state carried over from
     145             :    CertificateRequest...server Finished). */
     146             : 
     147             : FD_PROTOTYPES_BEGIN
     148             : 
     149             : /* fd_tls_estate_srv_new initializes an estate object for an incoming
     150             :    conn.  mem points to a memory region suitable for storing an
     151             :    fd_tls_estate_srv_t.  Returns cast of mem, which will be initialized
     152             :    to state FD_TLS_HS_START. */
     153             : 
     154             : fd_tls_estate_srv_t *
     155             : fd_tls_estate_srv_new( void * mem );
     156             : 
     157             : /* fd_tls_estate_srv_delete is currently a no-op. */
     158             : 
     159             : static inline void *
     160        6390 : fd_tls_estate_srv_delete( fd_tls_estate_srv_t * estate ) {
     161        6390 :   return (void *)estate;
     162        6390 : }
     163             : 
     164             : FD_PROTOTYPES_END
     165             : 
     166             : 
     167             : /* Client *************************************************************/
     168             : 
     169             : /* fd_tls_estate_cli contains TLS client handshake state while waiting
     170             :    for the server to send a message.
     171             : 
     172             :    TLS client side handshake state is considerably more complex than
     173             :    the server-side state.  Thus, estate_cli memory requirements are
     174             :    larger than for estate_srv.
     175             : 
     176             :    However, clients are not vulnerable to handshake packet floods:
     177             :    - The packet count per handshake is limited
     178             :    - Peers cannot initiate connections to clients (clients will simply
     179             :      drop unsolicited packets)
     180             : 
     181             :    Thus, estate_cli is not optimized for memory use. */
     182             : 
     183             : struct fd_tls_estate_cli {
     184             :   fd_tls_estate_base_t base;
     185             : 
     186             :   uchar server_pubkey   [ 32 ];
     187             :   uchar server_hs_secret[ 32 ];
     188             :   uchar client_hs_secret[ 32 ];
     189             :   uchar master_secret   [ 32 ];
     190             : 
     191             :   uchar client_cert        : 1;  /* 0=anon  1=client auth */
     192             :   uchar server_cert_rpk    : 1;
     193             :   uchar client_cert_nox509 : 1;
     194             :   uchar client_cert_rpk    : 1;
     195             :   uchar server_pubkey_pin  : 1;  /* if 1, require cert to match server_pubkey */
     196             : 
     197             :   fd_sha256_t transcript;
     198             : };
     199             : 
     200             : typedef struct fd_tls_estate_cli fd_tls_estate_cli_t;
     201             : 
     202             : FD_PROTOTYPES_BEGIN
     203             : 
     204             : fd_tls_estate_cli_t *
     205             : fd_tls_estate_cli_new( void * mem );
     206             : 
     207             : static inline void *
     208        6024 : fd_tls_estate_cli_delete( fd_tls_estate_cli_t * estate ) {
     209        6024 :   return (void *)estate;
     210        6024 : }
     211             : 
     212             : FD_PROTOTYPES_END
     213             : 
     214             : 
     215             : /* Common *************************************************************/
     216             : 
     217             : union fd_tls_estate {
     218             :   fd_tls_estate_base_t base;
     219             :   fd_tls_estate_srv_t  srv;
     220             :   fd_tls_estate_cli_t  cli;
     221             : };
     222             : 
     223             : typedef union fd_tls_estate fd_tls_estate_t;
     224             : 
     225             : #endif /* HEADER_fd_src_waltz_tls_fd_tls_estate_h */

Generated by: LCOV version 1.14