Line data Source code
1 : #ifndef HEADER_fd_src_waltz_tlsrec_fd_tlsrec_h 2 : #define HEADER_fd_src_waltz_tlsrec_fd_tlsrec_h 3 : 4 : /* fd_tlsrec.h provides the TLS 1.3 record layer, as used in TLS over 5 : TCP (RFC 8446). The record layer provides a mechanism to transfer 6 : handshake messages, alerts, and user data over a reliable stream. 7 : It also implements data authentication and encryption. 8 : 9 : This implementation provides the simplest way to secure individual 10 : TCP connections. It is not designed for high-performance use. It 11 : should not be used in servers that handle many concurrent connections 12 : due to high memory footprint. 13 : 14 : ### Middlebox Compatibility Mode 15 : 16 : fd_tlsrec ignores incoming compatibility messages as described in 17 : RFC 8446, Appendix D.4. It does not generate compatibility messages. 18 : 19 : ### Cryptography 20 : 21 : Each decryption step happens after a record has been fully received 22 : to allow for vectorized decryption. 23 : 24 : fd_tlsrec does not randomly pad records. It thus leaks the exact 25 : size of every outgoing record. Be careful when using with plaintexts 26 : where the size can be used as a side channel (see CVE-2019-4929). 27 : 28 : ### Integration 29 : 30 : fd_tlsrec offers a backend-agnostic non-blocking API. It is usually 31 : used with sockets (e.g. for HTTPS snapshot downloading). */ 32 : 33 : #include "fd_tlsrec_frag.h" 34 : #include "../tls/fd_tls.h" 35 : #include "../tls/fd_tls_estate.h" 36 : #include "../../ballet/aes/fd_aes_gcm.h" 37 : #include <stddef.h> 38 : 39 : /* fd_tlsrec_conn drives a TLS 1.3 connection over a reliable byte 40 : stream. The conn footprint is ~100 kB order of magnitude. */ 41 : 42 : struct fd_tlsrec_conn; 43 : typedef struct fd_tlsrec_conn fd_tlsrec_conn_t; 44 : 45 : /* FD_TLSREC_{SUCCESS,ERR_{...}} indicate error values returned by 46 : most API functions. */ 47 : 48 513517789 : #define FD_TLSREC_SUCCESS (0) 49 921 : #define FD_TLSREC_ERR_OOM (1) /* out of memory (forgot to poll?) */ 50 579 : #define FD_TLSREC_ERR_PROTO (2) /* protocol error */ 51 351 : #define FD_TLSREC_ERR_STATE (3) /* unexpected state */ 52 15 : #define FD_TLSREC_ERR_CRYPTO (4) /* crypto error */ 53 : 54 : /* FD_TLSREC_KEY_UPDATE_SEQ is the number of records encrypted under one 55 : application write key before fd_tlsrec_conn_tx rotates it with a 56 : KeyUpdate. RFC 8446 Section 5.5 bounds AES-GCM at ~2^24.5 full-size 57 : records per key. */ 58 : 59 6 : #define FD_TLSREC_KEY_UPDATE_SEQ (1UL<<24) 60 : 61 : /* fd_tlsrec_keys holds symmetric keys for a given encryption layer. */ 62 : 63 : struct __attribute__((aligned(FD_AES_GCM_ALIGN))) fd_tlsrec_keys { 64 : /* rebuilt on key change */ 65 : fd_aes_gcm_t read_gcm; 66 : fd_aes_gcm_t write_gcm; 67 : 68 : uchar read_secret [ 32 ]; 69 : uchar write_secret[ 32 ]; 70 : uchar read_key [ 16 ]; 71 : uchar read_iv [ 12 ]; 72 : uchar write_key [ 16 ]; 73 : uchar write_iv [ 12 ]; 74 : }; 75 : 76 : typedef struct fd_tlsrec_keys fd_tlsrec_keys_t; 77 : 78 : /* FD_TLSREC_HS_MSG_CAP is the max supported handshake message size. */ 79 : 80 32001 : #define FD_TLSREC_HS_MSG_CAP (0x10000UL) 81 : 82 : /* fd_tlsrec_hs_rbuf reassembles incoming handshakes messages one at a 83 : time. (private API) */ 84 : 85 : struct fd_tlsrec_hs_rbuf { 86 : uchar buf[ FD_TLSREC_HS_MSG_CAP ]; 87 : ulong sz; 88 : }; 89 : 90 : typedef struct fd_tlsrec_hs_rbuf fd_tlsrec_hs_rbuf_t; 91 : 92 : /* fd_tlsrec_buf_t defragments incoming TLS record data (private API) */ 93 : 94 : struct __attribute__((aligned(16UL))) fd_tlsrec_buf { 95 : uchar buf[ FD_TLSREC_CAP ]; 96 : ulong sz; 97 : }; 98 : 99 : typedef struct fd_tlsrec_buf fd_tlsrec_buf_t; 100 : 101 : struct fd_tlsrec_conn { 102 : fd_tls_t tls; /* TODO dedup across conns for better memory use */ 103 : fd_tls_secrets_fn_t secrets_fn; /* optional key-log observer */ 104 : 105 : fd_tlsrec_keys_t keys[2]; /* 0=handshake 1=app */ 106 : fd_tls_estate_t hs; 107 : 108 : fd_tlsrec_buf_t rec_buf; /* reassembly of TLS records */ 109 : fd_tlsrec_hs_rbuf_t hs_rbuf; /* reassembly of TLS handshake messages */ 110 : 111 : ulong read_seq; /* Incoming encrypted record counter */ 112 : ulong write_seq; /* Outgoing encrypted record counter */ 113 : 114 : uchar rx_closed; /* 1 if peer sent close_notify: no more plaintext is 115 : delivered (RFC 8446 Section 6.1), tx still works */ 116 : uchar key_update_pending; /* 1 if the peer requested a KeyUpdate that 117 : has not been answered yet */ 118 : uchar tx_level; /* FD_TLS_LEVEL_{INITIAL,HANDSHAKE,APPLICATION}: the 119 : encryption level an alert sent now would use */ 120 : uchar tx_closed; /* 1 once a fatal alert or close_notify went out: no 121 : more records are sent */ 122 : }; 123 : 124 : /* TLS v1.3 record content types */ 125 : 126 9 : #define FD_TLS_REC_CHANGE_CIPHER_SPEC ((uchar)20) 127 498 : #define FD_TLS_REC_ALERT ((uchar)21) 128 38214 : #define FD_TLS_REC_HANDSHAKE ((uchar)22) 129 156378 : #define FD_TLS_REC_APPLICATION_DATA ((uchar)23) 130 : 131 : /* fd_tlsrec_hdr_t is the TLS v1.3 record header. */ 132 : 133 : struct __attribute__((packed)) fd_tlsrec_hdr { 134 : uchar content_type; /* FD_TLS_REC_{...} */ 135 : ushort legacy_record_version; /* sent as 0x0303, ignored on receive */ 136 : ushort length; 137 : }; 138 : 139 : typedef struct fd_tlsrec_hdr fd_tlsrec_hdr_t; 140 : 141 : FD_PROTOTYPES_BEGIN 142 : 143 : FD_FN_PURE char const * 144 : fd_tlsrec_strerror( int err ); 145 : 146 : static inline void 147 127889612 : fd_tlsrec_hdr_bswap( fd_tlsrec_hdr_t * hdr ) { 148 127889612 : hdr->legacy_record_version = fd_ushort_bswap( hdr->legacy_record_version ); 149 127889612 : hdr->length = fd_ushort_bswap( hdr->length ); 150 127889612 : } 151 : 152 : /* fd_tlsrec_conn_init initializes a connection object. tls points to 153 : the TLS instance parameters. tls->secrets_fn, if non-NULL, observes 154 : generated traffic secrets after fd_tlsrec installs them. The 155 : tls->sendmsg_fn callback is ignored. is_server is 1 if conn operates 156 : in server mode. */ 157 : 158 : fd_tlsrec_conn_t * 159 : fd_tlsrec_conn_init( fd_tlsrec_conn_t * conn, 160 : fd_tls_t const * tls, 161 : int is_server ); 162 : 163 : FD_FN_PURE int 164 : fd_tlsrec_conn_is_server( fd_tlsrec_conn_t const * conn ); 165 : 166 : FD_FN_PURE int 167 : fd_tlsrec_conn_is_ready( fd_tlsrec_conn_t const * conn ); 168 : 169 : FD_FN_PURE int 170 : fd_tlsrec_conn_is_failed( fd_tlsrec_conn_t const * conn ); 171 : 172 : /* fd_tlsrec_conn_rx consumes ciphertext from tcp_rx (may be NULL; 173 : any fragment size is fine), writes ciphertext to send to the peer 174 : into tcp_tx, and decrypted app data into app_rx. The size pointers 175 : are capacity in, bytes written out. Call once with tcp_rx==NULL on 176 : a fresh client conn to emit the ClientHello. Any non-zero return is 177 : fatal (including ERR_OOM). On a protocol error tcp_tx holds the 178 : fatal alert record for the peer (unless it did not fit), and the size 179 : is reported as usual: send it before closing the connection. Once 180 : the peer's close_notify has been received, remaining tcp_rx bytes are 181 : consumed and discarded and the call returns SUCCESS with no 182 : plaintext; check conn->rx_closed. 183 : 184 : Post-handshake, one call writes at most one 27 byte record to tcp_tx: 185 : a single KeyUpdate answering however many the peer requested (RFC 186 : 8446 Section 4.6.3). If tcp_tx lacks room for it the reply waits 187 : for the next fd_tlsrec_conn_rx or fd_tlsrec_conn_tx call. 188 : 189 : app_rx is also used as decrypt scratch, so bytes past the returned 190 : size are clobbered. One call produces at most tcp_rx bytes consumed 191 : plus FD_TLSREC_CAP bytes of plaintext. */ 192 : 193 : int 194 : fd_tlsrec_conn_rx( fd_tlsrec_conn_t * conn, 195 : fd_tlsrec_slice_t * tcp_rx, 196 : uchar * tcp_tx, 197 : ulong * tcp_tx_sz_p, 198 : uchar * app_rx, 199 : ulong * app_rx_sz_p ); 200 : 201 : /* fd_tlsrec_conn_tx encrypts outgoing application data into TLS records. 202 : Returns ERR_STATE before the handshake completes and after 203 : fd_tlsrec_conn_close. */ 204 : 205 : int 206 : fd_tlsrec_conn_tx( fd_tlsrec_conn_t * conn, 207 : uchar * tcp_tx, 208 : ulong * tcp_tx_sz_p, 209 : fd_tlsrec_slice_t * app_tx ); 210 : 211 : /* fd_tlsrec_conn_close writes a close_notify alert record (24 bytes) 212 : into tcp_tx and closes the write side (RFC 8446 Section 6.1): no 213 : further records are sent, receiving still works. Returns ERR_STATE 214 : if the handshake has not completed or the write side is closed 215 : already, ERR_OOM if tcp_tx is too small. */ 216 : 217 : int 218 : fd_tlsrec_conn_close( fd_tlsrec_conn_t * conn, 219 : uchar * tcp_tx, 220 : ulong * tcp_tx_sz_p ); 221 : 222 : /* fd_tlsrec_conn_key_update sends a TLS 1.3 KeyUpdate message and 223 : rotates the write traffic key. request_peer_update must be 0 or 1. */ 224 : 225 : int 226 : fd_tlsrec_conn_key_update( fd_tlsrec_conn_t * conn, 227 : uchar * tcp_tx, 228 : ulong * tcp_tx_sz_p, 229 : int request_peer_update ); 230 : 231 : FD_PROTOTYPES_END 232 : 233 : #endif /* HEADER_fd_src_waltz_tlsrec_fd_tlsrec_h */