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 */