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 : #include "../../ballet/x509/fd_x509.h" 7 : 8 : /* Peer key types, same values as FD_X509_KEY_{...} */ 9 : 10 579 : #define FD_TLS_KEY_ED25519 ((uchar)0) 11 18 : #define FD_TLS_KEY_ECDSA_P256 ((uchar)1) 12 : #define FD_TLS_KEY_ECDSA_P384 ((uchar)2) 13 90 : #define FD_TLS_KEY_RSA ((uchar)3) 14 : 15 : /* Base ***************************************************************/ 16 : 17 : /* fd_tls_estate_base_t is the shared header of the 18 : fd_tls_estate_{srv,cli} objects. */ 19 : 20 : struct fd_tls_estate_base { 21 : uchar state; 22 : uchar server : 1; /* 1 if server, 0 if client */ 23 : ushort reason; /* FD_TLS_REASON_{...} */ 24 : 25 : /* Sadly required for SSLKEYLOGFILE */ 26 : uchar client_random[ 32 ]; 27 : }; 28 : 29 : typedef struct fd_tls_estate_base fd_tls_estate_base_t; 30 : 31 : /* Transcript-Hash (RFC 8446 Section 4.4.1) 32 : The transcript is a running hash over all handshake messages. The 33 : hash state depends on the current handshake progression. The hash 34 : order is as follows: 35 : 36 : client ClientHello always 37 : server ServerHello always 38 : server EncryptedExtensions always 39 : server CertificateRequest optional 40 : server Certificate always 41 : server CertificateVerify always 42 : server Finished always 43 : client Certificate optional 44 : client CertificateVerify optional 45 : client Finished always */ 46 : 47 : struct fd_tls_transcript { 48 : uchar buf[ 64 ]; /* Pending SHA block */ 49 : uint sha[ 8 ]; /* Current internal SHA state */ 50 : uint len; /* Number of bytes so far compressed into SHA state 51 : plus number of bytes in pending in buf */ 52 : }; 53 : 54 : typedef struct fd_tls_transcript fd_tls_transcript_t; 55 : 56 : /* Note: An experimental memory optimization that is not implemented 57 : here is alignment of SHA state. It might be possible to craft a 58 : transcript preimage that is aligned to SHA block size. This allows 59 : omitting the SHA block buffer, saving 64 bytes per transcript (and 60 : thus per in-flight handshake). */ 61 : 62 : FD_PROTOTYPES_BEGIN 63 : 64 : static inline void 65 : fd_tls_transcript_store( fd_tls_transcript_t * script, 66 8247 : fd_sha256_t const * sha ) { 67 8247 : memcpy( script->buf, sha->buf, 64UL ); 68 8247 : memcpy( script->sha, sha->state, 32UL ); 69 8247 : script->len = (uint)( sha->bit_cnt / 8UL ); 70 8247 : } 71 : 72 : static inline void 73 : fd_tls_transcript_load( fd_tls_transcript_t const * script, 74 8166 : fd_sha256_t * sha ) { 75 8166 : memcpy( sha->buf, script->buf, 64UL ); 76 8166 : memcpy( sha->state, script->sha, 32UL ); 77 8166 : sha->bit_cnt = (ulong)( script->len ) * 8UL; 78 8166 : sha->buf_used = (uint)( script->len % 64U ); 79 8166 : } 80 : 81 : FD_PROTOTYPES_END 82 : 83 : /* Server *************************************************************/ 84 : 85 : /* fd_tls_estate_srv contains compressed TLS server handshake state 86 : while waiting for the client to send a message. estate is optimized 87 : for small memory use for incoming conns (sizeof(fd_tls_estate_srv_t) 88 : bytes per handshake). 89 : 90 : *** Security ******************************************************** 91 : 92 : fd_tls servers must handle handshake requests from untrusted clients, 93 : and thus require hardening. A typical lifetime of an estate object 94 : is in the order of ~3 seconds (conn timeout). This requires some 95 : care to avoid memory exhaustion attacks. 96 : 97 : For example, an off-the-shelf TLS implementation uses a handshake 98 : state size of about 10 KB (via multiple allocations on global heap). 99 : Assuming 3 second conn timeout, and flood rate of 1 million 100 : ClientHello msg/s, 101 : an attacker could indefinitely occupy ~30 GB of raw heap allocations! 102 : More concerning -- Global heap pressure will cause latent allocation 103 : failures in unrelated code, which might escalate to OOM kills. 104 : 105 : For estate_srv, the corresponding memory is three million times 106 : sizeof(fd_tls_estate_srv_t), plus transport overhead. The memory of 107 : estate_srv objects is provided by the transport 108 : layer (e.g. QUIC or TLS record layer). Each estate_srv object has 109 : static footprint. This allows dense packing in custom memory arenas. 110 : 111 : This allows for robust handling of packet floods: Even in the event 112 : the estate_srv arena is exhausted, the impact is limited to temporary 113 : inability to accept new connections. Processing of established conns 114 : and unrelated code is unaffected. 115 : 116 : *** State Machine *************************************************** 117 : 118 : Each estate_srv object corresponds to an instance of a server-side 119 : TLS handshake state machine. It is first instantiated when the 120 : client sent its ClientHello, the first message of a TLS handshake. 121 : 122 : After processing ClientHello and sending through server Finished, 123 : the server waits in one of these states: 124 : 125 : FD_TLS_HS_WAIT_CERT: Receive the requested client certificate. 126 : FD_TLS_HS_WAIT_CV: Verify the client's CertificateVerify. 127 : FD_TLS_HS_WAIT_FINISHED: Verify client Finished. 128 : 129 : Without client authentication, the server goes directly to 130 : WAIT_FINISHED. 131 : 132 : State data contains: 133 : 134 : - The transcript hash state, which commits both sides to the entire 135 : sequence of handshake messages (such that they cannot be tampered 136 : with). 137 : 138 : - The client handshake secret, which is used to derive the "client 139 : Finished" verify data. 140 : 141 : - The client authentication flags and Ed25519 public key extracted 142 : from the client certificate when client authentication is enabled. */ 143 : 144 : struct fd_tls_estate_srv { 145 : /* TLS base (hs) handles are deliberately placed at the start. 146 : Allows for type punning between fd_quic_tls_hs_t and 147 : fd_tls_estate_{srv,cli}_t. DO NOT MOVE. 148 : Type of handshake object depends on is_server. */ 149 : fd_tls_estate_base_t base; 150 : 151 : uchar client_cert : 1; /* 0: no client auth 1: client cert */ 152 : uchar hello_retry : 1; 153 : 154 : fd_tls_transcript_t transcript; 155 : uchar client_hs_secret[32]; 156 : uchar client_pubkey[32]; 157 : }; 158 : 159 : typedef struct fd_tls_estate_srv fd_tls_estate_srv_t; 160 : 161 : 162 : /* Note: When requesting a cert, the server should consider stopping 163 : after CertificateVerify to save compute resources (at the expense of 164 : more memory required to save state carried over from 165 : CertificateRequest...server Finished). */ 166 : 167 : FD_PROTOTYPES_BEGIN 168 : 169 : /* fd_tls_estate_srv_new initializes an estate object for an incoming 170 : conn. mem points to a memory region suitable for storing an 171 : fd_tls_estate_srv_t. Returns cast of mem, which will be initialized 172 : to state FD_TLS_HS_START. */ 173 : 174 : fd_tls_estate_srv_t * 175 : fd_tls_estate_srv_new( void * mem ); 176 : 177 : static inline void * 178 6162 : fd_tls_estate_srv_delete( fd_tls_estate_srv_t * estate ) { 179 6162 : if( FD_LIKELY( estate ) ) fd_memzero_explicit( estate, sizeof(fd_tls_estate_srv_t) ); 180 6162 : return (void *)estate; 181 6162 : } 182 : 183 : FD_PROTOTYPES_END 184 : 185 : 186 : /* Client *************************************************************/ 187 : 188 : /* fd_tls_estate_cli contains TLS client handshake state while waiting 189 : for the server to send a message. 190 : 191 : TLS client side handshake state is considerably more complex than 192 : the server-side state. Thus, estate_cli memory requirements are 193 : larger than for estate_srv. 194 : 195 : However, clients are not vulnerable to handshake packet floods: 196 : - The packet count per handshake is limited 197 : - Peers cannot initiate connections to clients (clients will simply 198 : drop unsolicited packets) 199 : 200 : Thus, estate_cli is not optimized for memory use. */ 201 : 202 : struct fd_tls_estate_cli { 203 : /* TLS handshake handles are deliberately placed at the start. 204 : Allows for type punning between fd_quic_tls_hs_t and 205 : fd_tls_estate_{srv,cli}_t. DO NOT MOVE. 206 : Type of handshake object depends on is_server. */ 207 : fd_tls_estate_base_t base; 208 : 209 : uchar server_pubkey[ FD_X509_PUBKEY_MAX ]; /* leaf cert subjectPublicKey */ 210 : ulong server_pubkey_len; 211 : uchar server_key_type; /* FD_TLS_KEY_{...} */ 212 : uchar server_hs_secret[ 32 ]; 213 : uchar client_hs_secret[ 32 ]; 214 : uchar master_secret [ 32 ]; 215 : 216 : uchar client_cert : 1; /* 0=anon 1=client auth */ 217 : uchar client_cert_empty : 1; /* no compatible CertificateVerify scheme */ 218 : uchar server_pubkey_pin : 1; /* if 1, require cert to match server_pubkey */ 219 : uchar alpn_negotiated : 1; /* if 1, server selected the offered ALPN */ 220 : uchar cert_verify_err; /* FD_X509_VERIFY_{...} if ca_store is set, else 0 */ 221 : 222 : /* TCP middlebox compat (RFC 8446 Section 4.1.2) */ 223 : uchar session_id[ 32 ]; 224 : uchar session_id_sz; 225 : 226 : fd_sha256_t transcript; 227 : }; 228 : 229 : typedef struct fd_tls_estate_cli fd_tls_estate_cli_t; 230 : 231 : FD_PROTOTYPES_BEGIN 232 : 233 : fd_tls_estate_cli_t * 234 : fd_tls_estate_cli_new( void * mem ); 235 : 236 : /* fd_tls_estate_cli_delete destroys the handshake state. Securely 237 : erases the object, which holds the handshake secrets, the master 238 : secret, and the transcript hash state. See 239 : fd_tls_estate_srv_delete. */ 240 : 241 : static inline void * 242 6300 : fd_tls_estate_cli_delete( fd_tls_estate_cli_t * estate ) { 243 6300 : if( FD_LIKELY( estate ) ) fd_memzero_explicit( estate, sizeof(fd_tls_estate_cli_t) ); 244 6300 : return (void *)estate; 245 6300 : } 246 : 247 : FD_PROTOTYPES_END 248 : 249 : 250 : /* Common *************************************************************/ 251 : 252 : union fd_tls_estate { 253 : fd_tls_estate_base_t base; 254 : fd_tls_estate_srv_t srv; 255 : fd_tls_estate_cli_t cli; 256 : }; 257 : 258 : typedef union fd_tls_estate fd_tls_estate_t; 259 : 260 : #endif /* HEADER_fd_src_waltz_tls_fd_tls_estate_h */