Line data Source code
1 : #ifndef HEADER_fd_src_waltz_tls_fd_tls_h
2 : #define HEADER_fd_src_waltz_tls_fd_tls_h
3 :
4 : #include "fd_tls_estate.h"
5 : #include "../../ballet/chacha/fd_chacha_rng.h"
6 : #include "../../ballet/ed25519/fd_ed25519.h"
7 : #include "../../ballet/x509/fd_x509_ca_store.h"
8 :
9 : /* fd_tls implements a subset of the TLS v1.3 (RFC 8446) handshake
10 : protocol.
11 :
12 : fd_tls is not a general purpose TLS library. It only provides the
13 : TLS components required to secure peer-to-peer QUIC connections as
14 : they appear in Solana network protocol. Specifics are listed below.
15 :
16 : Older TLS versions, such as TLS v1.2, are not supported.
17 :
18 : ### Peer Authentication
19 :
20 : Peers are authenticated with X.509 certificates containing Ed25519
21 : public keys. Client cert authentication is optional for
22 : fd_tls_client_t and mandatory for fd_tls_server_t.
23 :
24 : Outside of QUIC mode, the client additionally accepts servers with
25 : ECDSA P-256 and RSA (2048 to 4096 bit) leaf keys, signing the
26 : handshake with ecdsa_secp256r1_sha256 or rsa_pss_rsae_sha{256,384,
27 : 512}, so that it can talk to Web PKI servers.
28 :
29 : ### Key Exchange
30 :
31 : Peers exchange symmetric keys using X25519, an Elliptic Curve Diffie-
32 : Hellman key exchange scheme using Curve25519. Pre-shared keys and
33 : other key exchange schemes are currently not supported.
34 :
35 : ### Data Confidentiality and Integratity
36 :
37 : fd_tls provides an API for the TLS_AES_128_GCM_SHA256 cipher suite.
38 : Other cipher suites are currently not supported.
39 :
40 : ### References
41 :
42 : This library implements parts of protocols specified in the following
43 : IETF RFCs:
44 :
45 : RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
46 : https://datatracker.ietf.org/doc/html/rfc8446
47 :
48 : RFC 6066: Transport Layer Security (TLS) Extensions:
49 : Extension Definitions
50 : https://datatracker.ietf.org/doc/html/rfc6066
51 :
52 : RFC 9001: Using TLS to Secure QUIC
53 : https://datatracker.ietf.org/doc/html/rfc9001
54 :
55 : RFC 7919: Negotiated Finite Field Diffie-Hellman Ephemeral
56 : Parameters for Transport Layer Security (TLS)
57 : RFC 4492: Elliptic Curve Cryptography (ECC) Cipher Suites for
58 : Transport Layer Security (TLS)
59 : https://datatracker.ietf.org/doc/html/rfc7919
60 : https://datatracker.ietf.org/doc/html/rfc4492
61 :
62 : RFC 8032: Edwards-Curve Digital Signature Algorithm (EdDSA)
63 : https://datatracker.ietf.org/doc/html/rfc8032
64 : Note: fd_ed25519 uses stricter signature malleability checks!
65 :
66 : RFC 7748: Elliptic Curves for Security
67 : https://datatracker.ietf.org/doc/html/rfc7748
68 :
69 : RFC 5288: AES Galois Counter Mode (GCM) Cipher Suites for TLS
70 : https://datatracker.ietf.org/doc/html/rfc5288 */
71 :
72 : /* Constants **********************************************************/
73 :
74 : /* FD_TLS_CV_SIGN_SZ is the size of the TLS 1.3 CertificateVerify
75 : signing payload: 64 bytes of 0x20 padding, the 33 byte context
76 : string, a zero separator and the 32 byte transcript hash (RFC 8446,
77 : Section 4.4.3). */
78 :
79 14379 : #define FD_TLS_CV_SIGN_SZ (130UL)
80 :
81 : /* Callbacks **********************************************************/
82 :
83 : /* fd_tls_secrets_fn_t is called by fd_tls when new encryption secrets
84 : have been generated. {recv/send}_secret are used for incoming/out-
85 : going data respectively and point to a 32-byte buffer valid for the
86 : lifetime of the function call. This function is invoked for each
87 : new encryption_level, which is FD_TLS_LEVEL_{HANDSHAKE,APPLICATION}.
88 : It is safe to discard handshake-level decryption secrets after the
89 : handshake has been completed. */
90 :
91 : typedef void
92 : (* fd_tls_secrets_fn_t)( void const * handshake,
93 : void const * recv_secret,
94 : void const * send_secret,
95 : uint encryption_level );
96 :
97 : /* fd_tls_sendmsg_fn_t is called by fd_tls to request transmission of a
98 : TLS message to the peer. msg points to a buffer containing msg_sz
99 : message bytes. The smallest message size is 4 bytes (the size of a
100 : message header). encryption_level indicates which key to use.
101 : flush==0 when another message for the same conn will follow
102 : immediately on return. flush==1 hints that no more sendmsg callbacks
103 : are issued until the next call to fd_tls_server_handshake. It is
104 : safe to "flush" (i.e. transmit data out through the NIC) even when
105 : flush==0. Returns 1 on success and 0 on failure. */
106 :
107 : typedef int
108 : (* fd_tls_sendmsg_fn_t)( void const * handshake,
109 : void const * msg,
110 : ulong msg_sz,
111 : uint encryption_level,
112 : int flush );
113 :
114 : /* fd_tls_quic_tp_self_fn_t is called by fd_tls to request QUIC
115 : transport params to be sent to the peer. quic_tp points to the
116 : buffer that may hold serialized QUIC transport parameters (RFC
117 : Section 18). quic_tp_bufsz is the size of the buffer at quic_tp.
118 : Return value is actual serialized (<=quic_tp_bufsz) on success.
119 : On failure, returns (>quic_tp_bufsz) to indicate insufficient bufsz.
120 : (Zero implies success, however!) */
121 :
122 : typedef ulong __attribute__((warn_unused_result))
123 : (* fd_tls_quic_tp_self_fn_t)( void * handshake,
124 : uchar * quic_tp,
125 : ulong quic_tp_bufsz );
126 :
127 : /* fd_tls_quic_tp_peer_fn_t is called by fd_tls to inform the user of
128 : the peer's QUIC transport params. quic_tp points to the serialized
129 : QUIC transport parameters (RFC 9000 Section 18). quic_tp_sz is the
130 : serialized size. Lifetime of quic_tp buffer ends at return. fd_tls
131 : does not do any validation on the peer's QUIC TP -- Please ensure
132 : your deserializer is robust given arbitrary data. */
133 :
134 : typedef void
135 : (* fd_tls_quic_tp_peer_fn_t)( void * handshake,
136 : uchar const * quic_tp,
137 : ulong quic_tp_sz );
138 :
139 : /* fd_tls_sign_fn_t is called by by fd_tls to request signing of a
140 : TLS 1.3 certificate verify payload.
141 :
142 : ctx is an arbitrary pointer that is provided as a callback argument.
143 : sig points to a 64 byte buffer where the implementor should store the
144 : ed25519 signature of the payload. Payload will point to a
145 : FD_TLS_CV_SIGN_SZ byte buffer containing the TLS 1.3 CertificateVerify
146 : payload.
147 :
148 : This function must not fail. Lifetime of the payload buffer ends at
149 : return.
150 :
151 : May be NULL for clients that never present a client certificate. If
152 : such a client (or one without a cert_x509) receives a CertificateRequest,
153 : fd_tls does not abort: it sends a Certificate message with an empty
154 : certificate_list and no CertificateVerify, and continues the
155 : handshake (RFC 8446 Section 4.4.2). The server then decides whether
156 : to proceed or to abort with an alert. Servers must always install a
157 : signer. */
158 :
159 : typedef void
160 : (* fd_tls_sign_fn_t)( void * ctx,
161 : uchar sig[ static FD_ED25519_SIG_SZ ],
162 : uchar const payload[ static FD_TLS_CV_SIGN_SZ ] );
163 :
164 : struct fd_tls_sign_vt {
165 : void * ctx;
166 : fd_tls_sign_fn_t sign_fn;
167 : };
168 :
169 : typedef struct fd_tls_sign_vt fd_tls_sign_t;
170 :
171 : static inline void
172 : fd_tls_sign( fd_tls_sign_t const * sign,
173 : uchar sig[ static FD_ED25519_SIG_SZ ],
174 14163 : uchar const payload[ static FD_TLS_CV_SIGN_SZ ] ) {
175 14163 : sign->sign_fn( sign->ctx, sig, payload );
176 14163 : }
177 :
178 : extern char const fd_tls13_cli_sign_prefix[ 98 ];
179 : extern char const fd_tls13_srv_sign_prefix[ 98 ];
180 :
181 : /* Public API *********************************************************/
182 :
183 : /* Handshake state identifiers */
184 :
185 128348259 : #define FD_TLS_HS_FAIL ( 0) /* client, server */
186 321612 : #define FD_TLS_HS_CONNECTED ( 1) /* client, server */
187 431691 : #define FD_TLS_HS_START ( 2) /* client, server */
188 38613 : #define FD_TLS_HS_WAIT_CERT ( 3) /* client, server */
189 32508 : #define FD_TLS_HS_WAIT_CV ( 4) /* client, server */
190 32247 : #define FD_TLS_HS_WAIT_FINISHED ( 5) /* client, server */
191 213543 : #define FD_TLS_HS_WAIT_SH ( 6) /* client */
192 18834 : #define FD_TLS_HS_WAIT_EE ( 7) /* client */
193 18849 : #define FD_TLS_HS_WAIT_CERT_CR ( 8) /* client */
194 :
195 : /* TLS encryption levels */
196 :
197 35427 : #define FD_TLS_LEVEL_INITIAL (0)
198 : #define FD_TLS_LEVEL_EARLY (1)
199 128579457 : #define FD_TLS_LEVEL_HANDSHAKE (2)
200 369870 : #define FD_TLS_LEVEL_APPLICATION (3)
201 :
202 : /* FD_TLS_SERVER_CERT_SZ_MAX is the max permitted size of the DER-
203 : serialized X.509 server certificate. */
204 :
205 20688 : #define FD_TLS_SERVER_CERT_SZ_MAX (1011UL)
206 :
207 : /* FD_TLS_SERVER_CERT_MSG_SZ_MAX is the max permitted size of the pre-
208 : buffered X.509 server certificate message. */
209 :
210 20682 : #define FD_TLS_SERVER_CERT_MSG_SZ_MAX (FD_TLS_SERVER_CERT_SZ_MAX+13UL)
211 :
212 : /* FD_TLS_EXT_QUIC_PARAMS_SZ is the max permitted byte size of encoded
213 : QUIC transport parameters */
214 :
215 12192 : # define FD_TLS_EXT_QUIC_PARAMS_SZ_MAX (510UL)
216 :
217 : /* fd_tls_t contains the local TLS config. It is typically shared
218 : across multiple TLS handshakes. */
219 :
220 : struct fd_tls {
221 : /* CSPRNG, caller-provided. caller is responsible for reseeding. */
222 : fd_chacha_rng_t * rng;
223 : fd_tls_secrets_fn_t secrets_fn;
224 : fd_tls_sendmsg_fn_t sendmsg_fn;
225 :
226 : /* QUIC specific callbacks -- Only called if quic flag is set.
227 : TODO: Will optional function pointers stall the pipeline? */
228 : fd_tls_quic_tp_self_fn_t quic_tp_self_fn;
229 : fd_tls_quic_tp_peer_fn_t quic_tp_peer_fn;
230 :
231 : /* Trust store for the server certificate chain (client mode). If
232 : non-NULL, the chain is verified against it and against server_name
233 : (RFC 5280 path validation, RFC 6125 hostname matching) and the
234 : handshake is aborted on failure. If NULL, no chain validation is
235 : done (QUIC peer-to-peer mode, or verification disabled). */
236 : fd_x509_ca_store_t const * ca_store;
237 :
238 : /* key_{private,public}_key is an X25519 key pair. During the TLS
239 : handshake, it is used to establish symmetric encryption keys.
240 : kex_private_key is an arbitrary 32 byte vector. It is recommended
241 : to generate a new X25519 key on startup from cryptographically
242 : secure randomness. kex_public_key is the corresponding public key
243 : curve point derived via fd_x25519_public.
244 :
245 : Security notes:
246 : - May not be changed while conns are active. */
247 : uchar kex_private_key[ 32 ];
248 : uchar kex_public_key [ 32 ];
249 :
250 : /* Signing function holding the Ed25519 key pair that identifies the
251 : server. During TLS handshakes, used to sign a transcript of the
252 : handshake to prove to the peer that we are in possession of this
253 : key. This function should sign with the Solana node identity key.
254 :
255 : Security notes:
256 : - May not be changed while conns are active.
257 : - Using a public key that is not derived from the private key may
258 : reveal the private key (!!!) */
259 : fd_tls_sign_t sign;
260 :
261 : /* cert_public_key is the Ed25519 public key that identifies the
262 : server. Must be the public key corresponding to the Solana node
263 : identity key used by the signer function above. */
264 : uchar cert_public_key [ 32 ];
265 :
266 : /* X.509 certificate to present to peer (optional).
267 : SubjectPublicKeyInfo must be Ed25519 and match cert_public_key. */
268 : uchar cert_x509[ FD_TLS_SERVER_CERT_MSG_SZ_MAX ];
269 : ulong cert_x509_sz;
270 :
271 : /* ALPN protocol identifier. Written by fd_tls_server_set_alpn.
272 : Format: <1 byte length prefix> <ASCII chars>.
273 : Is not NUL delimited. */
274 : uchar alpn[ 32 ];
275 : ulong alpn_sz;
276 :
277 : /* Server Name Indication (SNI) for client mode (RFC 6066).
278 : Set before starting a TLS client handshake. Omitted when
279 : server_name_len==0 (e.g. QUIC mode). NUL terminated. */
280 : char server_name[ 254 ];
281 : ushort server_name_len;
282 :
283 : /* Flags */
284 : ulong quic : 1;
285 : ulong _flags_reserved : 63;
286 : };
287 :
288 : typedef struct fd_tls fd_tls_t;
289 :
290 : /* Extended Alert Reasons *********************************************/
291 :
292 : /* fd_tls-specific error codes to identify reasons for alerts. These
293 : can help with debugging when the error cause is not evident by the
294 : alert itself. */
295 :
296 0 : #define FD_TLS_REASON_NULL ( 0)
297 :
298 0 : #define FD_TLS_REASON_ILLEGAL_STATE ( 1) /* illegal hs state */
299 0 : #define FD_TLS_REASON_SENDMSG_FAIL ( 2) /* sendmsg callback failed */
300 0 : #define FD_TLS_REASON_WRONG_ENC_LVL ( 3) /* wrong encryption level */
301 :
302 0 : #define FD_TLS_REASON_X25519_FAIL ( 9) /* fd_x25519_exchange failed */
303 0 : #define FD_TLS_REASON_NO_X509 (10) /* no X.509 cert installed */
304 24 : #define FD_TLS_REASON_WRONG_PUBKEY (11) /* peer cert has different pubkey than expected */
305 0 : #define FD_TLS_REASON_ED25519_FAIL (12) /* Ed25519 signature validation failed */
306 0 : #define FD_TLS_REASON_SECP256R1_FAIL (14) /* ECDSA P-256 signature validation failed */
307 45 : #define FD_TLS_REASON_RSA_FAIL (15) /* RSA-PSS signature validation failed */
308 :
309 0 : #define FD_TLS_REASON_CH_EXPECTED (101) /* wanted ClientHello, got another msg type */
310 0 : #define FD_TLS_REASON_CH_PARSE (103) /* failed to parse ClientHello */
311 3 : #define FD_TLS_REASON_CH_ENCODE (104) /* failed to encode ClientHello */
312 0 : #define FD_TLS_REASON_CH_NO_QUIC (106) /* Missing QUIC transport params in ClientHello */
313 0 : #define FD_TLS_REASON_CH_RETRY_KS (107) /* ClientHello still missing key share after a retry */
314 24 : #define FD_TLS_REASON_CH_NEG_VER (108) /* Unsupported TLS version */
315 24 : #define FD_TLS_REASON_CH_NEG_KX (109) /* Unsupported key exchange alg */
316 24 : #define FD_TLS_REASON_CH_NEG_SIG (110) /* Unsupported signature alg */
317 27 : #define FD_TLS_REASON_CH_NEG_CIPHER (111) /* Unsupported cipher suite */
318 :
319 0 : #define FD_TLS_REASON_SH_EXPECTED (201) /* wanted ServerHello, got another msg type */
320 0 : #define FD_TLS_REASON_SH_PARSE (203) /* failed to parse ServerHello */
321 0 : #define FD_TLS_REASON_SH_ENCODE (204) /* failed to encode ServerHello */
322 3 : #define FD_TLS_REASON_SH_NEG_CIPHER (205) /* ServerHello selected unoffered cipher suite */
323 6 : #define FD_TLS_REASON_SH_SESSION_ID (206) /* ServerHello session_id echo mismatch */
324 :
325 0 : #define FD_TLS_REASON_EE_NO_QUIC (301) /* Missing QUIC transport params in EncryptedExtensions */
326 0 : #define FD_TLS_REASON_EE_EXPECTED (302) /* wanted EncryptedExtensions, got another msg type */
327 15 : #define FD_TLS_REASON_EE_PARSE (304) /* failed to parse EncryptedExtensions */
328 0 : #define FD_TLS_REASON_EE_ENCODE (305) /* failed to encode EncryptedExtensions */
329 0 : #define FD_TLS_REASON_QUIC_TP_OVERSZ (306) /* Buffer overflow in QUIC transport params callback */
330 :
331 0 : #define FD_TLS_REASON_CV_EXPECTED (401) /* wanted CertificateVerify, got another msg type */
332 18 : #define FD_TLS_REASON_CV_SIGALG (402) /* CertificateVerify sig alg doesn't match cert key type */
333 9 : #define FD_TLS_REASON_CV_PARSE (404) /* failed to parse CertificateVerify */
334 0 : #define FD_TLS_REASON_CV_ENCODE (405) /* failed to encode CertificateVerify */
335 :
336 0 : #define FD_TLS_REASON_CERT_CR_EXPECTED (501) /* wanted Certificate or CertificateRequest, got another msg type */
337 108 : #define FD_TLS_REASON_CERT_CR_PARSE (503) /* failed to parse Certificate or CertificateRequest */
338 :
339 6 : #define FD_TLS_REASON_CERT_KEY_TYPE (601) /* unsupported certificate key type */
340 0 : #define FD_TLS_REASON_CERT_EXPECTED (602) /* wanted Certificate, got another msg type */
341 867 : #define FD_TLS_REASON_CERT_PARSE (604) /* failed to parse Certificate */
342 0 : #define FD_TLS_REASON_X509_PARSE (605) /* X.509 DER parse failed */
343 0 : #define FD_TLS_REASON_CERT_ENCODE (606) /* failed to encode Certificate */
344 168 : #define FD_TLS_REASON_CERT_VERIFY (607) /* certificate chain failed verification against ca_store */
345 :
346 51 : #define FD_TLS_REASON_CERT_CHAIN_EMPTY (701) /* cert chain contains no certs */
347 0 : #define FD_TLS_REASON_CERT_CHAIN_PARSE (702) /* failed to parse cert chain */
348 :
349 0 : #define FD_TLS_REASON_FINI_PARSE (901) /* invalid Finished message */
350 0 : #define FD_TLS_REASON_FINI_EXPECTED (902) /* wanted Finished, got another msg type */
351 0 : #define FD_TLS_REASON_FINI_FAIL (904) /* Finished data mismatch */
352 :
353 0 : #define FD_TLS_REASON_ALPN_PARSE (1001) /* failed to parse ALPN */
354 24 : #define FD_TLS_REASON_ALPN_NEG (1002) /* ALPN negotiation failed */
355 27 : #define FD_TLS_REASON_NO_ALPN (1003) /* no ALPN extension */
356 :
357 0 : #define FD_TLS_REASON_POST_HS_MSG (1101) /* unexpected post-handshake msg type */
358 18 : #define FD_TLS_REASON_KEY_UPDATE_PARSE (1102) /* failed to parse KeyUpdate */
359 87 : #define FD_TLS_REASON_CCS (1103) /* unexpected ChangeCipherSpec record */
360 129 : #define FD_TLS_REASON_ALERT_PARSE (1104) /* malformed alert record */
361 177 : #define FD_TLS_REASON_PEER_ALERT (1105) /* peer sent a fatal alert */
362 12 : #define FD_TLS_REASON_HS_INTERLEAVED (1106) /* record interleaved with a fragmented handshake message */
363 51 : #define FD_TLS_REASON_REC_TYPE (1108) /* unexpected record layer content type */
364 36 : #define FD_TLS_REASON_REC_OVERFLOW (1109) /* record larger than the protocol allows */
365 18 : #define FD_TLS_REASON_HS_KEY_CHANGE (1110) /* handshake data follows a key change in the same record */
366 24 : #define FD_TLS_REASON_HS_MSG_SIZE (1111) /* handshake message length invalid */
367 54 : #define FD_TLS_REASON_REC_MAC (1112) /* record failed authentication */
368 6 : #define FD_TLS_REASON_REC_PADDING (1113) /* record has no content type byte */
369 :
370 : FD_PROTOTYPES_BEGIN
371 :
372 : FD_FN_CONST ulong
373 : fd_tls_align( void );
374 :
375 : FD_FN_CONST ulong
376 : fd_tls_footprint( void );
377 :
378 : /* TODO document new/join/leave/delete */
379 :
380 : void *
381 : fd_tls_new( void * mem );
382 :
383 : fd_tls_t *
384 : fd_tls_join( void * );
385 :
386 : void *
387 : fd_tls_leave( fd_tls_t * );
388 :
389 : void *
390 : fd_tls_delete( void * );
391 :
392 : char const *
393 : fd_tls_alert_cstr( uint alert );
394 :
395 : char const *
396 : fd_tls_reason_cstr( uint reason );
397 :
398 : /* fd_tls_server_handshake ingests a TLS message from the client.
399 : Synchronously processes the message (API may become async in the
400 : future). Record must be complete (does not defragment). Returns
401 : number of bytes read on success. On failure, returns negated TLS
402 : alert code. */
403 :
404 : long
405 : fd_tls_server_handshake( fd_tls_t const * tls,
406 : fd_tls_estate_srv_t * handshake,
407 : void const * record,
408 : ulong record_sz,
409 : uint encryption_level );
410 :
411 : /* fd_tls_client_handshake is the client-side equivalent of
412 : fd_tls_server_handshake. Must not be called with messages sent after
413 : the handshake was completed (such as NewSessionTicket). */
414 :
415 : long
416 : fd_tls_client_handshake( fd_tls_t const * client,
417 : fd_tls_estate_cli_t * handshake,
418 : void const * record,
419 : ulong record_sz,
420 : uint encryption_level );
421 :
422 : static inline long
423 : fd_tls_handshake( fd_tls_t const * tls,
424 : fd_tls_estate_t * handshake,
425 : void const * record,
426 : ulong record_sz,
427 86256 : uint encryption_level ) {
428 86256 : if( handshake->base.server )
429 27612 : return fd_tls_server_handshake( tls, &handshake->srv, record, record_sz, encryption_level );
430 58644 : else
431 58644 : return fd_tls_client_handshake( tls, &handshake->cli, record, record_sz, encryption_level );
432 86256 : }
433 :
434 : /* fd_tls_hkdf_expand_label implements the TLS 1.3 HKDF-Expand function
435 : with SHA-256. Writes the resulting hash to out. secret is a 32 byte
436 : secret value. label points to the label string. label_sz is the
437 : number of chars in label (not including terminating NUL). context
438 : points to the context byte array. context_sz is the number of bytes
439 : in context.
440 :
441 : Constraints:
442 :
443 : out !=NULL
444 : secret!=NULL
445 : label_sz ==0 || label !=NULL
446 : context_sz==0 || context!=NULL
447 : 1<=out_sz <=32
448 : 0<=label_sz <=64
449 : 0<=context_sz<=64 */
450 :
451 : void *
452 : fd_tls_hkdf_expand_label( uchar * out,
453 : ulong out_sz,
454 : uchar const secret[ static 32 ],
455 : char const * label,
456 : ulong label_sz,
457 : uchar const * context,
458 : ulong context_sz );
459 :
460 : FD_PROTOTYPES_END
461 :
462 : #endif /* HEADER_fd_src_waltz_tls_fd_tls_h */
|